-
미국 메디케어 건강보험 플랜 비교 시스템을 재구축하며, 검증된 기술(Postgres, golang, React 등) 로만 구성된 단순한 구조로 10억 건 이상의 웹 요청을 안정적으로 처리한 경험을 공유함
-
단순함과 안정성을 목표로 아키텍처를 설계해, 평균 10ms 이하 응답 속도와 아주 낮은 장애율을 달성함
-
혁신(innovation token) 은 핵심적인 구조 분리(3개 대형 모듈, gRPC 통신)에만 최소한으로 적용하고, 그 외에는 모두 지루하지만 신뢰할 수 있는 방법론을 선택함
-
DB 스키마 관리, ETL 파이프라인, 테스트, 로깅, 문서화, CLI 도구까지 모든 운영 요소를 반복 가능하고 단순한 방식으로 구축해 팀 전체가 쉽게 이해·유지보수할 수 있는 시스템을 완성함
-
지속적 품질관리와 강한 팀워크가 대규모 정부 프로젝트에서도 통한다는 사례를 생생히 보여줌
Serving a billion web requests with boring code
High level
-
2년 반에 걸쳐 미국 정부의 메디케어 플랜 비교·구매 웹사이트를 리드 개발함
-
일 평균 500만 API 요청을 처리, 평균 응답 속도는 10ms 미만, 95% 요청은 100ms 이하로 유지
-
장애 발생률이 매우 낮아 실제 엔지니어가 새벽에 호출된 사례는 한 손에 꼽을 정도
-
Postgres, golang, React 등 누구나 이해할 수 있는 검증된 기술로만 구성해, 꾸준히 안정적인 시스템을 구축함
Boring über alles
- 최우선 원칙은 '지루하고 검증된 기술' 만을 우선하는 것(** Choose Boring Technology**)
- 혁신 시도는 꼭 필요한 곳에서만 innovation token을 아껴서 사용
- 복잡하고 화려한 솔루션보다 안정적이고 명확한 기술과 프로세스를 선호
The boring bits
-
Postgres: 데이터 저장의 핵심, 신뢰성과 확장성을 모두 만족. 복잡한 검색(페이시티드 검색 등)도 Postgres로 해결
-
golang: 빌드와 배포가 빠르고, 바이너리 산출물이 명확함. 에러 핸들링이 직관적이고, 새로운 팀원도 쉽게 적응 가능
-
React: SPA 프레임워크 중 가장 검증되어 있고, 팀원들이 이미 익숙했음. 접근성과 다양한 기기 지원도 중요한 고려 요소였음
- 장기적으로는 번들 크기와 속도 저하 이슈가 발생했지만, 당시 상황에서는 시간 내에 결과를 내기 위한 최적의 선택이었음
The innovation tokens
-
Modular backend: 전체 백엔드를 마이크로서비스도, 모놀리식도 아닌 3개의 대형 모듈(druginfo, planinfo, beneinfo)로 구성
- 각 모듈은 별도의 Postgres DB를 사용하고, 데이터 공유는 오직 gRPC를 통해서만 이뤄짐
-
druginfo: 약국, 보험, 포장 등 조합이 기하급수적으로 늘어나는 약가 정보를 매우 정교하게 인덱싱하고, 복잡한 사전처리와 성능 최적화가 필요
-
planinfo: 매일 새로운 CMS 데이터를 수신해, DB 전체를 새로 만들어 사용함(불변성 유지)
-
beneinfo: 실제 가입자 정보를 보관하는 유일한 부분으로, 민감한 PII(개인정보)는 최소한만 저장. 데이터 유출 리스크 최소화를 위해 설계와 운영에 신경 씀
-
gRPC: 모듈간 통신 인터페이스를 코드로 명확히 정의할 수 있는 장점. 자동화 도구와 연동성이 뛰어남
- 단, 빌드·툴링·디버깅은 복잡하고, JSON API 대비 직관성이 떨어지는 단점도 경험
- grpc-gateway를 통해 웹클라이언트 지원 및 대량 트래픽을 무리 없이 처리함
Strict backwards compatibility
-
API 및 데이터베이스의 하위 호환성 유지를 엄격하게 지킴
- 공개 API의 필드는 절대 삭제하지 않고, 보안 문제가 있지 않는 한 평생 유지
- DB 컬럼도 추가는 자유롭지만 삭제는 여러 단계 검증(참조 제거→몇 주 대기→실제 삭제) 절차를 거침
- 이 규율이 높은 변화 속도와 안정적인 배포·운영의 핵심 기반이 됨
Faceted search
-
ElasticSearch 대신 Postgres만으로 페이시티드 검색 구현
- well-indexed plan 테이블에 조건을 조합하는 250줄 함수 하나로 모든 검색 로직을 처리
- 비즈니스 요구에 집중, 불필요한 복잡성 없이 단순하게 해결함
Database
-
creation
- DB 스키마를 숫자가 붙은 .sql 파일로 관리, 순서대로 로딩하여 신뢰성 보장
-
planinfo/beneinfo DB는 매일 재생성, 마이그레이션 필요 없음. 버전 불일치 등 설정 오류 시 앱 자체를 아예 시작하지 않도록 설계
-
ETL
- 데이터 소스별 셸 스크립트로 S3에 적재 → cron으로 EC2 인스턴스가 최신 ETL 코드/데이터 가져와 신규 RDS DB 생성
- Postgres의 COPY 구문을 적극 활용, INSERT 대신 대량 데이터 적재를 효율적으로 처리
- 매일 2~4시간이면 수억 행 데이터를 새 DB로 전환 가능
-
models
-
xo 라이브러리로 DB 모델 자동 생성, 커스텀 템플릿으로 팀에 맞는 코드 생성
-
testing
-
가장 큰 실수는 sqlmock을 활용한 테스트를 과하게 만들어 데이터가 자주 바뀌는 상황에서 유지보수가 매우 번거로움
- 실제 불변 DB라면 실DB에 대한 테스트가 더 효율적이었을 것
-
Local database for development
- 각 테이블의 부분 데이터를 자동 생성하는 스크립트로, 개발자별로 작은 로컬 DB로 실제 데이터 기반 테스트와 개발 가능
- DB가 커지기 전에 이런 도구를 마련하면 전체 팀 개발 효율이 극대화됨
Miscellaneous tooling
- 각종 운영·관측 자동화를 위해 CLI 도구를 셸 스크립트로 구현, 모든 유틸리티 기능을 하나로 모아 관리
- splunk 로그를 Slack 명령어로 바로 그래프로 시각화하는 등 현장 중심의 도구를 적극 개발·활용
Logging
- 요청 진입 시점에 request id를 생성, 그 id가 모든 로그 컨텍스트에 붙어서 어디서든 추적 가능
-
zerolog로 안전하고 체계적인 로깅 설계
- 시스템 입구·퇴출, 예외 상황 등 중요 시점마다 필수 로그 남기기
Documentation
- GitHub markdown 문서를 sphinx-book-theme으로 변환해 위키북으로 운영
- 팀원 모두가 적극적으로 문서화에 기여, 한 곳에서 모든 시스템 문서를 찾을 수 있도록 함
- 뛰어난 문서화 문화가 팀의 성장과 유지보수, 신입 온보딩 효율을 크게 높임
Runtime integrations
- 클라이언트의 성능 저하 요청(분석 스크립트 삽입 등)은 최대한 설득해 최소화
- 쿼리도 브라우저 런타임이 아닌 빌드타임 처리로 전환해, 서비스 성능을 유지
- 실제론 고객 요청을 모두 막지는 못해, 일부는 성능 저하로 이어졌음
And more
- 기술 이외에도 긍정적이고 협력적인 팀 분위기와 강한 동기 부여가 대규모 시스템 성공의 진짜 원동력임을 강조
- 사소하지만 중요한 실무적 선택과 꾸준한 품질 관리의 힘을 실감한 사례였음