글로벌 웹 서비스 개발기
서비스 개발자로서 서비스 어플리케이션의 코드를 작성하는 일만 하고 시스템 개발자가 하는 일들에 대한 이해도가 적었었다. 특히 신규 서비스를 기획/개발하며 프로토타이핑 정도 수준의 개발을 많이 하다보니, 실제 서비스를 하는 것에서 클라우드 기반의 인프라 세팅이 왜 필요한지 공감하지 못했었다. 그러던 중, 단 기간 내에 글로벌 유저 주간 10만 가량이 들어왔고, 서버가 터지면서 인프라에 대한 고민과 공부를 급하게 하였다.
배포 자동화나, 테스트 주도의 개발 등은 머리가 무식해도 몸이 좀 고생하면 어떻게든 굴러는가는 구조지만, 트래픽이 순간적으로 몰리는 상황에 서버가 죽거나, 응답이 매우 지연되는 현상은 무조건 막아야했기 때문에 소잃고 외양간 고치는 격으로 데브옵스를 공부할 수 있는 기회가 되었다. 이번 기회에 삽질을 하며 배운 것들에 대한 정리를 해보았다.
클라우드 서비스
온프레미스와 클라우드가 있다고 하는데, 사내에 서버와 스토리지 등이 있음에도 불구하고, 신속 유연하게 서비스를 출시해야했고 확장성이 용이한 이점이 있는 클라우드 환경을 선택했다.
우리 팀은 중국에서 서비스하기에 알리클라우드를 써야만 해서, 관련 도큐먼트를 찾는데 어려움이 있었지만, 대부분 AWS에 있는 서비스와 유사하여 AWS 도큐먼트를 꽤 참고하였다.
1) OSS (Objects Storage Service, ex.Amazon S3)
: 가상서버 인스턴스를 제외한 가장 처음 쓰게되는 클라우드 서비스인 것 같다. 서비스 로딩을 지연 시키는 가장 큰 요소는 결국 이미지, 폰트 같은 정적 리소스일 확률이 높기 때문에, 사용자에게 많은 시각 요소를 빠르게 보여줘야 하는 모던 웹서비스에서 필수적인 서비스 같다. 브라우저 캐싱 설정, gzip, 버전 관리 등에 이점이 있는 듯 하다.
2) Cloud Database - RDBMS (ex. Amazon RDS)
: 원래 호스팅으로 쓰던 디지털 오션에 db 클라우드가 없기도 했고, 내부용으로 빠르게 실험할 때는 로컬 mysql, 심지어는 sqlite로도 문제 없는 경우도 많아서 안 썼었다. 처음에는 백업도 그냥 주기적 백업 스크립트 돌리면되고, 속도도 별 문제 없어서 굳이 써야하나 싶었는데, 스케일링이나 안정성 관리 측면에서 백업 자동화나 I/O 모니터링, 슬로우 쿼리 잡아주는 등 디비의 문제를 분리해서 볼 수 있게 해줘서 좋은 서비스인 것 같다.
3) CDN (Contents Delivery Network)
: 국내 서비스를 하면 S3에서 정적자원을 호스팅해도 속도의 저하가 거의 안 느껴질 수 있지만, 글로벌 호스팅을 할 경우엔 CDN은 선택이 아닌 필수이다. 가끔 CDN이 폰트 등 리소스를 CORS 걸어버리거나, 빈 자원을 캐싱해서 문제가 될 때도 있었지만 꼭 써야하는 것 같다. 개인적으로 재미있는 것은 리액트 빌드 파일 등 클라이언트 코드 자체를 정적 호스팅해도 잘 굴러가는 것이 었는데, 막연하게 동적/정적 자원을 분리해서 생각하다보니 로직이 담긴 코드는 정적 호스팅을 할 수 없다고 착각했던 것 같다.
4) Nginx, uWSGI
:웹 서버 프로그램에서 병목이 있을 수 있다는 글을 읽고 다음 항목들을 조정했다.
-worker connection
-keepalive timeout
-client max body size
-net.core.somaxconn
-processes
-Request time out
-Mysql connection pool
5) nGrinder, Jmeter, loadtest
-TPS(Transaction Per Second)와 평균 응답시간, 중앙값 응답시간, 오류율 등을
Jython, Groovy 등 코드 사용법이 익숙하지 않아 급한대로 수동으로 URL을 넣고 GET요청 위주로 테스트를 했다. 클라우드 환경에서 Saas로 사용할 수 있어서 편했다. Jmeter는 사용법은 좀 더 복잡하게 생겼지만 TPS, 오류율 등을 보다 더 잘 시각화해주는 도구인 것 같다. npm의 loadtest 모듈도 인프라 위가 아닌 로컬에서 서버 코드 자체의 문제를 검증할 수 있어 매우 유용했다.
6) bake
:서비스가 아닌 글 형식의 컨텐츠를 배포해야 했었는데, 수정 및 업데이트가 잦지 않고 보여주는 화면이 동일한 정적인 페이지이기에 페이지 캐싱을 고려했었다가, bake라는 좋은 방법이 있다는 걸 발견했다. bake는 대형 언론사 페이지 등에서 쓰는 방식으로 동적인 html을 빌드하여 쿼리셋을 단일한 static html 파일로 만들어주는 기법이다. 이렇게 할 경우 이미지 같은 정적 자원 처럼 데이터베이스나 비즈니스 로직 없이 단순한 serving이 가능해지고, S3 같은 스토리지만으로도 배포가 가능하다. 무엇보다 페이지 전체가 CDN으로 캐싱 가능하여 성능과 안정성의 여유가 생긴다.
7) redis(캐싱)
:RDBMS보다 NoSQL이 속도의 이점이 있는 것, 하드디스크보다 메모리가 접근이 빠른 것을 활용해 데이터베이스 중 일부를 임시저장하는 것. 가용 공간은 한정적이므로 머리를 잘 써서 무엇을 캐싱하고 무엇을 갱신할 지를 잘 정해야 한다.
8) celery
:오래 걸리는 작업을 대기열에 올려놓고, 사용자가 기다리지 않게 해준다. (비동기)
:회원가입이 없어 이메일 발송 등의 작업은 없었고, 렌더와 이미지 저장 등이 가장 오래 걸리는 작업이었다. 다만 미니 프로덕트들이다보니 응답결과가 바로 나와야 하는 경우가 많아서 비동기로 해도 결국 유저를 기다리게 해야하는 상황이 많아서 적용할 지점을 고민중이다
9) Jenkins/fabric
:아직 공부가 필요한 부분인데, 깃허브 등의 코드 관리 저장소와 연동하여 개발환경과 리얼 환경에서 배포를 자동화해주는 툴로 많이 쓰이는 것 같다. 개인적으로는 젠킨스는 서버도 띄워야 하고 별도의 프로그램 느낌이 나서 배보다 배꼽 느낌이 났고, fabric이 심플한 스크립트 느낌이 나서 좋은 것 같다. 도커의 Dockerfile 을 작성하는 정도의 느낌.
10) Cloud watch
:이 역시 아직 공부가 필요한 부분이나, cpu 사용률, 오류율 등이 몇 퍼센트가 넘을 경우 서버를 재시작하거나 오토스케일링을 하거나, 알림을 오게하는 등 여러 자동화 업무를 가능하게 해주는 도구였다. "서버 접속 안되는데요"라는 말을 새벽 2시에 듣고 급하게 일어나서 ssh접속을 안해도 되게 해주는 느낌.
결론적으로 이번에 느낀 점은 데브옵스 관련 글이 많이 없다는 것이었다. 그 이유는 내 생각엔 기술블로그를 주로 작성하는 스타트업들은 데브옵스가 짱짱한 수준까지 가기 쉽지 않아서. 반대로 데브옵스가 필요한 조직은 데브옵스하기 바빠서 글을 쓸 시간이 없어서인 것 같다. 아주 쉬운 것이더라도 데브옵스에서 배우는 것들을 정리해두어야 겠다.