duckdb

1 개의 포스트

datadog

AI 지원 리팩토링을 활용해 실시간 라우팅 시스템을 마이그레이션한 방법 (새 탭에서 열림)

Datadog은 Stream Router의 기존 FoundationDB 기반 KV 모델이 트랜잭션 크기와 데이터 증가에 따른 한계에 도달하자, 운영 중단 없이 PostgreSQL·DuckDB 기반의 관계형 구조로 전환했습니다. 이 과정에서 Claude와 Cursor를 활용했지만, AI가 자율적으로 코드를 작성한 것이 아니라 사람이 새 스키마와 기존 구현, 실패 테스트를 제공하고 테스트 결과로 검증하는 방식으로 사용했습니다. 핵심 결론은 AI가 대규모 마이그레이션을 크게 가속할 수 있지만, 데이터 모델 설계와 안전성 판단은 여전히 사람의 전문성이 필요하다는 것입니다. ## Stream Router의 역할과 기존 아키텍처 - Datadog은 하루 100조 개가 넘는 이벤트를 처리하며, 각 메트릭 데이터를 올바른 Kafka 클러스터·토픽·파티션으로 라우팅해야 합니다. - Stream Router는 Kafka 메시지를 직접 생산하거나 소비하지 않고, 다른 서비스가 사용할 라우팅 결정을 관리하는 제어 평면 서비스입니다. - 라우팅 정보는 다음과 같은 용도로 사용됩니다. - Producer가 데이터를 기록할 위치 결정 - Querier가 데이터를 읽을 위치 결정 - 시간에 따른 데이터 위치 이력 관리 - 기존 구조는 쓰기와 읽기를 분리한 Eventually Consistent 아키텍처였습니다. - 쓰기 경로: FoundationDB의 키-값 모델 사용 - 읽기 경로: 주기적으로 생성된 스냅샷을 RocksDB와 메모리 데이터베이스에 적재 - Producer와 Querier는 쓰기 경로에 직접 접근하지 않음 ## 설정 파일에서 중앙 제어 평면으로의 발전 - 2016년에는 몇 줄짜리 설정 파일을 모든 서비스에 배포해 라우팅을 관리했습니다. - 인프라와 고객 규모가 커지면서 설정 파일이 수천 줄로 증가했고, 수동 편집과 배포가 운영 부담이 되었습니다. - Stream Router 도입 후에는 다음과 같이 개선되었습니다. - 설정 파일 대신 gRPC API로 라우팅 변경 - 자동화된 오케스트레이션 - 점진적이고 자동화된 롤아웃 - 고가용성과 장애 내성을 고려한 읽기·쓰기 분리 ## KV 모델의 확장 한계 - 라우팅 데이터는 단순한 키-값 목록이 아니라 서로 연결된 관계형 데이터였습니다. - Route는 특정 Kafka Stream을 참조 - Route는 Sharding Strategy를 참조 - Rule은 Route를 참조하고 활성화 시점과 적용 방식을 결정 - 기존 KV 구조에서는 데이터베이스가 제공해야 할 관계 검증을 애플리케이션이 직접 수행해야 했습니다. - 수만 개의 레코드를 Pod 프로세스로 가져옴 - 애플리케이션 내부에서 관계형 데이터베이스처럼 조인과 일관성 검사를 수행 - 데이터와 변경 규모가 커지면서 FoundationDB 트랜잭션 크기 제한에 걸리는 작업이 발생했습니다. - FoundationDB를 PostgreSQL로 단순 교체하는 방안도 해결책이 되지 못했습니다. - 기존 KV 접근 패턴을 그대로 유지하면 수천 번의 순차적인 데이터베이스 왕복이 필요 - 일부 작업은 약 45분이 걸릴 것으로 예상 - 따라서 병목의 원인은 특정 데이터베이스가 아니라, KV에 맞춰진 데이터 모델과 애플리케이션 로직 자체였습니다. ## 관계형 스키마로 재설계 - 팀은 AI를 사용하기 전에 도메인 관계를 직접 분석하고 새 스키마를 설계했습니다. - 관계형 구조에서는 다음 관계를 외래 키로 명시합니다. - Streams와 Sharding Strategies → Routes - Routes → Rules - 기존 애플리케이션 코드가 수동으로 복원하던 관계를 데이터베이스가 직접 표현하고 검증할 수 있게 되었습니다. - 쓰기 경로에는 PostgreSQL을 선택했습니다. - 관계형 의미론 지원 - 트랜잭션 처리 - Datadog의 자체 관리형 PostgreSQL 플랫폼 활용 가능 - 읽기 경로에는 DuckDB를 선택했습니다. - 스냅샷 기반 읽기 계층에 적합한 임베디드 데이터베이스 - 배열 컬럼을 기본 지원 - PostgreSQL과 유사한 SQL 문법 - PostgreSQL과 DuckDB 사이에서 쿼리 로직을 공유할 수 있음 - SQLite도 검토했지만 배열 컬럼을 기본 지원하지 않아 적합하지 않았습니다. ## AI를 활용한 테스트 중심 리팩터링 - Claude와 Cursor는 코드를 독립적으로 생성하도록 맡기지 않았습니다. - 각 메서드마다 사람이 다음 정보를 제공했습니다. - 기존 구현 - 새 데이터베이스 스키마 - 현재 실패하는 테스트 - AI는 이를 바탕으로 첫 번째 구현을 만들었고, 테스트가 코드의 정확성을 검증했습니다. - 이 방식의 장점은 다음과 같습니다. - 전체 마이그레이션을 한 번에 생성하지 않고 메서드 단위로 분할 - 실패 테스트가 요구사항과 오류를 구체적으로 제시 - 생성 코드가 실제 동작과 데이터 관계를 만족하는지 즉시 확인 - 사람이 설계와 판단을 담당하고 AI는 반복적인 변환 작업을 가속 ## 안전한 마이그레이션을 가능하게 한 조건 - 마이그레이션이 성공할 수 있었던 기반은 AI보다 기존 시스템의 구조와 개발 프로세스였습니다. - 특히 저장소 계층이 `Controller`라는 내부 인터페이스 뒤에 모듈화되어 있었습니다. - 이러한 추상화 덕분에 저장 엔진과 구현을 교체하더라도 상위 계층의 변경 범위를 줄일 수 있었습니다. - 글의 제공된 부분은 안전성을 뒷받침한 요소를 설명하는 도중 끝나므로, 이후 테스트 전략이나 실제 전환 절차의 상세 내용은 포함되어 있지 않습니다. 결국 AI는 관계형 스키마를 설계하거나 운영 위험을 판단하는 도구라기보다, 명확한 설계와 테스트가 준비된 상태에서 반복적인 코드 변환을 빠르게 수행하는 도구로 활용하는 것이 적절합니다. 대규모 운영 시스템에서는 먼저 데이터 모델과 인터페이스를 사람이 설계하고, 작은 단위의 실패 테스트를 기준으로 AI 생성 코드를 검증하는 방식을 추천할 수 있습니다.