apache-flink

6 개의 포스트

Apache Flink + RocksDB 튜닝으로 광고 Frequency Capping 실시간 집계를 일주일까지 확장하기 (새 탭에서 열림)

토스 데이터 서비스 플랫폼 팀은 광고 노출 집계의 정확성을 높이고 서빙 효율을 개선하기 위해, 기존 Airflow 배치와 Flink 스트리밍이 혼재된 시스템을 전면 Flink 기반의 실시간 슬라이딩 집계 시스템으로 전환했습니다. 1분부터 7일까지의 광범위한 집계 구간을 단일 Redis 조회로 제공하기 위해 집계 특성별로 Flink 앱을 분리하고, RocksDB 및 런타임 설정을 최적화하여 비즈니스 오차를 최소화했습니다. 이 과정에서 대규모 상태(State) 관리와 초기 데이터 적재의 정합성 문제를 해결하며 운영 신뢰성을 확보했습니다. ### 광고 노출 제어(Frequency Capping)의 중요성 * 광고주 예산 낭비를 막고 노출 기회 손실을 방지하기 위해 사용자별 광고 노출 횟수를 정확하게 카운트하고 제어하는 메커니즘입니다. * 광고 상품에 따라 '하루 3회', '7일간 1회' 등 집계 구간이 다양하므로, 1분부터 7일까지의 모든 구간에 대해 이벤트 단위의 정밀한 슬라이딩 윈도우 집계가 필요합니다. ### 기존 시스템의 한계와 개선 동기 * 기존에는 Airflow를 이용해 당일(Head), 과거(Mid), 경계 보정(Tail)의 3단계로 나누어 처리하는 배치 구조를 사용했으나, 유지보수해야 할 DAG가 너무 많고 구조가 복잡했습니다. * 서빙 시점에 구간별로 Redis를 최대 4회 조회해야 하는 구조적 번거로움이 있었으며, 실시간으로 변하는 슬라이딩 윈도우를 정밀하게 구현하는 데 한계가 있었습니다. ### 병목 패턴에 따른 앱 분리 및 아키텍처 * 집계 구간별 병목 현상이 다르다는 점에 착안하여 시스템을 **Minutes**(1~30분), **Hours**(최대 12시간), **Days**(최대 7일)의 3개 앱으로 분리했습니다. * **Minutes**: 빈번한 만료 처리로 인한 Write Stall이 주요 병목이며, RocksDB Write 경로 튜닝이 핵심입니다. * **Hours**: 대량의 광고 ID 누적으로 인한 Filter Block Cache Miss와 CPU 포화가 발생하여 Managed Memory 증설이 필요합니다. * **Days**: Savepoint가 230GB에 달하는 대규모 상태가 병목이며, Checkpoint I/O 문제를 해결하기 위해 Changelog State Backend를 활용합니다. * Flink State를 '단일 진실 공급원(SSOT)'으로 삼아, 장애 발생 시에도 Redis를 State로부터 언제든 다시 구성할 수 있도록 설계했습니다. ### 초기 적재와 전환 정합성 확보 * 7일치의 과거 데이터를 채우는 과정에서 '백필(카운트만 수행)'과 '캐치업(카운트와 만료 타이머 함께 등록)' 파이프라인을 분리하는 2단계 구조를 설계했습니다. * 백필 도중 만료 타이머가 미리 발화하여 집계가 틀어지는 문제를 방지하기 위해, 백필 완료 후 특정 시점부터만 Redis에 쓰기가 수행되도록 제어했습니다. * `withIdleness` 설정을 통해 특정 파티션의 지연이 전체 Watermark 진행을 막지 않도록 하고, `timerState`의 TTL을 윈도우보다 길게 설정해 지연 상황에서도 감소 로직이 누락되지 않도록 보장했습니다. ### RocksDB와 런타임 최적화 * **Minutes 앱**: Write Buffer Manager(WBM) 압박을 완화하여 RocksDB가 쓰기를 멈추는 Write Stall 현상을 방지했습니다. * **Hours 앱**: Bloom Filter 및 메모리 설정을 통해 캐시 미스를 줄여 CPU 효율을 높였습니다. * **Days 앱**: 거대한 SST 파일로 인한 체크포인트 부하를 줄이기 위해 레벨 최적화와 Changelog 메커니즘을 적용했습니다. 대규모 데이터를 다루는 실시간 집계 시스템에서는 모든 구간을 하나의 설정으로 처리하기보다, 데이터의 규모와 병목 지점에 따라 앱을 분리하고 각기 다른 RocksDB 튜닝 전략을 적용하는 것이 운영 안정성 측면에서 효과적입니다. 또한, 상태(State)를 시스템의 최상위 데이터 원천으로 관리하는 원칙을 지킬 때 장애 복구와 데이터 정합성 유지가 훨씬 용이해집니다.

Hive에서 Iceberg로: 데이터 반영 속도 12배 향상의 비밀 (새 탭에서 열림)

LINE Plus는 수억 건에 달하는 상품 데이터를 처리하기 위해 기존에 사용하던 전체 데이터 복제(Full Dump) 방식의 ETL 구조를 탈피하고, Apache Iceberg와 Apache Flink를 결합한 증분(Incremental) 처리 구조를 도입했습니다. 이를 통해 데이터 규모가 커질수록 기하급수적으로 늘어나던 업데이트 비용과 시간을 대폭 절감하였으며, 결과적으로 데이터 반영 주기를 60분에서 5분으로 단축하여 약 12배의 성능 향상을 이루어냈습니다. 이 글은 대규모 데이터 환경에서 실시간성에 가까운 데이터 최신성을 확보하기 위한 기술적 여정과 엔진 선택의 근거를 상세히 다룹니다. **기존 전체 데이터 복제 방식의 한계** * **리소스 낭비와 지연:** 매번 수억 건의 전체 데이터를 다시 써야 하는 구조로 인해 데이터 규모가 커질수록 처리 비용이 증가하고, 사내 Hadoop 리소스 부족 시 업데이트 주기가 지연되는 문제가 발생했습니다. * **데이터 최신성 결여:** 스냅숏 기반의 추출 방식은 정합성은 보장하지만, 추출 작업에 걸리는 시간만큼 데이터가 과거 시점에 머물게 되어 라이브 서비스에서의 실시간 대응이 어려웠습니다. * **운영 DB 부하:** 대용량 데이터를 한꺼번에 추출할 때 발생하는 막대한 디스크 I/O와 Undo 세그먼트 팽창은 운영 환경의 성능 저하를 유발하는 고질적인 원인이 되었습니다. **Apache Iceberg를 통한 증분 처리 기반 마련** * **테이블 형식의 변화:** 기존 Hive의 디렉터리 기반 관리 방식에서 벗어나, 메타데이터를 이용해 스냅숏 단위로 파일을 추적하는 Iceberg 형식을 도입했습니다. * **행 단위 업데이트 지원:** 전체 데이터를 다시 쓸 필요 없이 변경된 행(row)만 선택적으로 업데이트(upsert)하거나 삭제(delete)할 수 있어, 데이터 규모와 상관없이 일정한 업데이트 비용을 유지할 수 있게 되었습니다. **Apache Flink 선택의 결정적 이유** * **스테이트풀(Stateful) 처리를 통한 최신성 보장:** Flink의 DataStream API를 활용해 `updatedate`를 상태값으로 관리함으로써, 컨슈머 랙 등으로 인해 뒤늦게 도착한 과거 데이터가 최신 데이터를 덮어쓰는 문제를 원천 차단했습니다. * **2단계 커밋(2PC) 기반의 정확히 한 번 처리:** Iceberg 테이블 쓰기와 Kafka 상태 메시지 발행을 하나의 트랜잭션으로 묶어, 데이터 누락이나 중복 없이 '전부 아니면 전무(All-or-Nothing)'의 정합성을 보장했습니다. * **강력한 장애 허용(Fault Tolerance):** 체크포인트 메커니즘을 통해 시스템 장애 발생 시에도 마지막 성공 지점부터 즉시 복구가 가능하며, 관리하던 상태값을 유실 없이 유지할 수 있습니다. **효율적인 운영을 위한 쿠버네티스 오퍼레이터 도입** * **운영 자동화:** 설정 작업을 수동으로 진행해야 하는 네이티브 쿠버네티스 방식 대신, Flink 쿠버네티스 오퍼레이터를 도입하여 라우팅, 웹 UI 구성 등 운영 요소를 커스텀 리소스로 추상화하고 관리를 자동화했습니다. * **격리 및 확장성:** 애플리케이션 모드를 통해 잡(job)별 클러스터 격리 수준을 높이고, 헬름(Helm) 차트를 이용해 손쉽게 배포 및 확장할 수 있는 환경을 구축했습니다. 대규모 데이터셋에서 실시간에 가까운 데이터 동기화와 엄격한 정합성이 모두 필요하다면, 단순한 배치 처리보다는 Flink와 Iceberg의 조합을 통한 증분 파이프라인 구축을 권장합니다. 특히 Flink의 2단계 커밋과 체크포인트 기능을 활용하면 분산 환경에서도 데이터 무결성을 보장하면서 시스템의 업데이트 주기를 획기적으로 단축할 수 있습니다.

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 전략을 사용하고, 쓰기 병목을 해소하기 위해 기본 키 기반의 버킷팅을 적용하는 것이 실무적으로 매우 효과적인 접근임을 보여줍니다.

매번 다 퍼올 필요 없잖아? 당근의 MongoDB CDC 구축기 (새 탭에서 열림)

당근은 서비스 성장에 따른 데이터 규모 확대와 이로 인한 MongoDB 부하 문제를 해결하기 위해 기존의 전체 덤프 방식 대신 Flink CDC를 도입했습니다. 이를 통해 DB 부하를 60% 이하로 안정화하면서도 2시간 이내 데이터 전달이라는 SLO(Service Level Objective)를 충족하는 성과를 거두었습니다. 결과적으로 확장성 있는 파이프라인을 구축하여 서비스 안정성과 데이터 분석 효율성을 동시에 확보했습니다. **기존 방식의 한계와 CDC 도입 배경** * **성능적 한계:** 기존에는 Spark Connector를 사용해 전체 데이터를 덤프했으나, 데이터가 늘어날수록 DB CPU 사용률이 급증(Spike)하고 적재 시간이 길어지는 문제가 발생했습니다. * **안정성 문제:** 2시간 내 데이터 적재라는 목표를 맞추려면 DB 부하가 너무 커지고, 부하를 줄이면 적재 시간이 지연되는 트레이드오프 상황에 직면했습니다. * **CDC의 필요성:** `updated_at` 같은 특정 필드에 의존하는 증분 적재 방식은 스키마 변경이나 누락에 취약하므로, DB의 변경 로그(Oplog)를 직접 읽어 변경분을 추적하는 CDC 방식이 최적의 대안으로 선정되었습니다. **Flink CDC를 최종 선택한 기술적 이유** * **Change Stream 네이티브 지원:** MongoDB의 Change Stream 기능을 활용해 변경 로그를 안정적으로 읽어오며, resume token과 체크포인트를 연동하여 장애 발생 시에도 중단된 지점부터 정확히 재개할 수 있습니다. * **정확히 한 번(Exactly-Once) 보장:** 강력한 체크포인트 메커니즘을 통해 상태를 외부 스토리지(GCS/S3 등)에 보존하므로 데이터 중복이나 누락 없는 처리가 가능합니다. * **통합 파이프라인 구성:** CDC 데이터 추출부터 변환(Transform), 적재(Sink)까지 하나의 Job 내에서 엔드투엔드(End-to-End)로 처리할 수 있어 운영 복잡도가 낮습니다. * **병렬 처리 기반의 확장성:** TaskManager를 늘림으로써 처리량을 선형적으로 확장할 수 있어, 이벤트가 급증하는 상황에도 유연하게 대응할 수 있습니다. **CDC 기반 데이터 파이프라인 아키텍처** * **실시간 구독 및 적재:** MongoDB에서 발생하는 모든 변경 이벤트(insert, update, delete)를 Flink CDC가 실시간으로 수집하여 BigQuery로 전송합니다. * **효율적인 배치 전략:** 실시간 스트리밍 대신 1시간 단위(Hourly) 배치 방식을 채택하여 시스템 복잡도를 낮추고, 장애 시 재처리의 용이성과 멱등성을 확보했습니다. * **단계별 후처리 프로세스:** 1. **Schema Evolution:** 스키마 저장소와 비교하여 BigQuery 테이블의 필드를 자동 업데이트합니다. 2. **Extract & Merge:** 최신 변경 이벤트를 추출해 중복을 제거하고 원본 형태의 Raw 테이블에 병합합니다. 3. **Materialize:** 최종적으로 스키마를 적용해 분석에 최적화된 테이블로 구체화합니다. 대규모 트래픽 환경에서 운영 DB의 부하를 최소화하면서 데이터 가용성을 높이려면, 무조건적인 전체 조회보다는 CDC를 통한 변경분 추적 방식이 필수적입니다. 특히 데이터 모델 변환이 잦은 NoSQL 환경이라면 Flink CDC와 같은 통합 도구를 활용해 파이프라인을 단순화하고, 서비스의 SLO에 맞춰 배치와 스트리밍 중 적절한 주기를 선택하는 것이 운영 안정성 측면에서 권장됩니다.

매번 다 퍼올 필요 없잖아? 당근의 MongoDB CDC 구축기 (새 탭에서 열림)

당근 데이터 가치화 팀은 서비스 성장에 따른 데이터 규모 증가로 기존 MongoDB 전체 덤프 방식이 유발하던 DB 부하와 데이터 적재 지연 문제를 해결하기 위해 Flink CDC를 도입했습니다. 이를 통해 전체 데이터를 매번 조회하지 않고 변경된 로그만 캡처하여 BigQuery로 적재함으로써 DB CPU 부하를 60% 이하로 안정화하고, 2시간 이내 데이터 전달이라는 서비스 수준 목표(SLO)를 달성했습니다. 결과적으로 운영 효율성과 데이터 분석의 실시간성을 동시에 확보하는 파이프라인을 구축할 수 있었습니다. **기술 스택 선정: 왜 Flink CDC인가?** * **MongoDB Change Stream 네이티브 지원**: 별도의 커넥터 개발 없이 MongoDB의 고수준 변경 이벤트 API인 Change Stream을 안정적으로 구독할 수 있으며, resume token과 Flink의 체크포인트 기능을 연동해 장애 시에도 정확한 시점부터 재시작이 가능합니다. * **Exactly-Once 처리 보장**: 분산 파일 시스템에 상태를 주기적으로 저장하는 체크포인트 전략을 통해 장애가 발생하더라도 데이터 중복이나 누락 없이 '정확히 한 번' 처리를 보장합니다. * **통합 파이프라인 구축**: 변경 데이터 추출(CDC)부터 데이터 정제, 변환, BigQuery로의 적재(Sink)까지 하나의 Job 안에서 End-to-End로 처리할 수 있어 운영 복잡도가 낮습니다. * **병렬 처리 기반의 확장성**: TaskManager를 늘려 처리량을 선형적으로 확장할 수 있어, 데이터 이벤트가 폭증하는 상황에서도 유연하게 대응할 수 있습니다. **CDC 기반 아키텍처 및 데이터 흐름** * **Change Stream 활용**: MongoDB의 모든 쓰기 연산을 기록하는 Oplog를 Change Stream을 통해 실시간으로 구독하여 insert, update, delete 이벤트를 수신합니다. * **단계별 배치 파이프라인**: 2시간 이내의 SLO 충족과 운영 안정성을 위해 실시간 스트리밍 대신 매시간(hourly) 배치 방식을 채택했습니다. * **Schema Evolution**: 스키마 저장소와 BigQuery 테이블을 비교하여 변경된 필드를 자동으로 반영합니다. * **Extract & Merge**: 최근 변경 이벤트에서 중복을 제거하고 추출하여 JSON 형태의 Raw 테이블에 병합합니다. * **Materialize**: 최종적으로 스키마를 적용해 사용자가 분석하기 쉬운 테이블 형태로 구체화합니다. * **배치 방식의 이점**: 시간 윈도우를 통해 지연된 이벤트를 안정적으로 회수할 수 있고, 장애 발생 시 실패 구간을 명확히 정의해 재처리(Backfill)하기가 용이합니다. **실용적인 결론** 대규모 트래픽이 발생하는 서비스 환경에서 운영 데이터베이스의 부하를 최소화하면서 분석용 데이터를 확보하려면 CDC 도입이 필수적입니다. 특히 MongoDB와 같이 스키마가 유연한 NoSQL 데이터를 BigQuery와 같은 정형 데이터 저장소로 옮길 때는, Flink CDC와 같은 통합 처리 엔진을 활용해 변환 로직과 확장성을 동시에 확보하는 것이 운영 효율 측면에서 매우 유리합니다. 실시간성이 극도로 중요하지 않다면 배치 단계를 결합해 데이터 정합성과 멱등성을 보장하는 구조를 고려해볼 수 있습니다.

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의 사례처럼, 도구의 장점을 극대화하면서도 유지보수성을 놓치지 않는 아키텍처 설계가 대규모 금융 플랫폼의 안정성을 뒷받침합니다.