Cassandra는 읽기 성능을 어떻게 높였는가 [2026.03.06]
사내에서 Cassandra를 검토하고 도입하는 과정이 있었다. 평소에는 MySQL과 Redis를 주로 사용해왔기 때문에, 처음 Cassandra를 보았을 때 가장 궁금했던 것은 “이 데이터베이스는 내가 익숙한 저장소들과 정확히 무엇이 다를까?”였다.
MySQL InnoDB는 기본적으로 B-Tree와 clustered index를 중심으로 데이터를 저장하고, Redis는 이름 그대로 in-memory data store라는 성격이 아주 분명하다. 반면 Cassandra는 저장 엔진이 LSM Tree(Log-Structured Merge Tree) 를 기반으로 동작하고, 쓰기를 “바로 수정”하기보다 “먼저 쌓아두고 나중에 정리”하는 방향으로 설계되어 있다.
조금 더 들여다보니 Cassandra의 핵심은 단순히 “NoSQL”이라는 분류에 있지 않았다. 오히려 왜 쓰기는 빠르고, 왜 읽기는 상대적으로 복잡하며, 왜 삭제조차 즉시 지우지 않고 나중에 정리하는가를 이해해야 전체 그림이 보였다. 이 글에서는 그중에서도 저장 엔진의 핵심 흐름인 쓰기 경로, Compaction, 읽기 경로를 중심으로 Cassandra를 정리해보려 한다.
Cassandra는 처음부터 대규모 데이터, 여러 노드에 걸친 복제, 높은 가용성, 수평 확장을 전제로 설계된 저장소다. 공식 문서는 Cassandra가 전 세계 규모의 복제와 항상 가능한 저지연 읽기/쓰기를 요구하는 환경에서, 당시의 관계형 시스템이 감당하기 어려웠던 문제를 해결하기 위해 이런 구조를 택했다고 설명한다. 데이터는 partition key를 기준으로 여러 노드에 분산 저장되며, 같은 파티션은 설정된 replication factor에 따라 여러 물리 노드에 복제된다. 이때 각 replica 노드는 전달받은 쓰기 요청을 자신의 로컬 저장 엔진에서 처리한다.
이 선택은 자연스럽게 CAP 관점의 성격도 만든다. Cassandra는 네트워크 분할 상황에서도 계속 동작하는 Availability + Partition Tolerance 쪽에 무게를 두고, 그 대가로 일부 상황에서는 즉시 강한 일관성보다 eventual consistency 를 택한다. 대신 replica, timestamp, repair, tombstone 같은 메커니즘을 통해 결국 일관된 상태로 수렴하도록 만든다.
익숙한 MySQL 관점에서 보면, 데이터는 보통 인덱스 페이지 안에 정돈된 구조로 놓여 있고, 어떤 값을 바꾼다는 것은 결국 그 구조 어딘가를 찾아가 수정하는 일에 가깝다. Redis는 그보다 더 직접적이다. 메모리에 있는 값을 바로 읽고 쓰는 것에 강하다. Cassandra는 이 둘과 다르게, 쓰기 시점에는 최대한 단순하게 append 하고, 나중에 백그라운드에서 여러 파일을 합쳐 정리한다. 즉, “지금 당장 예쁘게 정리된 상태로 쓰기”보다 “빨리 받아 적고 나중에 정리하기”에 가깝다.