Flink + RocksDB 튜닝으로 광고 집계 시스템 성능 UP!

by DD
1개월 전
조회수 40

광고 노출 횟수 집계 시스템을 Flink 기반으로 확장하여 1분부터 7일까지의 실시간 집계(Real-time Aggregation)를 지원

기존 Airflow 기반 배치 시스템의 유지보수 복잡성(Maintenance Complexity)서빙 레이어(Serving Layer) 병목 문제를 해결

RocksDB 튜닝을 통해 Write Stall, Filter Block Cache Miss, Checkpoint I/O 등 각 앱별 병목 현상(Bottleneck)을 개선

초기 적재와 전환 정합성을 위해 백필(Backfill)과 캐치업(Catch-up) 파이프라인 분리 및 Event Time 기반 쓰기 조건 적용

Flink Changelog(DSTL) 도입 및 Native Savepoint 교착 문제 해결을 통해 Checkpoint I/O 성능 향상을 달성

Kryo에서 POJO로의 직렬화 방식 변경, State 키 구조 단순화를 통해 성능 개선(Performance Improvement)Block Cache 효율 증대

Frequency Capping 시스템의 아키텍처 변화

본문에서는 기존 Airflow 기반 배치 시스템에서 Flink 기반 실시간 집계 시스템으로의 전환 과정을 설명한다. 기존 시스템은 Head, Mid, Tail 세 계층으로 구성되어, 서빙 시점에 여러 번의 Redis 조회가 필요했다. Flink 기반 시스템은 1분~7일 슬라이딩 구간을 단일 Redis 조회로 제공하며, 데이터 격리 아키텍처(Data Isolation Architecture)를 통해 재처리 시에도 정확한 집계를 보장한다. 특히, 3개의 Flink 앱(minutes/hours/days) 분리를 통해 각 구간별 병목 현상에 효과적으로 대응했다. 이러한 아키텍처 변화는 유지보수성(Maintainability)성능(Performance) 향상에 기여했다.

초기 적재와 전환 정합성 확보 방안

실시간 전환 과정에서 가장 중요한 문제는 초기 데이터 적재와 실시간 집계 간의 정합성 확보였다. 이를 위해 백필(Backfill)과 캐치업(Catch-up) 파이프라인을 분리하는 2단계 구조를 설계했다. 백필 파이프라인은 과거 데이터를 초기화하고, 캐치업 파이프라인은 실시간 이벤트를 처리한다. 두 파이프라인의 경계에서 Redis 쓰기 조건, withIdleness 설정, timerState TTL 설정을 통해 정합성을 유지했다. 특히, withIdleness 설정을 통해 파티션의 Idle 상태를 감지하고, timerState TTL을 슬라이딩 윈도우 만료 시간보다 길게 설정하여 데이터 손실을 방지했다.

RocksDB 튜닝을 통한 성능 개선

각 Flink 앱(minutes/hours/days)의 병목 현상에 따라 RocksDB 설정을 다르게 튜닝했다. minutes 앱에서는 Write Buffer Manager(WBM) 압박으로 인한 Write Stall을 해결하기 위해 managed 메모리 및 WBR(Write Buffer Ratio)을 조정했다. hours 앱에서는 Filter Block Cache Miss를 해결하기 위해 partitioned-index-filters=true를 적용하고, target-file-size-base 및 max-size-level-base 설정을 변경하여 레벨 최적화를 수행했다. days 앱에서는 대규모 State로 인한 Checkpoint I/O 병목을 해결하기 위해 use-dynamic-size 및 target-file-size-base 튜닝을 진행했다. 이러한 튜닝을 통해 전반적인 시스템 성능(System Performance)을 향상시켰다.

Flink TM 메모리 구조 최적화

Flink TaskManager(TM) 메모리 구조를 정밀하게 조정하여 성능을 개선했다. Grafana의 Flink 메모리 지표를 기반으로 task heap, managed memory, network buffer 등의 설정을 조정했다. network.fraction을 0.01로 제한하고, G1PeriodicGC 설정을 통해 불필요한 메모리 점유를 방지했다. 또한, K8s limit을 고려하여 메모리 사용량을 최적화했다. 이러한 메모리 튜닝은 자원 효율성(Resource Efficiency)을 높이고, 안정적인 시스템 운영(Stable System Operation)을 가능하게 했다.

Flink Changelog(DSTL) 도입과 Savepoint 교착 문제 해결

days 앱의 Checkpoint I/O 병목을 해결하기 위해 Flink Changelog(DSTL, Distributed State Transaction Log)를 도입했다. DSTL은 State 변경분을 즉시 로깅하여 Checkpoint 시 변경분만 업로드하도록 하여, Compaction으로 인한 업로드량 증가 문제를 해결했다. 또한, Native Savepoint와 Changelog를 함께 사용할 때 발생하는 교착 문제를 CANONICAL Savepoint로 전환하여 해결했다. 이러한 조치를 통해 Checkpoint 성능(Checkpoint Performance)을 향상시키고, 안정적인 Savepoint(Stable Savepoint)를 보장했다.

직렬화 방식 변경 및 State 구조 단순화

Kryo에서 POJO로의 직렬화 방식 변경을 통해 CPU 사용량을 약 20%에서 12%로 감소시켰다. 또한, MapState>> 형태의 중첩 구조를 MapState로 단순화하여 직렬화 부하를 줄였다. 이러한 변경은 Block Cache 수용량 증가, Changelog I/O 감소, Checkpoint 크기 감소 등의 부가적인 효과를 가져왔다. 결과적으로 전반적인 시스템 성능(Overall System Performance)을 향상시키고, 자원 사용량(Resource Usage)을 최적화했다.

Apache Flink + RocksDB 튜닝으로 광고 Frequency Capping 실시간 집계를 일주일까지 확장하기