Cassandra 광범위 파티션 문제, Netflix의 동적 분할로 해결!
Netflix는 대규모 시계열 데이터(Time Series Data) 처리를 위해 Apache Cassandra 4.x를 사용하나, 광범위한 파티션(Wide Partitions) 문제로 성능 저하 발생
기존 파티션 전략의 한계(워크로드 예측 불가, 변화하는 트래픽)를 극복하기 위한 자동화된 솔루션 모색
시간 슬라이스 단위 재파티셔닝으로 테이블 전체 성능 개선 시도, 개별 ID 단위 동적 파티셔닝으로 특정 데이터셋의 문제 해결
동적 파티셔닝 도입 후 평균 읽기 지연 시간(Read Latency) 수 초에서 수 밀리초로 감소 및 타임아웃 현상 대폭 완화
광범위 파티션(Wide Partitions)의 근본 원인과 영향
시계열 데이터는 시간이 지남에 따라 이벤트가 누적되어 Cassandra 파티션 크기(Partition Size)가 비대해지는 경향이 있음. 이는 수백만 건의 읽기/쓰기 작업이 발생하는 시계열 워크로드에서 특히 두드러짐.
높은 읽기 지연 시간(High Read Latency): 파티션이 커질수록 특정 데이터 접근 시 수 초 단위의 지연 발생 가능
타임아웃(Timeouts) 및 시스템 불안정: 과도한 지연은 Garbage Collection(GC) 일시 중지, CPU 사용량 급증, 스레드 큐잉(Thread Queueing) 유발
단순 스케일 업(Scale-up)의 한계: 비용 증가 대비 근본적인 해결책이 되지 못하며, 더 스마트한 대안 필요성 대두됨.
시간 슬라이스(Time Slice) 단위 재파티셔닝 전략
기존 시계열 추상화 시스템은 데이터를 시간 청크(Time Chunk)로 분할하여 광범위 파티션 문제를 완화함. 각 시간 슬라이스(Time Slice)는 고유한 파티셔닝 전략을 가질 수 있음.
자동화된 워커(Background Worker): `nodetool tablehistograms` API를 활용하여 파티션 크기 분포 모니터링.
구성 가능한 밀도(Configured Density): 파티션 크기가 목표 범위(예: 2MB~10MB)를 벗어날 경우, 새로운 시간 슬라이스에 대한 파티셔닝 전략 조정 (예: `time_bucket` 간격 확장).
한계점: 개별 ID 단위의 비정상적인 데이터 증가에는 효과적이지 않으며, 테이블 전체에 적용되는 방식임.
개별 ID 단위 동적 파티셔닝 파이프라인
이 파이프라인은 개별 시계열 ID 수준에서 광범위 파티션을 감지하고 비동기적으로 분할하는 방식임.
탐지(Detection): 읽기 경로에서 설정된 임계값 초과 시 Kafka로 이벤트 발행하여 광범위 파티션 감지.
계획 및 분할(Planning & Splitting): 전체 파티션을 읽어 분할 계획 수립 후, 체크섬(Checksum) 검증을 통해 데이터 무결성 보장하며 비동기적으로 분할 실행.
읽기 서빙(Serving Reads): 완료된 분할 파티션 정보를 Bloom 필터에 로드하여 읽기 요청을 투명하게 리디렉션.
불변성(Immutability) 우선: 복잡성을 줄이기 위해 초기에는 변경 불가능한(Immutable) 파티션에 집중하여 구현함.
동적 파티셔닝의 구현 세부 사항
파이프라인은 상태 전이 및 체크포인팅을 위해 `wide_row` 메타데이터 테이블을 활용함. 이 테이블은 분할 상태와 향후 읽기 요청 라우팅에 필요한 정보를 저장함.
계획(Planning): 부분 읽기 실패 시 체크포인트부터 재개 가능하도록 설계됨.
분할(Splitting): `EventBucketPartitionSplitStrategy` 등 다양한 분할 전략을 적용하여 이벤트 버킷 수를 조정하거나, 초광폭 파티션의 경우 여러 Cassandra 복제본으로 분산.
읽기 경로(Read Path): Bloom 필터 히트 시 `wide_row` 메타데이터를 조회하여 분할된 파티션에서 데이터를 읽도록 위임.
메타데이터 캐싱: 읽기 성능 저하를 최소화하기 위해 메타데이터 조회는 읽기 스루 캐시(Read-through Cache)로 지원됨.
신뢰성 확보 및 단계적 롤아웃 전략
데이터 무결성 및 시스템 안정성 확보를 위해 다층적인 검증 메커니즘을 적용함.
오프라인 검증: Spark 작업을 활용하여 분할된 데이터가 원본 데이터와 일치하는지 검증.
단계적 롤아웃(Phased Rollout): Shadow 모드에서 기존 읽기 경로와 새 경로의 응답을 비교하며 점진적으로 새 기능 활성화.
비교 단계(Comparison Phase): 바이트 단위 비교(Byte-level Comparison)를 통해 두 경로 간 데이터 불일치 여부 확인.
안전한 폴백(Fallback): 원본 광범위 파티션은 삭제하지 않아 부분 실패 시 복구 메커니즘으로 활용, 운영 안정성 강화.
동적 파티셔닝 도입 후 성능 개선 결과
동적 파티셔닝 도입으로 광범위 파티션의 평균 읽기 지연 시간이 수 초에서 낮은 두 자릿수 밀리초로 크게 개선됨.
꼬리 지연 시간(Tail Latency): 수 초에서 약 200ms 이하로 감소하여 사용자 경험 향상.
읽기 타임아웃(Read Timeouts) 감소: 시스템 가용성 및 안정성 증대.
대용량 파티션 처리: 500MB 이상의 파티션도 페이지네이션(Pagination)을 통해 안정적으로 조회 가능해짐.
운영 부담 감소: 지원 요청 감소 및 전반적인 서비스 성능 향상에 기여함.