Apache Kafka

36 개의 포스트

kakao4분 읽기큐레이션 요약

잃어버린 리포트를 찾아서: 카카오 메시징 시스템의 경쟁 조건 문제와 안티 패턴 제거 과정

KIMS의 메시지 상태가 `SENT`에 멈춘 원인은 벤더사의 전송 결과 리포트가 메시지 레코드의 DB 커밋보다 먼저 도착하는 경쟁 조건이었다. 특히 응답이 빠른 특정 벤더와, 과금 후처리로 트랜잭션이 길어진 유료 메시지에서 문제가 집중되었으며, 전체 메시지의 약 0.02%에서 발생했다. 트랜잭션 범위를 줄이고 각 보장의 필요성을 재검토하는 과정에서, 불필요한 장기 트랜잭션과 외부 이벤트 발행을 분리해야 한다는 결론에 도달했다. ### KIMS 메시지 처리 구조 - KIMS는 카카오 내부 서비스용 SMS 전송 플랫폼으로, 하루 약 100만 건을 처리한다. - 다수의 IDC와 MSA 컴포넌트, 여러 외부 SMS 벤더로 구성되어 있다. - 기본 흐름은 다음과 같다. - API Server가 품질 지표를 기준으로 벤더를 선택한다. - 벤더 호출 후 메시지를 `SENT` 상태로 DB에 기록한다. - 벤더가 전송 결과 리포트를 전달한다. - Report Server가 메시지를 `REPORTED` 상태로 갱신한다. - 각 단계가 비동기적으로 분리되어 있어, 처리 순서가 뒤집힐 가능성이 존재했다. ### `SENT` 상태에 멈춘 메시지 - 일부 메시지가 리포트를 수신했음에도 `REPORTED`로 갱신되지 않았다. - Report Server 로그에는 벤더 리포트 수신 기록이 남아 있었다. - 즉, 리포트가 네트워크에서 유실된 것이 아니라 DB 반영 전에 폐기된 상황이었다. - 문제가 전체 메시지가 아닌 약 0.02%에서만 발생해 재현과 원인 분석이 어려웠다. ### 빠른 벤더와 긴 트랜잭션이 만든 경쟁 조건 - 리포트 누락은 특정 벤더로 전송된 메시지에서 집중적으로 발생했다. - 해당 벤더는 API 호출 후 평균 약 20ms, 문제 사례에서는 약 8ms 만에 리포트를 보냈다. - 반면 API Server는 벤더 호출 이후 후처리와 DB 영속화를 진행하고 있었다. - 유료 메시지는 과금 이벤트 발행 로직까지 하나의 `@Transactional` 범위에 포함되어 트랜잭션이 더 오래 유지됐다. - 결과적으로 처리 순서가 다음처럼 역전될 수 있었다. - API Server가 벤더 호출 - 과금 후처리와 이벤트 발행 수행 - 벤더가 리포트 전송 - Report Server가 상태 갱신 시도 - 아직 메시지 레코드가 DB에 없어 리포트가 유효하지 않은 것으로 판단되어 Drop - API Server가 뒤늦게 메시지를 DB에 저장 - 메시지의 초기 상태를 기록하는 Write 경로와 리포트를 읽어 상태를 갱신하는 Read 경로가 같은 시점에 교차하면서 Race Condition이 발생했다. ### 트랜잭션 범위 줄이기 - 기존 트랜잭션에는 DB 상태 변경뿐 아니라 Kafka 이벤트 발행 등 비즈니스 로직도 포함되어 있었다. - 이로 인해 Long-lived Transaction이 발생하고 DB Commit 시점이 지연됐다. - 과금 이벤트 발행을 `@Async`, `@TransactionalEventListener` 기반으로 분리해 커밋 이후 별도 스레드에서 실행하도록 변경했다. - 트랜잭션 책임을 상태 변경과 DB 영속화까지로 제한했다. - 평균 커밋 시점이 약 10ms 앞당겨졌고, 리포트 누락도 눈에 띄게 감소했다. - 외부 이벤트 발행 실패 때문에 DB 트랜잭션 전체가 롤백되는 Dual-write 문제도 완화됐다. - 외부 시스템으로 보내는 이벤트는 DB 트랜잭션과 본질적으로 동시에 롤백할 수 없으므로, 트랜잭션 내부에 무리하게 포함하는 방식은 부적절했다. ### 트랜잭션 보장의 필요성 재검토 글은 단순히 트랜잭션을 짧게 만드는 데서 그치지 않고, 해당 업무에 트랜잭션 자체가 필요한지 질문한다. MySQL의 `REPEATABLE READ`에서 제공되는 보장을 세 가지로 나누어 검토했다. - **원자성** - 여러 쓰기 작업 중 일부만 성공하는 상황을 막고 전체를 롤백하는 기능이다. - 해당 로직의 DB 쓰기는 사실상 단일 작업이었다. - 여러 테이블이나 레코드에 걸친 원자성이 필요하지 않다면 트랜잭션의 Abortability는 필수적이지 않을 수 있다. - **읽기 격리** - 라우팅 벤더 정보와 실시간 품질 지표를 조회하고 있었다. - 품질 지표는 분 단위로 갱신되며, 1분 전 데이터가 사용되어도 문제가 없었다. - 서로 독립적인 메타데이터를 조회하므로 동일한 스냅샷에서 읽어야 할 필요도 크지 않았다. - **쓰기 격리** - 변경 내용을 커밋 전까지 다른 트랜잭션에 노출하지 않는 보장이다. - JPA/Hibernate의 Dirty Checking에서는 변경 사항이 먼저 Persistence Context의 1차 캐시에 반영되고, 실제 DB Write는 트랜잭션 종료 시점까지 지연될 수 있다. - 이 지연이 리포트 처리보다 DB 저장이 늦어지는 직접적인 원인이 되었다. ### 실용적인 설계 교훈 - 외부 시스템의 응답 시간이 매우 짧을 수 있다는 전제에서 비동기 흐름을 설계해야 한다. - “호출 후 DB 저장”처럼 순서를 가정한 구조는 벤더별 응답 편차 때문에 경쟁 조건을 만들 수 있다. - 트랜잭션에는 반드시 원자적으로 처리해야 하는 DB 작업만 포함하고, 이벤트 발행·외부 API 호출·긴 후처리는 분리하는 것이 좋다. - 트랜잭션의 원자성·읽기 격리·쓰기 격리가 실제 비즈니스 요구사항인지 각각 검토해야 한다. - 리포트 처리에서는 아직 원본 메시지가 저장되지 않은 경우를 단순 Drop하지 말고, 재시도·지연 큐·Transactional Outbox 같은 보완책을 함께 고려해야 한다.

원문 읽기(새 탭에서 열림)
pinterest원문

Pinterest의 차세대 DB 인 (새 탭에서 열림)

Pinterest는 기존의 파편화된 배치 기반 DB 적재 시스템을 개선하기 위해 Iceberg와 CDC(Change Data Capture) 기술을 결합한 통합 프레임워크를 구축했습니다. 이 시스템은 데이터 지연 시간을 24시간 이상에서 수 분 단위로 단축하고, 변경된 데이터만 처리하는 방식으로 인프라 비용을 획기적으로 절감했습니다. 이를 통해 분석, 머신러닝, 규정 준수 등 현대적인 데이터 요구사항에 기민하게 대응할 수 있는 고성능 데이터 생태계를 마련했습니다. ### 통합 CDC 프레임워크의 계층 구조 * **CDC 레이어**: Debezium 및 TiCDC를 활용해 MySQL, TiDB, KVStore의 변경 사항을 1초 미만의 지연 시간으로 포착하여 Kafka에 기록합니다. * **스트리밍 레이어**: Flink 작업이 Kafka의 이벤트를 실시간으로 처리하여 S3에 위치한 'CDC Iceberg 테이블'에 추가 전용(Append-only) 방식으로 저장합니다. * **배치 레이어**: Spark 작업이 주기적으로(15~60분) CDC 테이블의 최신 변경 사항을 읽어 `Merge Into` 구문을 통해 최종 'Base Iceberg 테이블'에 업서트(Upsert)를 수행합니다. * **부트스트랩 및 유지보수**: 초기 데이터 로드를 위한 전용 파이프라인과 소형 파일 압축(Compaction) 및 스냅샷 만료 관리를 위한 유지보수 작업을 포함합니다. ### CDC 테이블과 베이스 테이블의 이원화 관리 * **CDC 테이블**: 모든 변경 이력을 담은 시계열 원장으로, 5분 미만의 지연 시간을 유지하며 원천 데이터의 변경 로그를 보존합니다. * **베이스 테이블**: 온라인 DB의 현재 상태를 그대로 반영하는 스냅샷 테이블입니다. CDC 테이블로부터 최신 레코드를 추출하여 정합성을 맞춥니다. * **동기화 로직**: `ROW_NUMBER()` 함수를 활용해 기본 키(PK)별로 가장 최신 업데이트(최근 타임스탬프 및 GTID 기준)를 식별한 후, 삭제 유형은 제거하고 나머지는 업데이트 또는 삽입합니다. ### 성능 및 비용 최적화 전략 * **Merge-on-Read (MOR) 방식 채택**: Copy-on-Write(COW) 방식은 업데이트 시 대규모 파일을 다시 작성해야 하므로 스토리지와 계산 비용이 높습니다. Pinterest는 비용 효율성을 극대화하기 위해 MOR 방식을 표준 전략으로 선택했습니다. * **기본 키 해시 버킷팅(Bucketing)**: 베이스 테이블을 PK의 해시값(예: `bucket(100, id)`)으로 파티셔닝하여 Spark가 업서트 작업을 병렬로 효율적으로 처리할 수 있도록 설계했습니다. * **증분 처리 효율성**: 매일 전체 테이블을 덤프하던 방식에서 변경된 데이터(통상 5% 미만)만 처리하는 방식으로 전환하여 연산 리소스 낭비를 차단했습니다. 방대한 양의 데이터베이스를 데이터 레이크로 통합할 때는 Iceberg의 `Merge Into` 기능을 활용한 증분 업데이트가 필수적입니다. 특히 읽기 성능과 쓰기 비용 사이의 균형을 위해 MOR 전략을 사용하고, 쓰기 병목을 해소하기 위해 기본 키 기반의 버킷팅을 적용하는 것이 실무적으로 매우 효과적인 접근임을 보여줍니다.

naver원문

비용, 성능, 안정성을 목표로 한 지능형 로그 파이프라인 도입 (새 탭에서 열림)

네이버의 통합 데이터 플랫폼 AIDA 내 로그 수집 시스템인 'Logiss'는 대규모 로그 파이프라인을 운영하며 겪었던 무중단 배포의 한계, 리소스 낭비, 로그 중요도 미분류 문제를 해결하기 위해 지능형 파이프라인을 도입했습니다. 핵심은 Storm의 멀티 토폴로지 구성을 통한 블루-그린 배포 구현과 실시간 트래픽 상태에 따라 처리 속도를 동적으로 조절하는 지능형 제어 알고리즘의 적용입니다. 이를 통해 서비스 중단 없는 배포는 물론, 인프라 비용을 약 40% 절감하고 장애 시 핵심 로그를 우선 처리하는 안정성까지 확보하며 성능과 비용의 최적점을 찾아냈습니다. **멀티 토폴로지와 블루-그린 배포를 통한 무중단 운영** * 기존 Traffic-Controller는 단일 토폴로지 구조로 인해 배포 시마다 데이터 처리가 3~8분간 중단되는 문제가 있었으나, 이를 해결하기 위해 멀티 토폴로지 기반의 블루-그린 배포 방식을 도입했습니다. * Storm 2.x의 `assign` 방식 대신 Kafka의 컨슈머 그룹 관리 기능을 활용하는 `subscribe` 방식으로 내부 로직을 커스텀 변경하여, 여러 토폴로지가 동일 파티션을 중복 소비하지 않도록 개선했습니다. * 이를 통해 트래픽이 몰리는 낮 시간대에도 중단 없이 안전하게 신규 기능을 배포하고 점진적인 트래픽 전환이 가능해졌습니다. **지능형 트래픽 제어를 통한 리소스 최적화** * 낮과 밤의 트래픽 차이가 5배 이상 발생하는 환경에서 피크 타임 기준으로 장비를 고정 할당하던 비효율을 제거하기 위해 '지능형 속도 제어' 알고리즘을 도입했습니다. * Kafka의 랙(lag) 발생량과 백엔드 시스템(OpenSearch 등)의 CPU 부하 상태를 실시간으로 감시하여, 시스템이 여유로울 때는 로그 처리 속도를 자동으로 높여 적체를 빠르게 해소합니다. * 유동적인 속도 조절 덕분에 기존 대비 투입 장비 리소스를 약 40% 절감하는 성과를 거두었으며, 갑작스러운 트래픽 유입에도 유연하게 대응할 수 있게 되었습니다. **로그 중요도 기반의 우선순위 처리** * 모든 로그를 동일한 속도로 처리하던 방식에서 벗어나, 비상 상황 발생 시 서비스 핵심 로그가 먼저 처리될 수 있도록 우선순위(High, Medium, Low) 개념을 도입했습니다. * 트래픽 지연이 발생하면 중요도가 낮은 로그의 처리 속도는 제한하고, 사업 및 서비스 운영에 필수적인 핵심 로그는 지연 없이 전송되도록 파이프라인 가용성을 확보했습니다. **저장소별 차등 샘플링을 통한 비용 절감** * 실시간 검색을 위한 OpenSearch와 장기 보관을 위한 랜딩 존(Landing Zone)에 데이터를 전송할 때, 각 저장소의 목적에 맞게 샘플링 비율을 다르게 설정할 수 있는 기능을 구현했습니다. * 모든 데이터를 무조건 100% 저장하는 대신, 분석 목적에 따라 일부 샘플링만으로 충분한 로그는 저장량을 줄여 인덱싱 부하를 낮추고 스토리지 비용을 효율적으로 관리할 수 있게 되었습니다. 대규모 로그 파이프라인 운영에서 비용 효율과 안정성은 상충하기 쉬운 가치이지만, 시스템의 상태를 실시간으로 파악하고 제어하는 '지능형' 로직을 통해 두 마리 토끼를 모두 잡을 수 있습니다. 특히 스트리밍 처리 프레임워크의 제약 사항을 직접 커스텀하여 비즈니스 요구사항에 맞춘 최적화 사례는 유사한 데이터 플랫폼을 운영하는 기술진에게 실무적인 통찰을 제공합니다.

toss원문

고객은 절대 기다려주지 않는다: 빠른 데이터 서빙으로 고객 만족도를 수직 상승 시키는 법 (새 탭에서 열림)

토스페이먼츠는 가파른 성장세에 따른 데이터 조회 부하를 해결하기 위해 CQRS 아키텍처를 도입하고 Apache Druid를 중심으로 한 데이터 서빙 환경을 구축했습니다. 초기에는 Elasticsearch와 Druid를 결합하여 대규모 시계열 데이터의 실시간 집계와 검색 성능을 확보했으며, 이를 통해 비용 효율성과 시스템 안정성을 동시에 달성했습니다. 현재는 Druid의 조인 제약과 멱등성 문제를 해결하기 위해 StarRocks를 도입하며, 도메인 간 결합이 자유로운 통합 원장 시스템으로 진화하고 있습니다. ### CQRS와 Apache Druid 도입 배경 * **MSA 전환과 DB 분리:** 서비스 규모가 커지며 모놀리식에서 MSA로 전환했으나, DB가 분산되면서 도메인 간 조인이나 통합 조회가 어려워지는 문제가 발생했습니다. * **명령과 조회의 분리:** 읽기 전용 저장소로 Apache Druid를 선택하여 원장 DB(MySQL)의 부하를 줄이고, 수십억 건의 데이터를 저지연으로 조회하는 CQRS 구조를 설계했습니다. * **Druid의 기술적 이점:** 시계열 데이터 최적화, SQL 지원을 통한 낮은 러닝 커브, 모든 컬럼의 비트맵 인덱스(Bitmap Index)화, 그리고 클라우드 네이티브 구조를 통한 비용 효율성을 고려했습니다. ### 데이터 가공 및 메시지 발행 방식 * **CDC 대신 메시지 발행 선택:** 데이터팀이 도메인 로직을 직접 소유해야 하는 CDC 방식 대신, 각 도메인 팀에서 완성된 데이터를 발행하는 방식을 채택하여 시스템 의존성을 Kafka로 단순화했습니다. * **역정규화 테이블 구성:** 복잡한 수단별 원장 데이터를 조회 친화적인 역정규화 테이블로 변환하여 적재했으며, JSON 필드 단위까지 비트맵 인덱스가 생성되어 효율적인 질의가 가능해졌습니다. ### AWS 환경에서의 비용 및 성능 최적화 * **컴퓨팅과 스토리지 분리:** 고가의 네트워크 스토리지(EBS) 대신 S3를 영구 저장소로 활용하고, 쿼리 수행 시에는 로컬 SSD를 사용하여 성능을 9배 이상 향상했습니다. * **스팟 인스턴스 활용:** 데이터가 S3에 안전하게 보관되는 특성을 이용해 개발/테스트 환경에서 스팟 인스턴스를 적극적으로 사용하여 월 5,000만 원 이상의 클라우드 비용을 절감했습니다. * **고가용성 확보:** 네트워크 스토리지 의존성을 제거함으로써 가용 영역(AZ) 간 분산 배치가 유연해져 시스템의 안정성을 높였습니다. ### Druid 운영의 기술적 도전과 극복 * **파편화 및 멱등성 문제:** 데이터가 시점별로 분산되는 파편화 현상을 해결하기 위해 60초 주기 탐지 프로세스와 자동 컴팩션(Compaction)을 도입했습니다. * **Rollup을 통한 성능 극대화:** 동일 차원의 데이터를 자동 집계하여 저장하는 Rollup 기능을 적용해, 수십 초 걸리던 집계 쿼리 응답 속도를 0.5~1초 내외로 99% 이상 개선했습니다. * **ES 하이브리드 아키텍처:** 단일 ID 기반의 고속 검색은 Elasticsearch가 담당하고, 필터링된 결과의 대규모 집계는 Druid가 처리하도록 역할을 분담해 검색 성능을 안정화했습니다. ### StarRocks 도입을 통한 통합 원장 구축 * **조인 및 멱등성 한계 극복:** Druid의 제한적인 조인 기능과 멱등성 처리의 어려움을 해결하기 위해 StarRocks를 새롭게 도입했습니다. * **도메인 간 데이터 결합:** 결제부터 매입, 정산까지 이르는 전체 라이프사이클을 한눈에 볼 수 있는 통합 원장을 구현하여 비즈니스 요구사항에 유연하게 대응하고 있습니다. **결론적으로** 대규모 트래픽 환경에서는 단순한 DB 분리를 넘어 검색(ES), 시계열 집계(Druid), 그리고 복잡한 조인과 멱등성 보장(StarRocks)이라는 각 도구의 장점을 살린 하이브리드 아키텍처 설계가 필수적입니다. 특히 스토리지와 컴퓨팅을 분리한 구조는 비용 절감뿐만 아니라 운영의 유연성을 확보하는 핵심 전략이 됩니다.

toss원문

레거시 결제 원장을 확장 가능한 시스템으로 (새 탭에서 열림)

토스페이먼츠는 20년 된 레거시 결제 원장의 구조적 한계와 도메인 간 강한 결합을 해결하기 위해 MySQL 기반의 신규 원장 시스템을 구축했습니다. 데이터 불변성을 보장하는 INSERT-only 원칙과 이벤트 기반 아키텍처를 도입하여 복합 결제 지원 등 비즈니스 확장성을 확보했습니다. 이 과정에서 발생한 데이터 불일치와 타임아웃 문제를 해결하며 시스템의 자가 회복 능력을 강화하고 안정적인 운영 환경을 마련했습니다. ### 레거시 원장 시스템의 한계와 과제 - **데이터 구조의 불일치:** 결제수단별로 테이블 구조가 다르고, 동일한 성격의 데이터가 서로 다른 테이블에 저장되어 유지보수와 온보딩에 큰 비용이 발생했습니다. - **도메인 간 강한 결합:** 결제, 정산, 회계 등 여러 서비스가 하나의 원장 테이블과 컬럼을 공유하여, 작은 기능 수정 시에도 전사적인 영향도 분석이 필요했습니다. - **구조적 확장성 부족:** 결제와 결제수단이 1:1 관계로 묶여 있어, 더치페이나 복합 결제(카드+포인트)와 같은 현대적인 결제 시나리오를 지원할 수 없었습니다. ### 신규 원장 설계의 3가지 전략 - **데이터 불변성과 일관성:** 모든 승인 내역을 공통 테이블(`approve`)에 저장하고, 수정 대신 INSERT-only 방식을 채택하여 데이터의 정합성을 높이고 데드락을 방지했습니다. - **이벤트 기반의 도메인 분리:** 각 도메인이 직접 DB를 조회하는 대신 Kafka 이벤트를 구독하여 데이터를 처리하게 함으로써 도메인 간 의존성을 제거했습니다. - **결제와 승인 개념의 분리:** '결제'는 주문의 상태를, '승인'은 실제 결제수단의 실행을 의미하도록 분리하여 하나의 결제에 여러 승인 수단이 연결될 수 있는 유연한 구조를 만들었습니다. ### 무중단 마이그레이션 및 정합성 검증 - **비동기 점진적 적재:** 실서비스 장애를 방지하기 위해 기존 원장에 먼저 저장한 후, 신규 원장에는 별도의 ThreadPool을 통한 비동기 방식으로 데이터를 적재했습니다. - **검증 배치 운영:** 비동기 적재 중 발생할 수 있는 누락을 방지하기 위해, 매 5분마다 Read-Only DB를 기반으로 기존 원장과 신규 원장의 데이터를 비교하고 보정하는 배치를 실행했습니다. - **고성능 이관 작업:** 수억 건의 데이터 이관을 위해 Bulk Insert를 도입하고, 네트워크 지연 최소화를 위해 마이그레이션 서버를 DB와 동일한 가용 영역(AZ)에 배치했습니다. ### 운영 중 장애 대응과 시스템 고도화 - **쿼리 최적화:** 옵티마이저의 판단 오류로 발생한 풀 스캔(Full Scan) 문제를 인덱스 힌트(Index Hint) 추가와 롤백 시스템을 통해 빠르게 해결했습니다. - **타임아웃 및 정합성 관리:** MSA 구조에서 서버 간 타임아웃 설정을 일치시키고, 외부 원천사와의 상태 불일치를 해결하기 위한 망취소(Network Cancellation) 로직을 강화했습니다. - **이벤트 처리의 신뢰성:** 아웃박스(Outbox) 패턴과 로그 기반 복구를 통해 이벤트 누락을 방지하고, 헤더에 멱등키를 포함해 중복 이벤트 처리 문제를 해결했습니다. 신규 시스템으로의 전환은 단순한 DB 교체가 아니라 시스템의 지속 가능성을 확보하는 과정입니다. 초기 설계의 완벽함보다 중요한 것은 운영 중 발생하는 예외 상황에 시스템이 스스로 대응하고 회복할 수 있는 '자가 회복 구조'를 갖추는 것이며, 이를 위해 데이터 보정 배치와 로깅 시스템 같은 안전장치를 반드시 고려해야 합니다.

naver원문

네이버 TV (새 탭에서 열림)

Apache Kafka의 차세대 소비자 그룹 프로토콜(Consumer Group Protocol v2)은 기존 v1 프로토콜이 가진 리밸런싱 성능의 한계와 복잡성을 근본적으로 해결하기 위해 도입되었습니다. 새로운 프로토콜은 리밸런싱 로직의 주체를 클라이언트에서 서버(Broker)로 옮겨 전체적인 시스템 안정성을 높였으며, 대규모 클러스터 운영 시 발생하던 중단 시간을 획기적으로 단축했습니다. 이 글은 네이버의 실무 경험을 바탕으로 v2의 주요 특징과 성능 개선 사항, 그리고 안정적인 마이그레이션 전략을 제시합니다. **기존 Consumer Group Protocol v1의 문제점** * **Stop-the-world 리밸런싱:** 리밸런싱이 발생하면 모든 컨슈머가 데이터 처리를 멈추고 파티션을 재할당받아야 하므로 일시적인 처리 지연이 불가피했습니다. * **클라이언트 측의 과도한 부담:** 리밸런싱 로직이 컨슈머 클라이언트에 포함되어 있어, 클라이언트 수가 늘어날수록 통신량과 계산 복잡도가 급증하는 구조적 한계가 있었습니다. * **디버깅의 어려움:** 리밸런싱 과정이 복잡하고 클라이언트별로 상태가 달라 문제 발생 시 원인 파악과 모니터링이 까다로웠습니다. **Consumer Group Protocol v2의 핵심 특징과 장점** * **서버 중심 리밸런싱:** 그룹 코디네이터(Broker)가 파티션 할당 로직을 직접 수행하여 클라이언트의 계산 부하를 줄이고 전체 프로세스를 단순화했습니다. * **점진적 협력 리밸런싱:** 모든 컨슈머를 멈추지 않고, 변경이 필요한 파티션만 점진적으로 재할당하여 서비스 가용성을 극대화했습니다. * **하트비트 메커니즘 개선:** 하트비트 응답 내에 리밸런싱 명령을 포함시켜 별도의 JoinGroup/SyncGroup 절차 없이도 빠른 상태 동기화가 가능해졌습니다. **성능 향상 및 운영 효율화** * **확장성 강화:** 수천 개의 파티션과 수백 명의 컨슈머가 참여하는 대규모 그룹에서도 리밸런싱 시간을 일관되게 유지합니다. * **불필요한 리밸런싱 감소:** 컨슈머의 일시적인 네트워크 순단이나 짧은 지연에 대해 보다 유연하게 대응하여 불필요한 그룹 재편성을 방지합니다. * **전용 툴 지원:** 새로운 프로토콜에 최적화된 모니터링 툴과 API를 통해 소비자 그룹의 상태를 더 정밀하게 확인하고 관리할 수 있습니다. **성공적인 마이그레이션 및 설정 가이드** * **호환성 확인:** Kafka 브로커와 클라이언트 버전을 확인하여 v2 프로토콜(KIP-848) 지원 여부를 먼저 점검해야 합니다. * **단계적 도입:** `group.protocol` 설정을 통해 기존 v1과 새로운 v2를 선택적으로 적용할 수 있으며, 개발 환경에서 충분한 검증 후 운영 환경에 반영하는 것이 권장됩니다. * **클라이언트 업데이트:** v2의 이점을 온전히 누리기 위해서는 브로커뿐만 아니라 컨슈머 클라이언트 라이브러리 역시 최신 버전으로 업그레이드해야 합니다. 대규모 트래픽을 처리하며 리밸런싱으로 인한 지연 시간에 민감한 서비스라면 Kafka 3.x 후반대 버전부터 도입된 Consumer Group Protocol v2로의 전환을 적극적으로 검토해야 합니다. 특히 컨슈머 그룹의 규모가 크거나 빈번한 배포가 일어나는 환경일수록 v2 도입을 통한 운영 안정성 향상 효과가 더욱 뚜렷하게 나타날 것입니다.

naver원문

6개월 만에 연간 수십조를 처리하는 DB CDC 복제 도구 무중단/무장애 교체하기 (새 탭에서 열림)

네이버페이는 차세대 아키텍처 개편 프로젝트인 'Plasma'의 최종 단계로, 연간 수십조 원의 거래 데이터를 처리하는 DB CDC 복제 도구인 'ergate'를 성공적으로 개발하여 무중단 교체했습니다. 기존의 복제 도구(mig-data)가 가진 유지보수의 어려움과 스키마 변경 시의 제약 사항을 해결하기 위해 Apache Flink와 Spring Framework를 조합한 새로운 구조를 도입했으며, 이를 통해 확장성과 성능을 동시에 확보했습니다. 결과적으로 백엔드 개발자가 직접 운영 가능한 내재화된 시스템을 구축하고, 대규모 트래픽 환경에서도 1초 이내의 복제 지연 시간과 강력한 데이터 정합성을 보장하게 되었습니다. ### 레거시 복제 도구의 한계와 교체 배경 * **유지보수 및 내재화 필요성:** 기존 도구인 `mig-data`는 DB 코어 개발 경험이 있는 인원이 순수 Java로 작성하여 일반 백엔드 개발자가 유지보수하거나 기능을 확장하기에 진입 장벽이 높았습니다. * **엄격한 복제 제약:** 양방향 복제를 지원하기 위해 설계된 로직 탓에 단일 레코드의 복제 실패가 전체 복제 지연으로 이어졌으며, 데이터 무결성 확인을 위한 복잡한 제약이 존재했습니다. * **스키마 변경의 경직성:** 반드시 Target DB에 칼럼을 먼저 추가해야 하는 순서 의존성이 있어, 작업 순서가 어긋날 경우 복제가 중단되는 장애가 빈번했습니다. * **복구 프로세스의 부재:** 장애 발생 시 복구를 수행할 수 있는 인원과 방법이 제한적이어서 운영 효율성이 낮았습니다. ### Apache Flink와 Spring을 결합한 기술 아키텍처 * **프레임워크 선정:** 저지연·대용량 처리에 최적화된 **Apache Flink(Java 17)**를 복제 및 검증 엔진으로 채택하고, 복잡한 비즈니스 로직과 복구 프로세스는 익숙한 **Spring Framework(Kotlin)**로 이원화하여 구현했습니다. * **Kubernetes 세션 모드 활용:** 12개에 달하는 복제 및 검증 Job을 효율적으로 관리하기 위해 세션 모드를 선택했습니다. 이를 통해 하나의 Job Manager UI에서 모든 상태를 모니터링하고 배포 시간을 단축했습니다. * **Kafka 기반 비동기 처리:** nBase-T의 binlog를 읽어 Kafka로 발행하는 `nbase-cdc`를 소스로 활용하여 데이터 유실 없는 파이프라인을 구축했습니다. ### 데이터 정합성을 위한 검증 및 복구 시스템 * **지연 컨슈밍 검증(Verifier):** 복제 토픽을 2분 정도 지연하여 읽어 들이는 방식으로 Target DB에 데이터가 반영될 시간을 확보한 뒤 정합성을 체크합니다. * **2단계 검증 로직:** 1차 검증 실패 시, 실시간 변경으로 인한 오탐인지 확인하기 위해 Source DB를 직접 재조회하여 Target과 비교하는 보완 로직을 수행합니다. * **자동화된 복구 흐름:** 일시적인 오류는 5분 후 자동으로 복구하는 '순단 자동 복구'와 배치 기반의 '장애 자동 복구', 그리고 관리자 UI를 통한 '수동 복구' 체계를 갖추어 데이터 불일치 제로를 지향합니다. ### DDL 독립성 및 성능 개선 결과 * **스키마 캐싱 전략:** `SqlParameterSource`와 캐싱된 쿼리를 이용해 Source와 Target의 칼럼 추가 순서에 상관없이 복제가 가능하도록 개선했습니다. Target에 없는 칼럼은 무시하고, 있는 칼럼만 선별적으로 반영하여 운영 편의성을 극대화했습니다. * **성능 최적화:** 기존 대비 10배 이상의 QPS를 처리할 수 있는 구조를 설계했으며, CDC 이벤트 발행 후 최종 복제 완료까지 1초 이내의 지연 시간을 달성했습니다. * **모니터링 강화:** 복제 주체(ergate_yn)와 Source 커밋 시간(rpc_time)을 전용 칼럼으로 추가하여 데이터의 이력을 추적할 수 있는 가시성을 확보했습니다. 성공적인 DB 복제 도구 전환을 위해서는 단순히 성능이 좋은 엔진을 선택하는 것을 넘어, **운영 주체인 개발자가 익숙한 기술 스택을 적재적소에 배치**하는 것이 중요합니다. 스트림 처리는 Flink에 맡기고 복잡한 복구 로직은 Spring으로 분리한 ergate의 사례처럼, 도구의 장점을 극대화하면서도 유지보수성을 놓치지 않는 아키텍처 설계가 대규모 금융 플랫폼의 안정성을 뒷받침합니다.

datadog원문

복제의 재정의: 저지연 멀티테넌트 데이터 복제 플랫폼 구축기 (새 탭에서 열림)

데이터독(Datadog)은 모놀리식 포스트그레스(Postgres) 데이터베이스의 확장성 한계와 수동 데이터 파이프라인의 복잡성을 해결하기 위해 자동화된 관리형 데이터 복제 플랫폼을 구축했습니다. 이 플랫폼은 체계적인 변경 데이터 캡처(CDC)와 비동기 복제 방식을 통해 데이터 일관성을 유지하면서도 시스템 성능을 비약적으로 향상시켰습니다. 결과적으로 엔지니어링 팀은 인프라 관리의 부담에서 벗어나 안정적이고 낮은 지연 시간으로 대규모 데이터를 다양한 서비스 간에 자유롭게 이동시킬 수 있게 되었습니다. **포스트그레스의 확장성 한계와 데이터 재건축** * 서비스 초기에는 포스트그레스의 ACID 보장과 편의성이 유용했으나, 데이터량이 증가하면서 복잡한 조인 및 집계 쿼리의 응답 시간이 수 밀리초에서 수 초 단위로 급격히 악화되었습니다. * 특정 조직의 메트릭 요약 페이지에서 수십만 개의 행을 조인할 때 P90 지연 시간이 7초에 달했으며, 인덱스 팽창(Bloat)과 VACUUM 작업 부하로 인한 I/O 병목 현상이 발생했습니다. * OLTP 부하와 검색/필터링 부하를 분리하기 위해, 복제 과정에서 데이터를 비정규화(Denormalization)하여 전용 검색 플랫폼으로 전송하는 아키텍처로 전환했습니다. * 이러한 최적화를 통해 페이지 로드 시간을 최대 97% 단축(30초 → 1초)하고, 복제 지연 시간을 500ms 수준으로 유지하는 성과를 거두었습니다. **Temporal을 활용한 복제 파이프라인 프로비저닝 자동화** * Debezium, Kafka, Elasticsearch 등 다양한 기술 스택이 결합된 복제 파이프라인을 수동으로 구축하는 과정은 운영상 큰 부담이 되었습니다. * 포스트그레스의 `wal_level` 설정, 논리적 복제 슬롯 생성, 사용자 권한 관리, Kafka 토픽 매핑 등 반복적이고 오류가 잦은 단계를 Temporal 워크플로우를 통해 모듈화했습니다. * WAL(Write-Ahead Log) 보존 문제를 해결하기 위한 하트비트 테이블 설정부터 싱크 커넥터 배포까지의 모든 과정을 오케스트레이션하여 운영 탄력성을 높였습니다. * 자동화된 플랫폼 덕분에 개발자들은 인프라 설정 대신 혁신에 집중할 수 있게 되었으며, 멀티 테넌트 환경에서도 일관된 파이프라인 관리가 가능해졌습니다. **성능과 확장성을 위한 비동기 복제 전략** * 강한 일관성을 보장하는 동기 복제 대신, 대규모 고처리량 환경에 적합한 비동기 복제 방식을 채택했습니다. * 동기 복제는 네트워크 지연이나 복제본의 응답 상태가 기본 시스템의 성능에 직접적인 영향을 주지만, 비동기 방식은 애플리케이션의 쓰기 성능을 네트워크 지연으로부터 격리합니다. * 장애 발생 시 미세한 데이터 지연이 발생할 수 있는 트레이드오프가 있으나, 이는 확장성과 가용성을 우선시하는 데이터독의 분산 환경에 더 적합한 선택이었습니다. **결론 및 권장사항** 대규모 시스템에서 데이터베이스의 성능 저하를 방지하려면 OLTP와 읽기 전용 검색 워크로드를 분리하는 것이 필수적입니다. 이때 발생하는 복잡한 데이터 이동 문제는 Temporal과 같은 워크플로우 엔진으로 자동화하여 운영 비용을 낮추고, 비동기 복제 모델을 통해 시스템의 전체적인 처리량과 가용성을 확보하는 전략이 권장됩니다.

netflix원문

넷플릭스에서 Write-Ahead (새 탭에서 열림)

넷플릭스는 대규모 데이터 환경에서 발생하는 데이터 손실, 시스템 엔트로피, 복제 및 재시도 메커니즘의 한계를 극복하기 위해 분산 **Write-Ahead Log(WAL)** 추상화 레이어를 구축했습니다. 이 시스템은 데이터 변경 사항을 캡처하고 강력한 내구성을 보장하며 하위 소비자에게 데이터를 안정적으로 전달하는 단일 인터페이스를 제공합니다. 결과적으로 개발자는 복잡한 데이터 정합성 문제를 직접 해결할 필요 없이 비즈니스 로직에 집중할 수 있게 되었으며, 플랫폼 전반의 탄력성과 운영 효율성이 크게 향상되었습니다. **WAL의 핵심 구조와 유연한 API** * **WriteToLog API:** 단순한 인터페이스를 통해 내부 구현을 추상화하며, 데이터 내구성을 '성공/실패/알 수 없음'의 세 가지 상태(Trilean)로 반환하여 신뢰성을 높였습니다. * **네임스페이스(Namespace):** 데이터의 저장 위치와 방식을 정의하는 논리적 격리 단위로, 설정에 따라 Kafka, SQS 등 다양한 기반 스토리지를 선택할 수 있습니다. * **페르소나 기반 아키텍처:** 네임스페이스 설정에 따라 지연 큐, 복제 도구, 인덱싱 도구 등 목적에 맞는 다양한 '페르소나'로 동작합니다. **지연 큐와 신뢰할 수 있는 재시도 메커니즘** * 네트워크 오류나 다운스트림 서비스 장애 발생 시 데이터 처리 처리량을 희생하지 않고도 실패한 메시지를 안전하게 재시도합니다. * SQS를 기본 스토리지로 활용하여 메시지 전달 시점을 조절하는 지연 기능을 구현함으로써 실시간 데이터 파이프라인의 안정성을 확보했습니다. **범용 교차 리전 복제 및 데이터 동기화** * Kafka를 활용하여 서로 다른 리전 간에 데이터를 복제하며, 기본적으로 복제를 지원하지 않는 스토리지 엔진에서도 리전 간 데이터 정합성을 유지할 수 있게 합니다. * Key-Value 저장소와 Elasticsearch 같은 서로 다른 데이터 저장소 간의 상태를 동기화하여 구체화된 뷰(Materialized Views)나 보조 인덱스를 안정적으로 구축합니다. **안정적인 데이터 삭제 및 부하 관리** * 데이터베이스에서 대량의 데이터를 삭제할 때 발생하는 메모리 부족(OOM) 문제를 해결하기 위해 WAL을 활용합니다. * 삭제 요청을 WAL에 기록한 후 처리 속도를 제어(Rate-limiting)하거나 예약된 시간에 실행함으로써 데이터베이스 노드에 가해지는 충격을 완화합니다. **시스템 설계 원칙과 격리 전략** * **수집 및 소비의 분리:** 고가용성 수집 레이어와 신뢰 중심의 소비 레이어를 분리하여 트래픽 급증이나 다운스트림 장애가 전체 시스템으로 전이되는 것을 방지합니다. * **멀티테넌시와 격리:** 공유 리소스를 사용하되 네임스페이스별로 격리된 리소스 풀을 할당하여 특정 작업이 다른 서비스의 성능에 영향을 주지 않도록 설계되었습니다. 데이터 플랫폼 차원의 통합 WAL 솔루션 도입은 각 서비스 팀이 개별적으로 구축하던 복제 및 재시도 로직의 중복을 제거하고 기술 부채를 크게 줄여줍니다. 대규모 분산 시스템을 운영하는 조직이라면 데이터의 최종 정합성과 시스템 탄력성을 확보하기 위해 이러한 추상화된 로그 계층을 검토하는 것이 권장됩니다.

airbnb원문

에어비앤비의 차세대 (새 탭에서 열림)

에어비앤비는 기존의 키-값(Key-Value) 저장소인 Mussel v1의 운영 복잡성과 확장성 한계를 극복하기 위해, NewSQL 백엔드 기반의 Mussel v2로 아키텍처를 전면 재설계했습니다. 새로운 시스템은 쿠버네티스 네이티브 환경에서 대규모 벌크 로드와 실시간 스트리밍 처리를 동시에 지원하며, 한 자릿수 밀리초 단위의 읽기 성능을 안정적으로 제공합니다. 결과적으로 에어비앤비는 데이터 일관성 제어권 확보와 비용 투명성 강화는 물론, 미션 크리티컬한 서비스들을 중단 없이 성공적으로 마이그레이션하는 성과를 거두었습니다. ### v1의 한계와 재설계 배경 * **운영 복잡성:** EC2와 Chef 스크립트에 의존했던 v1은 노드 확장이나 교체에 수 시간이 소요되었으나, v2는 쿠버네티스 매니페스트를 통한 자동화로 이를 수 분 이내로 단축했습니다. * **데이터 핫스팟:** 정적 해시 파티셔닝(Static Hash Partitioning) 방식은 특정 노드에 부하가 쏠리는 문제를 야기했으나, v2는 동적 범위 샤딩(Dynamic Range Sharding)을 도입하여 100TB 이상의 테이블에서도 안정적인 지연 시간을 유지합니다. * **가시성 부족:** 리소스 사용량이 불투명했던 과거와 달리, v2는 네임스페이스별 테넌시 관리와 쿼터 할당, 대시보드를 통해 비용 통제력을 높였습니다. ### Mussel v2의 핵심 아키텍처 * **Dispatcher:** 상태가 없는(Stateless) 쿠버네티스 서비스로, 클라이언트의 API 호출을 백엔드 쿼리로 변환하며 이중 쓰기(Dual-write)와 섀도우 리드(Shadow-read)를 관리합니다. * **이벤트 기반 쓰기:** 모든 쓰기 작업은 내구성을 위해 Kafka에 먼저 기록된 후 Replayer를 통해 백엔드에 반영되어, 트래픽 급증을 유연하게 흡수하고 일관성을 보장합니다. * **읽기 최적화:** 논리적 테이블 매핑을 통해 포인트 룩업, 범위 쿼리, 접두사 쿼리를 최적화하며, 지연 시간을 줄이기 위해 로컬 복제본으로부터의 읽기(Stale Read) 기능을 제공합니다. ### 벌크 로드 및 데이터 만료(TTL) 시스템 * **고성능 인입:** S3에 업로드된 대규모 데이터를 쿠버네티스 워커 플릿이 병렬로 처리하여 기존 테이블에 병합하거나 교체하는 벌크 로드 프로세스를 최적화했습니다. * **토폴로지 인지형 TTL:** 데이터 범위를 서브 태스크로 나누어 병렬로 스캔하고 삭제하는 서비스를 도입하여, 대규모 데이터셋에서도 라이브 쿼리에 영향을 주지 않고 효율적으로 스토리지를 관리합니다. ### 무중단 마이그레이션 전략 * **Blue/Green 방식 적용:** 기존 v1에 CDC(Change Data Capture) 기능이 부족했음에도 불구하고, Kafka 스트림을 활용한 맞춤형 파이프라인을 구축해 v1과 v2 간의 최종 일관성을 유지했습니다. * **단계적 전환:** 모든 트래픽을 v1으로 보내는 단계부터 v2에서 성능을 검증하는 섀도우 단계, v2를 주 저장소로 사용하는 리버스 단계를 거쳐 최종 컷오버(Cutover)를 진행했습니다. * **안정성 장치:** 테이블 단위로 마이그레이션을 수행하고 자동 서킷 브레이커와 즉시 롤백 로직을 구현하여, 데이터 손실이나 서비스 중단 없이 100개 이상의 유스케이스를 이전했습니다. 성공적인 저장소 엔진 교체는 단순히 성능 향상에 그치지 않고, 운영 자동화와 유연한 확장성을 통해 비즈니스 요구사항에 기민하게 대응할 수 있는 기반을 마련해 줍니다. 특히 대규모 데이터 마이그레이션 시 Kafka를 중간 매개체로 활용하고 단계별 검증 과정을 거치는 전략은 시스템 안정성을 확보하는 데 필수적인 요소입니다.

datadog원문

규모를 줄여 100배 향상한 실시간 프로세스 메트릭 효율성 (새 탭에서 열림)

Datadog은 프로세스 및 컨테이너 모니터링 시스템의 실시간 데이터 처리 방식을 '호스트 구독(Host Subscription)' 기반 모델로 전환하여 확장성 문제를 해결했습니다. 사용자가 현재 화면에서 보고 있는 특정 호스트(최대 50개)에 대해서만 2초 간격의 고빈도 수집을 활성화함으로써, 전체 트래픽 볼륨을 100배 줄이고 인프라 비용을 98% 절감하는 성과를 거두었습니다. 이 글은 불필요한 데이터 수집을 최소화하면서도 사용자 경험과 시스템 효율성을 동시에 개선한 기술적 여정을 다룹니다. ## 기존 실시간 데이터 수집의 한계 * **전체 활성화 방식의 비효율성:** 기존에는 테넌트 내 한 명의 사용자만 페이지를 조회해도 해당 테넌트 전체 인프라의 모든 호스트에서 2초 간격의 데이터 수집이 시작되었습니다. 이로 인해 초당 수백만 개의 프로세스 데이터가 유입되는 부하가 발생했습니다. * **수평적 확장 불가능:** 실시간 정렬 기능을 제공하기 위해 테넌트의 모든 데이터를 단일 서버의 메모리에 보관해야 했습니다. 이는 시스템을 수평적으로 확장하는 것을 불가능하게 만들었으며, 서버 사양을 높이는 수직적 확장에만 의존하게 했습니다. * **리소스 낭비:** 실제 사용자가 한 번에 확인하는 프로세스는 약 50개 내외임에도 불구하고, 보이지 않는 수만 개의 프로세스 데이터를 실시간으로 수집하고 처리하는 비효율이 존재했습니다. ## 사용자 가시성 중심의 설계 전환 * **실시간 수집 대상의 최소화:** 사용자가 보고 있는 화면에 노출된 프로세스가 실행 중인 호스트에 대해서만 실시간 모드를 활성화하도록 전략을 수정했습니다. * **데이터 용도 분리 및 정렬 로직 최적화:** 2초 간격의 실시간 데이터는 화면 갱신에만 사용하고, 10초마다 수행되는 정렬 작업에는 일반적인 10초 간격 데이터를 활용하도록 변경했습니다. * **시스템 단순화:** 실시간 뷰와 히스토리 뷰에서 동일한 정렬 로직을 사용할 수 있게 되어 시스템 복잡성이 줄어들었고, 고빈도 메트릭을 메모리에 상주시켜야 할 필요성도 사라졌습니다. ## 호스트 구독 모델 및 필터링 최적화 * **호스트 구독(Host Subscription) 도입:** 사용자가 현재 보고 있는 호스트 목록을 추적하고, 이 상태를 Kafka를 통해 인테이크(Intake) 서비스와 라이브 서버 간에 공유합니다. * **조기 필터링(Early Filtering):** 구독 정보를 바탕으로 데이터 수집 단계(Intake)에서부터 필요한 데이터만 선별하여 처리합니다. 이는 Datadog 에이전트와 백엔드 서버 모두의 부하를 줄이는 핵심 기여를 했습니다. * **성능 개선 결과:** 개념 증명(PoC) 단계에서 이미 라이브 데이터 서버의 메모리 사용량은 85%, CPU 사용량은 33% 감소했으며, 이는 시스템 전체의 안정성 향상으로 이어졌습니다. 대규모 인프라 모니터링 환경에서 모든 데이터를 실시간으로 수집하는 것은 막대한 비용과 확장성 문제를 야기합니다. 사용자의 가시성 범위 내로 수집 대상을 제한하고 데이터의 용도(갱신 vs 정렬)에 따라 수집 빈도를 이원화하는 접근 방식은 리소스 효율성을 극대화하면서도 고성능 실시간 뷰를 제공할 수 있는 실용적인 해결책이 됩니다.

line원문

DDD를 Merchant 시스템 구축에 활용한 사례를 소개합니다 (새 탭에서 열림)

기존의 음식 배달 중심 시스템에서 벗어나 소매 상품 판매에 최적화된 새로운 Merchant 시스템을 구축하기 위해 도메인 주도 설계(DDD)를 도입했습니다. 이번 프로젝트는 DDD가 단순히 코드 구현 기술이 아니라, 도메인의 역할과 책임을 명확히 정의하고 이를 바탕으로 조직 구조와 협업 방식을 설계하는 방법론임을 보여줍니다. 클린 아키텍처와 비동기 이벤트 기반의 모듈 구성을 통해 시스템의 확장성을 확보하고, 글로벌 팀 간의 원활한 협업 체계를 마련하며 성공적으로 시스템을 론칭했습니다. **소매 플랫폼으로의 전환과 도메인 정의** * 기존 시스템의 '음식점 기반 소매 판매' 한계를 극복하기 위해 독립적인 Merchant 시스템을 설계했습니다. * Merchant 시스템은 점포, 상품, 재고 등의 정보를 제공하고, 실제 판매는 '소비자 플랫폼'에서 담당하는 구조로 역할을 분리했습니다. * 핵심 도메인을 점포(shop), 상품(item), 카테고리(category), 재고(inventory), 주문(order)의 다섯 가지로 정의하여 복잡도를 낮추었습니다. **클린 아키텍처를 활용한 시스템 설계** * 도메인 엔티티가 외부 환경의 변화에 영향을 받지 않도록 클린 아키텍처를 채택했습니다. * 모든 팀원이 쉽게 이해하고 따를 수 있는 명확한 계층 구조를 통해 유지보수 편의성을 높였습니다. * 의존성 방향을 내부(도메인)로만 허용하여 비즈니스 로직의 순수성을 유지했습니다. **비동기 기반의 모듈 및 통신 구조** * 시스템을 외부 요청을 받는 'API' 모듈과 비즈니스 로직을 처리하는 '엔진' 모듈로 분리하여 가용성을 높였습니다. * gRPC를 통한 API 제공과 Apache Kafka 기반의 내부 통신을 결합했으며, Decaton 라이브러리를 사용해 파티션 대비 높은 처리량을 확보했습니다. * 플랫폼 특성을 고려하여 즉각적인 응답보다는 최종 일관성(Eventual Consistency)과 빠른 API 응답 능력에 초점을 맞춘 비동기 구조를 설계했습니다. **글로벌 협업과 조직의 일치(Conway's Law)** * 한국 팀은 핵심 도메인(Core)을, 일본 팀은 현지 시스템 연계(Link, BFF)를 담당하도록 조직을 구성해 콘웨이의 법칙을 실천했습니다. * 의사결정 과정과 논의 배경을 기록하는 ADR(Architectural Decision Record)을 활용해 조직 간의 공감대를 형성하고 불필요한 재논의를 방지했습니다. * 추상화된 연계 계층을 통해 새로운 소비자 플랫폼이 추가되더라도 핵심 도메인의 변화는 최소화되는 유연한 구조를 만들었습니다. 성공적인 DDD 적용을 위해서는 헥사고날 아키텍처와 같은 기술적인 구현에만 매몰되지 않는 것이 중요합니다. 도메인의 역할과 책임을 먼저 명확히 정의하고, 그 경계에 맞춰 팀 조직과 소통 구조를 설계할 때 진정한 설계의 이점을 얻을 수 있습니다. 시스템의 아키텍처가 조직의 소통 구조를 반영한다는 점을 인지하고, 기술과 조직 관리의 균형을 맞추는 접근이 권장됩니다.

datadog원문

수천 개의 예측 불가능한 엔드포인트에 안정적으로 로그를 전달한 방법 (새 탭에서 열림)

Datadog은 수천 개의 외부 엔드포인트로 로그를 안정적으로 전달하기 위해 물리적인 택배 배송 서비스의 원리를 소프트웨어 아키텍처에 도입했습니다. 특히 Kafka의 엄격한 순차 처리(FIFO) 특성으로 인해 발생하는 '특정 목적지의 장애가 전체 시스템을 마비시키는 문제'를 해결하는 데 집중했습니다. 이를 통해 저지연, 고처리량, 그리고 높은 신뢰성을 보장하는 멀티테넌트 로그 전달 시스템을 구축할 수 있었습니다. ### 로그 포워딩의 역할과 내부 데이터 흐름 * Datadog 로그 포워딩은 내부에서 처리된 JSON 형식의 로그를 ElasticSearch, Splunk, 또는 커스텀 HTTP 엔드포인트와 같은 외부 목적지로 전송하는 디지털 배송 서비스입니다. * 모든 로그 데이터는 내부적으로 Kafka 토픽을 통해 이동하며, 이는 마치 물류 센터의 컨베이어 벨트처럼 작동하여 데이터의 순서를 보장합니다. * 다양한 고객과 목적지로 향하는 로그들이 Kafka 파티션 내에 혼합되어 흐르기 때문에, 이를 목적지별로 다시 그룹화하여 효율적으로 전달하는 과정이 필요합니다. ### 외부 엔드포인트 연동 시 발생하는 병목 현상 * **엔드포인트 불확실성**: 외부 수신 서버는 Datadog의 통제 밖에 있으며, 수시로 응답이 느려지거나 일시적으로 오프라인 상태가 될 수 있습니다. * **Head-of-Line Blocking**: Kafka는 파티션 내의 데이터를 순서대로 처리(Commit)해야 합니다. 만약 특정 목적지의 서버가 응답하지 않아 전송에 실패하면, 해당 파티션에 담긴 다른 모든 목적지의 로그들까지 전송이 중단되는 병목 현상이 발생합니다. * **데이터 유실과 중복의 트레이드오프**: 전송 성공 확인 없이 다음 데이터를 읽으면 유실 위험이 있고, 성공할 때까지 무한히 재시도하면 전체 시스템의 지연 시간(Latency)이 급격히 증가합니다. ### 대규모 멀티테넌시 환경의 설계 제약 * **리소스 효율성**: 수만 개의 목적지마다 별도의 Kafka 토픽을 생성하는 것은 운영 오버헤드와 리소스 낭비가 너무 커서 현실적으로 불가능합니다. * **처리량 최적화**: 매 로그마다 HTTP 요청을 보내는 대신, 택배를 모아서 한 번에 배송하듯 적절한 '배치(Batch)' 처리를 통해 네트워크 오버헤드를 줄여야 합니다. * **보호 메커니즘**: 고객의 엔드포인트가 과부하로 인해 다운되지 않도록 전송 속도를 조절(Rate Limiting)하는 기능이 필수적입니다. ### 실용적인 결론 대규모 분산 시스템에서 외부 시스템과 연동하는 기능을 설계할 때는 **"단일 장애 지점이 전체 시스템에 미치는 영향"**을 최소화하는 격리 전략이 핵심입니다. Kafka와 같은 FIFO 기반 시스템을 사용할 경우, 장애가 발생한 데이터 스트림을 별도의 재시도 경로로 분리하여 정상적인 데이터 흐름이 방해받지 않도록 아키텍처를 구성해야 합니다.

datadog원문

수천 개의 워크로드 컨테이너에 빠르고 안정적인 구성 배포를 확장한 방법 (새 탭에서 열림)

데이터독(Datadog)은 초당 수백만 개의 로그를 처리하는 대규모 분산 환경에서 사용자가 설정한 로그 파싱 규칙 등 '컨텍스트 데이터'를 수천 개의 컨테이너에 실시간으로 전파해야 하는 과제에 직면해 있습니다. 단순히 데이터베이스를 조회하거나 짧은 주기의 캐시를 사용하는 방식은 대규모 트래픽 환경에서 DB 부하와 지연 시간 문제를 야기하며, 이를 해결하기 위해 데이터독은 안정성과 확장성을 모두 고려한 독자적인 설정 전파 시스템을 구축했습니다. ### 실시간 설정 전파의 기술적 도전 과제 * **컨텍스트 데이터의 중요성**: 로그 파싱 규칙, 민감 데이터 스캐너 설정, 저장 쿼터 등 사용자별(per-tenant) 설정 데이터는 데이터독 서비스가 고객 데이터를 처리하는 방식의 핵심을 이룹니다. * **낮은 지연 시간 요구**: 사용자가 UI에서 설정을 변경하면 '라이브 테일(Live Tail)'과 같은 실시간 서비스에 즉각 반영되어야 하며, 이는 수천 개의 워크로드 컨테이너가 변경 사항을 거의 동시에 인지해야 함을 의미합니다. * **고도의 신뢰성**: 컨텍스트 데이터는 데이터 처리에 필수적이므로, 이 데이터를 공급하는 시스템은 어떤 장애 상황에서도 견고하게 동작해야 하는 '록 솔리드(rock solid)'한 수준의 안정성이 요구됩니다. ### 단순 접근 방식의 한계 * **온디맨드 조회의 불가능**: 로그가 들어올 때마다 DB에서 설정을 읽어오는 방식은 초당 수십만 건의 읽기 요청을 발생시켜 DB가 감당할 수 없는 수준의 부하를 줍니다. * **로컬 캐싱의 트레이드오프**: 각 컨테이너에 데이터를 캐싱하고 일정 시간마다 갱신하는 방식은 DB 부하를 줄일 수 있지만, 캐시 만료 시간만큼 설정 반영이 늦어져 사용자 경험을 저해합니다. 캐시 기간을 늘릴수록 지연은 심해지고, 줄일수록 DB 부하는 급증하는 딜레마가 발생합니다. ### V1 아키텍처: Kafka 기반 캐시 무효화 * **작동 원리**: 사용자가 설정을 변경하면 DB에 저장된 후 Kafka를 통해 무효화 알림(invalidation message)이 브로드캐스트됩니다. 이를 수신한 모든 워크로드 컨테이너는 해당 테넌트의 데이터만 DB에서 다시 읽어와 캐시를 갱신합니다. * **장점**: 수년간 잘 작동했으며, 평상시 DB 읽기 횟수를 최소화하면서도 설정 변경 시에만 신속하게 업데이트를 수행할 수 있었습니다. * **확장성 한계**: 데이터독의 규모가 커짐에 따라 한 번의 설정 변경이 수천 개의 컨테이너에서 동시에 DB 조회를 일으키는 '천둥 벌거숭이(thundering herd)' 문제를 야기했습니다. 이는 중앙 DB에 막대한 부하를 주며, DB 장애 시 설정 전파가 완전히 중단되는 취약점을 드러냈습니다. 사용자 설정 변경이 실시간으로 반영되어야 하는 대규모 분산 시스템에서는 중앙 집중식 데이터베이스에 직접 의존하는 구조를 탈피해야 합니다. 워크로드 컨테이너가 DB에 직접 접근하여 데이터를 가져오는 대신, 변경 사항을 안정적으로 밀어넣어 주거나 중간에 완충 역할을 하는 계층을 두어 DB 부하를 격리하고 시스템 전체의 복원력을 높이는 설계가 권장됩니다.

figma원문

며칠의 지연 시간에서 실 (새 탭에서 열림)

피그마(Figma)는 급격한 사용자 증가와 데이터 볼륨 확대에 대응하기 위해 기존의 배치 기반 동기화 시스템을 실시간 증분 동기화(Incremental Synchronization) 파이프라인으로 전면 재구축했습니다. 과거 수일이 소요되던 데이터 동기화 지연 시간을 근실시간(Near Real-time) 수준으로 단축함으로써 데이터 분석의 신속성과 정확성을 확보했습니다. 이 과정에서 상용 솔루션 대신 자체 인프라에 최적화된 기술 스택을 선택하여 비용 절감과 확장성이라는 두 마리 토끼를 잡는 데 성공했습니다. **기존 배치 동기화 방식의 한계와 비용 문제** * 2020년에 설계된 초기 시스템은 매일 전체 테이블을 `SELECT *` 쿼리로 조회하여 S3에 업로드하고 Snowflake로 가져오는 단순한 구조였습니다. * 데이터 규모가 커짐에 따라 동기화 작업이 6시간에서 길게는 수일까지 지연되었으며, 이를 처리하기 위해 고가의 데이터베이스 복제본을 유지하는 데 매년 수백만 달러의 비용이 발생했습니다. * 동기화 지연은 전사 KPI 분석 및 비즈니스 의사결정을 방해하는 핵심 병목 구간이 되었습니다. **상용 솔루션 대신 자체 구축을 선택한 이유** * **유연성:** Amazon RDS와 같은 특정 클라우드 벤더의 API를 활용해 복제본 유지 관리 오버헤드 없이 직접 스냅샷을 생성하는 등 인프라 최적화가 필요했습니다. * **비용 효율성:** 대규모 데이터 환경에서 상용 솔루션을 사용할 경우 자체 구축 대비 약 5~10배 이상의 비용이 발생할 것으로 예상되었습니다. * **확장성:** 피그마의 지속적인 성장에 맞춰 빠르게 혁신하고 제어할 수 있는 맞춤형 파이프라인이 필요했습니다. **증분 동기화를 위한 기술적 아키텍처** * **스냅샷 및 데이터 적재:** Amazon RDS의 스냅샷 내보내기 기능을 사용해 S3로 초기 데이터를 복사하고, Snowflake의 `COPY INTO` 문을 통해 베이스 테이블에 로드합니다. * **CDC(Change Data Capture) 스트리밍:** Kafka Connect를 활용해 Postgres의 변경 로그를 실시간으로 캡처하고, Amazon MSK를 거쳐 Snowflake의 CDC 테이블로 스트리밍합니다. * **증분 병합(Merge):** Snowflake의 저장 프로시저(Stored Procedure)와 태스크(Task) 기능을 이용해 베이스 테이블과 CDC 데이터를 주기적으로 병합하는 맞춤형 `MERGE` 로직을 구현했습니다. **데이터 무결성을 위한 워크플로우 설계** * **부트스트랩(Bootstrap):** 새로운 테이블을 파이프라인에 추가할 때 스키마 진화에 대응할 수 있도록 아티팩트를 버전화하고, 원자적 뷰(View) 업데이트를 통해 서비스 중단 없는 전환을 지원합니다. * **검증(Validation):** 부분적 실패, 설정 오류, 소스 데이터의 이상 현상으로 인한 데이터 부패를 방지하기 위해 파이프라인 전 과정에서 데이터의 정확성과 일관성을 검증하는 프로세스를 통합했습니다. 데이터 파이프라인의 성능 한계에 직면한 조직은 단순히 컴퓨팅 파워를 늘리기보다, 전체 데이터를 옮기지 않는 '증분 동기화'와 자사 환경에 최적화된 CDC 기술 스택을 도입함으로써 비용과 성능 문제를 근본적으로 해결할 수 있습니다. 특히 대규모 환경에서는 벤더 종속성을 탈피한 자체 아키텍처 설계가 장기적인 확장성 면에서 더 유리할 수 있습니다.