ipify: 300억 요청 처리, 그 너머로

스케일 가능한 웹서비스를 Heroku로 엄청나게 단순한 방법으로 만들어 운영한 이야기. 번역.
1,677 words

Randall Degges의 포스트 To 30 Billion and Beyond를 번역했다. ipify를 만들고 확장하는 일련의 과정을 풀어 쓴 이야기다.

Thank you, Randall Degges for giving me the opportunity to translate this article. If you want to read the original, please check To 30 Billion and Beyond.


ipify: 300억 요청 처리, 그 너머로

Buzz Lightyear Charging Sketch

몇 년 전에 무료 웹서비스인 ipify를 만들었습니다. ipify는 무료로 사용할 수 있는, 고도로 확장 가능한 IP 주소 검색 서비스입니다. REST API를 호출하면 어느 퍼블릭 IP 주소를 사용하고 있는지 확인 할 수 있습니다.

ipify를 만든 당시에는 복잡한 인프라스트럭처 관리 소프트웨어를 만들고 있었고 클라우드 인스턴스에서 관리용 API를 사용하지 않고 동적으로 퍼블릭 IP 주소를 알아내야 했었습니다.

무료로 사용 가능한 역 IP 검색 서비스를 검색해봤지만 적합한 해결책을 찾지 못했습니다.

  • IP를 스크랩 할 수 있는 웹사이트가 있긴 했습니다. (하지만 별로 좋은 형태가 아니고 호스트에서 사용하기엔 불편합니다)
  • 비용을 청구하는 API도 있었습니다. (잌!)
  • 일간 조회 횟수를 제한하는 API도 있었습니다. (한꺼번에 많은 인스턴스를 관리해야 했기에 사용하기 두려웠습니다)
  • 제가 원하는 방식의 API도 있었지만, 오류가 발생하기도 하고 가끔 서비스가 내려가기도 하거나 질적으로 떨어지기도 했습니다. 어느 제공자를 dig로 살펴봤더니 전체 서비스가 단일 서버 (A 레코드)에서 동작하고 그 서버에서 요청이 직접 종료되었습니다. 세계 규모로 확장 가능하거나 고가용성의 서비스라고 말하기 어려웠습니다.
  • 보기엔 괜찮은 API도 있었지만, 지속해서 유지하기 위한 기부를 받으려고 했습니다. 사용하려는 API 서비스가 언제 죽을지 모를 상황이라니 마음 놓고 사용할 수 없었습니다.

이런 이유로 인해 작은 서비스를 직접 만들어서 내 문제와 가능한 한 많은 사람의 문제를 해결하고 싶었습니다. 더군다나 하나의 문자열을 반환하는 소프트웨어를 작성하는 일은 그렇게 엄청 어려운 일은 아니었습니다. 하지 말아야 할 이유가 있을까요?

가장 최악의 경우라고 상상해볼 수 있는 일은 기꺼해야 월 30달러가량 사용하고 공개 서비스라는 점을 염두에 두고 다루는 정도였습니다.

ipify 버전 0

ipify의 첫 코드는 상당히 단순했습니다. 50줄도 되지 않는 작은 코드를 Node로 작성했습니다. (당시에 많은 시간을 Node를 갖고 놀며 지냈습니다.) ipify 서비스가 문자열을 반환하는 일이 전부라는 전제에서는 Node를 사용할 가장 적합한 경우인 것을 알 수 있었습니다. 적은 CPU 사용량으로 수많은 요청을 처리하는 작업이죠.

API 서비스를 Node로 만들고 나서 간단한 정적 사이트를 프론트엔드로 붙여 아마존의 S3에 올렸습니다. 그리고 S3 버킷 앞에 아마존의 CDN 서비스인 CloudFront를 설정해서 페이지를 캐싱하는 것으로 엄청 빠르게 불러올 수 있도록 했습니다.

어떤 상상의 날개를 펼쳐봐도 저는 디자이너가 아니었습니다. 그래도 다행히 bootstrap을 사용해서 조금 나은 모습을 갖출 수 있었습니다. =)

모든 준비가 끝난 후에 간단하게 테스트를 수행했습니다. 모든 것이 준비되었다는 생각에 다음 단계인 배포로 넘어갔습니다.

Heroku 입성

Heroku Logo

저는 Heroku의 왕 팬입니다. (심지어 Heroku에 대한 도 썼습니다.) Heroku를 수년 간 사용하고 있고 개발 세계에 있어서 가장 저평가되고 있는 서비스 중 하나라고 생각합니다. 한 번도 사용해본 적이 없다면 지금 확인해보시길 바랍니다!

ipify를 확장 가능하고 고가용성으로, 그리고 저렴하게 운영하려면 Heroku 만큼 단순하고 좋은 선택지가 없다고 생각하고는 Heroku를 사용하기로 결정했습니다.

ipify를 Heroku에 1~2분 정도 걸려 배포하고 단일 dyno(웹서버)로 실행한 후에 제한적으로 테스트를 수행했습니다. 여전히 잘 동작하니 스스로 뿌듯한 기분이 들었습니다.

Heroku에 익숙하지 않다면 ipify 인프라스트럭처가 어떻게 동작하는지 살펴봅시다.

  • Heroku는 ipify 웹서비스를 512M 램과 제한된 CPU인 작은 dyno (웹서버)에서 구동합니다.
  • 만약 프로세스가 충돌하거나 어떤 심각한 문제가 발생한다면 Heroku는 자동으로 서비스를 재시작합니다.
  • Heroku는 앱으로 들어오는 모든 요청을 로드 벨런스를 거친 후 요청을 처리하기 위해 dyno (웹서버)로 전달합니다.

이런 설정이 좋은 이유는:

  • 고가용성: Heroku의 로드벨런서, 제 dyno, 모든 것이 고가용성입니다.
  • 유지보수도, 관리 설정도, 어떤 배포 코드도 필요하질 않습니다. 100% 자동입니다.
  • 저렴합니다. 단일 서버를 위해 월 ~7달러가량 냅니다.
  • 빠릅니다. 헤로쿠는 아마존 웹서비스(AWS) 상에서 돌아가며 모든 인프라스트럭처는 세계에서 가장 인기있는 클라우드 호스트 위치인 AWS 미동부 (버지니아)에서 운영됩니다. 이 의미는 지리적으로 US 동부 해안에서 운영된다는 점인데 물 건너 유럽이나 나머지 US 지역에서 그다지 멀지 않다는 의미입니다. 세계 대부분 지역의 사용자가 서비스를 사용한다고 해도 그렇게 오래 걸리지는 않을 겁니다.

지금까지는 상당히 괜찮았습니다. 만들고, 설정하고, 테스트하고, 프로덕션으로 옮기기까지 1일 이하의 노력으로 끝낼 수 있었습니다.

그리고나서 ipify를 제 인프라스트럭처 관리 코드와 통합하는 것으로 원래 해결하려던 문제를 처리했습니다.

한 달 정도 모든 것이 잘 흘러갔습니다. 몇 가지 문제를 알아차리기 전까지는 말이죠.

인기… 헐?

Spartan Warrior Sketch

ipify를 홍보한 적이 없지만 “ip address api”를 구글에서 검색하면 꽤 상단에 걸리게 되었습니다. SEO와 문구 수정에 사용한 수년 간의 노력이 빛을 발한 것 같습니다.

그동안 ipify가 구글 검색 결과에서 상당히 높은 순위로 노출된 덕분에 수천 명의 사용자가 생겼습니다. 서비스가 많이 노출되면서 몇 이슈가 나타나기 시작했습니다.

제 Heroku 로드 벨런서가 경고를 보내기 시작했습니다. Node 서버가 들어오는 요청을 충분히 빠르게 처리하지 못하고 있다는 내용이었습니다. 결과적으로 다음과 같은 일이 나타났습니다.

  • 너무 많은 사용자가 ipify에 API 요청을 보내고 있습니다
  • 제 Node 서버가 요청에 대해 느리게 응답해서 지연이 늘고 있었습니다
  • Heroku의 로드벨런서가 이 문제를 알아차리고 Node 서버에 보내기 전에 요청을 버퍼에 저장했다가 보내기 시작했습니다.
  • Node 서버가 빠르게 요청을 처리하지 못한 탓에 로드벨런서에서 사용자에게 503을 전달하고 요청을 끝내버렸습니다.

그다지 좋은 모습이 아닙니다.

이 문제를 해결하기 위해 한 일은 간단했습니다. Heroku에 dyno를 더 추가했습니다. 이 방식으로 수용량을 두 배로 늘렸고 모든 서비스가 부드럽게 동작하기 시작했습니다. 그 이면엔 두 “프로덕션” dyno를 구동한 탓에 거의 50달러 가량을 지불해야 했습니다. 첫 dyno 이후엔 일반 요금인 dyno당 월 25달러를 지불해야 했습니다.

서비스가 이 정도로 인기 있다면 월 50달러를 내는 것도 나쁘지 않다고 생각해서 지불하기로 결정하고 다시 안정적인 상황으로 돌아올 수 있었습니다.

하지만… 그렇게 말처럼 쉬운 문제가 아니었습니다.

한주도 채 지나기 전에 Heroku에서 이전과 동일한 경고를 받았습니다. 사용량을 보니 트래픽은 두 배로 늘었고 ipify는 더 많은 사용량을 보였습니다.

저는 또 다른 dyno를 추가하고 월 75달러를 지불하게 되었습니다. 그래도 좀 더 살펴보기로 했습니다. 저는 짠돌이라서 월 50달러 이상 쓰는 건 기쁜 일이 아니었습니다.

수사

L Sketch

수사를 시작하면서 가장 먼저 살펴본 것은 실제로 ipify가 초 당 얼마나 많은 요청을 처리하는가(requests per second, rps)를 살펴보는 일이었습니다. 숫자를 보고 상당히 놀랐습니다. 낮았거든요.

제 기억에는 ipify는 10rps 정도였습니다. 이렇게 작은 숫자를 처리할 수 없다면 뭔가 코드가 문제라고 생각했습니다. 만약 10rps를 작은 웹 서버 두 개를 사용하는데도 처리하지 못하는 상태라면 끔찍하게 잘못된 것이 분명했습니다.

처음 알아차린 것은 단일 Node 프로세스로 처리하고 있다는 점이었습니다. Node의 클러스터 모듈을 사용해서 쉽게 고칠 수 있었습니다. 이제 각각의 CPU 코어에서 하나의 프로세스를 구동할 수 있게 되었습니다. 효과적으로 dyno에서 두 배의 처리량을 다룰 수 있게 되었습니다.

하지만 20 rps는 여전히 작은 숫자로 느껴져서 좀 더 깊이 파헤쳐보기로 했습니다. Heroku에서 로드 테스트를 수행하기보다 제 랩탑에서 로컬로 테스트를 수행했습니다.

제 랩탑은 512M 램의 작은 Heroku dyno보다 훨씬 강력하기 때문에 더 처리량이 많을 것으로 생각했습니다.

ab 도구를 사용해서 테스트를 수행했고 놀랄 수 밖에 없었습니다. 훨씬 좋은 사양의 제 랩탑에서도 30 rps 정도 처리하지 못하는 것입니다. (제 랩탑은 리눅스로 구동되고 있었고 ab는 효율적으로 동작하는 환경이었습니다.) 그래서 기초적인 분석을 시작했고 Node에서 단순한 문자열 조작 동작을 하는데 많은 시간을 사용한다는 것을 확인할 수 있었습니다. (X-Forwarded-For 헤더에서 IP 주소를 추출하고 다듬는 일이었습니다) 여러 가지 실험을 해봤지만, 이 한계를 뛰어넘을 만큼 좋은 성능을 내는 것은 불가능했습니다.

이 시점에서 ipify 서비스는 두 dyno를 통해서도 겨우 20 RPS 정도 처리할 수 있었습니다. ipify는 월 ~5200만 요청을 처리하고 있었습니다. 그다지 인상적이지 않았습니다.

이 서비스를 Go로 다시 작성하기로 했습니다. (Go는 몇 달 전부터 사용하기 시작했습니다) 동일한 Go 서버를 작성했을 때 성능 측면에서 더 나은지 확인해보고 싶었습니다.

ipify 버전 1

Warrior Sketch

ipify를 Go로 다시 작성하는 일은 짧은 (그리고 즐거운) 실험이었습니다.

이 과정에서 Gorilla/mux, Martini와 httprouter 같은 다양한 Go 라우팅 스택을 사용해볼 수 있었습니다. 이 세 가지 라우팅 도구를 사용해보고 비교해본 결과 httprouter가 다른 둘에 비교해 비약적으로 성능이 좋은 것을 확인했습니다.

제 랩탑에서 Go 서버는 초당 ~2,500 요청을 처리할 수 있었습니다. 엄청난 향상이었습니다. 또한, 메모리 사용량도 엄청 적어서 5M 남짓을 사용했습니다.

Go와 사랑에 빠진 저는 즉시 행동으로 옮겼습니다. Go 기반 ipify 서비스를 Heroku에 배포했습니다.

결과는 환상적이었습니다. 단일 dyno에서 2천 RPS 정도를 처리할 수 있었습니다. 이런 변화는 월 25달러 수준으로 월 ~52억 요청을 처리할 수 있게 되었습니다.

몇일 후에 경험 있는 Go 개발자와 대화를 한 후, 문자열을 처리하는 기능 몇 가지를 다시 작성했고 그 덕분에 추가로 ~1천 RPS 정도를 확보할 수 있었습니다. 이 시점에 dyno 당 월 ~77억 요청을 처리하고 있었습니다. (조금 더 많거나 적었습니다.)

저는 말할 것도 없이 흥분했습니다.

더 큰 유명세

Tyrael Sketch

짧은 시간이긴 하지만 호스팅 비용을 줄일 수 있었습니다. 대략 2달 정도 지난 후에 ipify는 또 다른 문제를 경험하게 되었습니다.

엄청난 비율로 성장을 지속하고 있었습니다. 이즈음에 ipify에 대해 Google Alerts를 설정해뒀는데 그래서 사람들이 이 서비스에 대해 언급하면 바로 알 수 있었습니다.

점점 많은 사람이 ipify를 개인 프로젝트와 업무에서 사용한다는 점을 확인할 수 있었습니다. 그리고 몇 회사에서는 자신들의 프로덕트에 포함해도 되느냐는 질문을 받기 시작했습니다. (대형 스마트 TV 공급자, 다양한 미디어 대행사와 IoT 업체 등.)

ipify가 월간 150억 요청을 처리할 때쯤 호스팅 비용으로 월 50달러를 사용하고 있었습니다.

하지만 이런 상황은 오래 지속되지 않았습니다.

ipify의 트래픽은 급격히 성장하는걸 확인할 수 있었습니다. 아마 몇 달 후에는 수 십 억의 월간 요청을 더 받게 될 겁니다.

또한, 급작스러운 트래픽에 의한 문제도 겪기 시작했습니다. ipify가 짧은 시간에 엄청난 양의 트래픽을 받게 되면 순식간에 죽는 경우가 있었습니다. 아마 이 트래픽은 부트스트랩 스크립트, 스케쥴 작업(cron job) 그리고 다른 비슷한 방식의 작업으로 발생한 것이라 짐작하고 있습니다.

뒤늦게는 백신 업체에서 ipify를 차단하기 시작했다는 얘기도 들을 수 있었습니다. 루트킷이나 바이러스, 지저분한 소프트웨어가 ipify를 사용하기 시작한 탓입니다. 공격자는 공격 대상을 공격하기 전에 ipify를 사용해서 피해자의 퍼블릭 IP 주소를 얻어내는 등의 악의적인 용도로 사용했습니다. 이런 사용자도 분명 대규모의 급작스러운 트래픽에 책임이 있다고 가정했습니다.

이런 악의적인 사용자를 좋아하지도 않고 그 일을 돕는데 돈을 쓰고 싶지도 않았지만 ipify는 중립적으로 사용하고 싶은 사람은 아무나 사용할 수 있도록 그대로 운영하기로 결정했습니다. 개발자 서비스인데 어떤 사람만 사용하도록 고르고 선택하는 것은 탐탁치 않았습니다. 모든걸 단순하게 유지하기로 했습니다.

이런 결정에도 여전히 급작스러운 트래픽 문제는 해결해야 했습니다. 이런 트래픽은 쉽게 처리하기 어려운데 우선적으로 두 선택지가 있었습니다.

  • 추가적인 dyno를 운영해 비용을 지불하고 항상 급작스러운 트래픽에 대비하는 방법, 또는
  • Adept와 같은 자동 확장 도구를 사용해서 트래픽 패턴에 따라 dyno를 생성하고 제거하는 방법

결국엔 첫 번째를 선택했습니다. 단순히 Adept의 서비스를 사용해서 추가적인 비용을 지출하고 싶지 않았기 때문입니다. (물론 이 서비스를 사용해본 적이 있고 엄청나게 멋진 서비스입니다.) 이 즈음에 월간 150달러를 지불했고 ipify는 250억 월간 요청을 처리했습니다.

이렇게 최근까지 왔습니다.

ipify 300억 요청 도달

Buzz Lightyear Proud Sketch

지난 몇 달 동안 ipify는 새로운 기록을 냈고 월간 300억 요청을 몇 차례 넘었습니다. 이렇게 새로운 기록을 경신하는 일은 지켜보는 즐거움이 있습니다.

오늘날 ipify는 2천에서 2만 RPS를 유지하고 있습니다. (이 수치는 항상 절대 일관적이질 않았습니다.) 트래픽은 항상 달라졌고 사용량은 정기적으로 높아졌는데 트래픽 패턴에서 의미를 찾는 걸 완전히 포기했습니다. 평균 응답 시간은 트래픽 패턴에 따라 1~20ms 사이를 유지했습니다.

현재 서비스는 트래픽과 여러 요인에 따라 월간 150~200달러로 운영되고 있습니다. 월간 200달러를 소비한다고 가정하고 수치를 계산해보면 ipify는 각 요청을 0.000000007달러로 운영하고 있습니다. 충격적으로 낮은 비용이죠.

만약 이 서비스를 Lambda에서 돌린다고 가정하고 요금을 계산해본다면 월간 1,243.582달러 (연산) + 6,000달러 (요청) = ~ 7,243.58달러 정도를 사용하게 될 겁니다. 참고로 이건 간단한 입계산입니다. ipify의 수치를 Lambda 요금 계산기에 입력해서 얻은 결과입니다.

결론적으로 ipify에 들어가는 비용에 엄청나게 만족하고 있습니다. 간단한 용도를 제공하는 짠돌이 서비스죠.

ipify의 미래

이제 미래를 생각해보게 되었습니다. ipify는 지속해서 성장하고 있습니다. 서비스는 ipv6 지원 (Heroku가 현재 지원하지 않아요 🙁), 더 나은 웹디자인, IP 주소에 대한 다른 메타데이터 등 여러 가지 요청을 받고 있습니다.

최근 다른 프로젝트 덕분에 엄청나게 바쁜 탓에 ipify의 소유권을 제 좋은 친구인 https://www.whoisxmlapi.com에 넘겼습니다.

조나단과 그의 팀은 가치 있고 흥미로운 개발자 API 서비스를 만드는데 제격인 포트폴리오를 갖고 있습니다.

제가 지속해서 돕고 있긴 하지만 조나단과 그의 팀은 현재 ipify의 새로운 기능을 구현하고 있습니다. 제가 기대하는 좋은 변화를 반영하기 위해 열심히 작업하고 있습니다. (더 나은 UI와 데이터 엔드포인트를 포함해서 말입니다.)

저는 앞으로도 꾸준히 성장할 ipify가 기대됩니다.

저에게 질문이나 궁금한 점이 있다면 이메일로 남겨주세요.