문제점 및 해결 방안
기존 분석 벤더는 여러 가지 심각한 문제점을 안고 있었습니다. Doximity는 이러한 문제점들을 해결하기 위해 Rails 기반의 자체 솔루션으로 전환하는 대규모 마이그레이션을 단행했습니다.
1. 직접 비용 (Direct Costs)
-
문제점: 연간 약 25만 달러에 달하는 높은 계약 비용과 독특한 가격 모델(고유 사용자 수 기반)로 인해 공용 페이지에 분석 코드가 실수로 삽입될 경우 막대한 초과 요금이 발생했습니다.
-
해결 방안: 자체 Rails 솔루션으로 전환함으로써 벤더 계약 비용을 완전히 제거하고, 공용 페이지 트래픽에 대한 비용 부담 없이 모든 데이터를 추적할 수 있게 되었습니다. 이는 연간 25만 달러 이상의 직접적인 비용 절감 효과를 가져왔습니다.
2. 유효성 검사 (Validations)
-
문제점: 초당 약 3,000건의 이벤트가 발생하는 대규모 환경에서 데이터의 표준화된 형식을 유지하기 위한 유효성 검사가 필수적이었으나, 벤더는 64MB에 달하는 복잡한 JSON 스키마 기반의 유효성 검사를 지원하지 않았습니다. 이로 인해 iOS, Android, 웹, Ruby 서버 등 6개의 클라이언트에 각각 유효성 검사 로직을 내장하고 독립적으로 배포해야 하는 유지보수 부담이 컸습니다.
-
해결 방안: Rails 서버에서 유효성 검사 로직을 중앙 집중화했습니다.
Active Model Validations을 활용하여 복잡한 스키마를 쉽게 관리하고, 유효하지 않은 이벤트는 별도의 ‘invalid’ 토픽으로 분리하여 개발자가 문제 원인을 명확히 파악하고 수정할 수 있도록 했습니다.
3. QA 시간 소모 (QA Time Sync)
-
문제점: QA 팀은 분석 데이터의 유효성을 검증하기 위해 프로덕션 환경에서 수동으로 이벤트를 발생시킨 후, 초당 3,000개의 이벤트가 스트리밍되는 벤더의 웹 페이지에서 원하는 이벤트를 1/6초 안에 찾아야 했습니다. 이는 매우 비효율적이었으며, 한 번에 하나의 분석 이벤트만 검증할 수 있어 신규 기능 배포 시 QA 시간이 크게 늘어났습니다.
-
해결 방안: Rails의
Action Cable을 활용하여 QA 전용 웹 인터페이스를 구축했습니다. QA 팀은 자신의 사용자 ID로 이벤트를 필터링하여 실시간으로 관련 이벤트를 확인할 수 있게 되었습니다. 이로써 20개의 이벤트를 검증하는 작업이 단 한 번의 작업으로 단축되었고, 유효하지 않은 이벤트도 즉시 파악할 수 있게 되었습니다.
4. 느린 데이터 처리 속도 (Slowness)
-
문제점: 분석 데이터가 벤더에서 Doximity의 내부 데이터 저장소로 전송되는 데 1~3시간이 소요되어 QA 및 문제 해결이 지연되었고, 비즈니스 팀의 의사 결정에도 부정적인 영향을 미쳤습니다.
-
해결 방안: 자체 Rails 파이프라인은 클라이언트에서 데이터 저장소까지 1초 미만의 처리 속도를 달성했습니다. 이는 Kafka를 통한 실시간 이벤트 스트리밍과 효율적인 Rails 애플리케이션 설계를 통해 가능해졌습니다.
5. 시스템 가시성 부족 (Lack of Visibility)
-
문제점: 벤더 시스템은 단순한 이벤트 전달량만 보여줄 뿐, 유효/유효하지 않은 이벤트 수, 오류율 등 시스템의 상세한 상태를 파악할 수 있는 가시성을 제공하지 않았습니다. 이로 인해 문제 발생 시 원인 파악이 어려웠습니다.
-
해결 방안: Prometheus와 Grafana를 활용하여 모든 파이프라인 단계(수신, 파싱, 검증 등)에 대한 포괄적인 대시보드를 구축했습니다. 각 단계에서 발생하는 이벤트 수, 처리 시간, 오류 등을 실시간으로 모니터링하여 시스템의 건전성을 완벽하게 파악하고 신속하게 대응할 수 있게 되었습니다.
아키텍처 및 구현
Doximity는 CloudFront를 리버스 프록시로, AWS Kinesis를 딜리버리 큐로, S3를 백업 저장소로 활용하여 강력한 신뢰성을 확보했습니다. 핵심은 Kafka를 이벤트 스트리밍 플랫폼으로 사용하고, Rails 애플리케이션을 통해 데이터를 처리하는 것입니다.
-
API 스테이지: Rails 컨트롤러는 클라이언트 요청을 받아
kafka_rbGem을 통해 ‘raw_event’ 토픽으로 이벤트를 발행합니다. 에러 발생 시 ‘dead_letter_event’ 토픽으로 전송하여 시스템 중단 없이 에러를 기록합니다. -
파싱 스테이지: 별도의 Rails 프로세스가 ‘raw_event’ 토픽을 구독하여 데이터를 표준화된 형식으로 파싱하고 ‘ready_event’ 토픽으로 발행합니다. 봇 트래픽 등 불필요한 이벤트는 ‘discarded’ 토픽으로 보냅니다.
-
유효성 검사 스테이지: 또 다른 Rails 프로세스가 ‘ready_event’ 토픽을 구독하여 유효성 검사를 수행합니다. 유효한 이벤트는 ‘valid_event’ 토픽으로, 유효하지 않은 이벤트는 ‘invalid_event’ 토픽으로 발행합니다.