랄프 월도 에머슨(Ralph Waldo Emerson)의 말처럼 '어리석은 일관성은 좁은 마음의 산물'일지 모르지만, 확장 가능하고 성공적인 엔터프라이즈급 캐싱 전략을 구현하는 데 있어 일관성은 결코 어리석은 것이 아닙니다. 오히려 엔터프라이즈 데이터베이스 운영 관리에서 가장 큰 난제 중 하나가 바로 캐시 일관성 유지입니다.
그렇다면 애초에 왜 캐시를 사용할까요? 엔터프라이즈 캐시의 가장 큰 장점은 데이터를 빠르고 효율적으로 접근할 수 있다는 점입니다. 기본(primary) 데이터베이스에 직접 호출하면 시간과 처리 자원 모두에서 상당한 비용이 발생하지만, 캐시 호출은 번개처럼 빠르며 기본 데이터베이스에는 아무런 부담을 주지 않습니다.
캐시 일관성을 위협하는 세 가지 장애물
물론 이러한 장점은 캐시의 데이터가 원본 데이터와 항상 동일한 값을 유지한다는 전제 위에 성립합니다. 단순해 보이는 목표지만, 이론만큼 실전은 쉽지 않습니다. 실제로 다음 세 가지 함정이 일관성을 무너뜨릴 수 있습니다.
1. 기본 데이터베이스의 변경 사항이 캐시에 반영되지 않을 때
캐시를 통한 데이터 접근은 정의상 기본 데이터베이스보다 빠르기 때문에, 특정 항목이 요청되면 시스템은 먼저 캐시를 확인합니다. 해당 항목이 캐시에 존재한다면 기본 데이터베이스보다 훨씬 빠르게 결과를 반환할 수 있습니다. 이 전략을 캐시 어사이드(cache-aside) 패턴이라고 부릅니다. 기본적으로 캐시를 먼저 조회하고, 데이터가 없으면 애플리케이션이 기본 데이터베이스를 질의한 뒤 그 결과를 사용자에게 전달하는 경로에 캐시에 함께 저장합니다.
문제는 기본 데이터베이스의 데이터가 변경된 시점과 캐시가 그 변경을 반영하는 시점 사이의 간격(gap)에서 발생합니다. 이 간격은 애플리케이션이 캐시를 확인하는 빈도에 따라 달라지는데, 확인 작업 자체가 프로세서 자원을 소모합니다. 같은 프로세서는 캐시 업데이트만큼 중요한, 혹은 그 이상으로 중요한 수많은 다른 기능과 트랜잭션을 동시에 처리하고 있기 때문입니다.
결국 과제는 업데이트를 너무 자주 확인하는 것과 너무 드물게 확인하는 것 사이의 적절한 균형점, 일종의 '골디락스 영역'을 찾는 것입니다. 물론 사용자가 이 간격 동안 오래된 데이터에 접근한다면 그 균형은 깨지고 말습니다.

2. 캐시된 결과의 업데이트가 지연될 때
이 문제는 앞선 문제와 다소 겹칩니다. 기본 데이터베이스의 값이 업데이트될 때마다 캐시에는 메시지가 전송되어, 변경된 값을 갱신하거나 아예 삭제하도록 지시합니다. 후자의 경우 해당 값이 다음에 요청될 때 기본 데이터베이스에서 읽어온 뒤 이후부터는 캐시에서 제공됩니다. 평소에는 이 통신이 비교적 신속하게 이루어져 캐시 항목이 갱신 또는 삭제되며 일관성이 유지됩니다.
그러나 이 역시 처리 능력과 시간이 필요합니다. 지연은 가용한 처리 속도와 네트워크 처리량(throughput)의 영향을 받습니다. 서버가 캐시 업데이트 메시지를 보낸 시점부터 캐시가 그 메시지를 수신해 실제로 반영하기까지의 사이에 사용자가 운 나쁘게 오래된 데이터에 접근한다면, 결과는 낡았거나 잘못된 데이터, 혹은 둘 다일 수 있습니다.
3. 캐시 노드 간에 불일치가 존재할 때
웹사이트나 애플리케이션의 규모가 커질수록 캐시는 하나의 노드가 아닌 여러 노드에 분산 저장되는 경우가 많습니다. 기본(primary) 노드 외에도 동일한 데이터를 저장하는 복제(replica) 노드가 여러 개 존재할 수 있으며, 로드 밸런싱과 성능 측면에서는 이것이 합리적인 선택입니다.
하지만 데이터 무결성 관점에서 보면 또 하나의 잠재적 불일치 원인이 됩니다. 기본 데이터베이스의 데이터가 업데이트될 때마다 이 변경 사항은 모든 복제본에도 반영되어야 합니다. 노드들의 지리적 위치와 개수에 따라 이 업데이트 과정은 상당한 시간이 걸릴 수 있습니다. 업데이트가 진행 중이라 하더라도, 사용자가 아직 변경이 반영되지 않은 노드에 접속할 가능성은 충분히 있습니다. 그리고 그 결과는, 짐작하시겠지만, 캐시 불일치입니다.
캐시 불일치가 가져오는 비용
캐시된 데이터베이스의 모든 장점에도 불구하고, 캐시 불일치 가능성은 가장 두드러진 약점입니다. 그렇다면 문제는 얼마나 클까요? 결론적으로 캐시 불일치의 비용은 맥락에 따라 달라집니다.
어떤 불일치는 큰 문제 없이 지나갈 수 있습니다. 예를 들어 캐시의 '좋아요' 총합이 기본 데이터베이스의 실제 값과 잠시 어긋나더라도, 순간적인 차이는 문제를 일으키거나 눈에 띄지 않을 가능성이 높습니다.
반면 캐시에는 특정 상품의 마지막 한 개가 재고로 남아 있다고 표시되어 있는데, 기본 데이터베이스의 실제 재고는 이미 바닥났다면 어떻게 될까요? 이 충돌은 고객을 혼란스럽게 하고 떠나게 만들며, 브랜드의 신뢰도를 훼손하고, 회사의 거래와 회계에 혼란을 초래합니다. 최악의 경우 법적 문제로까지 번질 수 있습니다.
불일치에 대응하는 세 가지 방법
다행히도 앞서 살펴본 캐시 불일치의 각 원인에는 그에 대응하는 해결책이 존재합니다.
1. 캐시 무효화(Cache Invalidation)
캐시 무효화 방식에서는 기본 데이터베이스의 값이 업데이트될 때마다 대응하는 키를 가진 캐시 항목이 자동으로 삭제됩니다. 다소 '무식한(brute force)' 접근으로 볼 수도 있지만, 장점은 비용이 많이 들고 시간이 걸리는 쓰기를 기본 데이터베이스에 한 번만 수행하면 된다는 점입니다. 두 번 이상의 쓰기가 필요 없습니다.
2. 라이트 스루 캐싱(Write-Through Caching)
이 방식에서는 기본 데이터베이스를 갱신하고 캐시를 제거하는 대신, 애플리케이션이 캐시를 먼저 업데이트하면 캐시가 기본 데이터베이스를 동기적으로(synchronously) 갱신합니다. 즉, 기본 데이터베이스가 업데이트를 주도하는 것이 아니라, 캐시가 스스로의 일관성을 책임지고 자신이 수행한 변경 사항을 기본 데이터베이스에 알리는 구조입니다.
3. 라이트 비하인드 캐싱(Write-Behind Caching)
안타깝게도 두 번의 쓰기가 오히려 문제를 만드는 경우도 있습니다. 라이트 스루 전략의 단점은 캐시와 기본 데이터베이스 양쪽을 모두 갱신해야 하므로, 시간이 걸리고 프로세서에 부담을 주는 변경이 캐시에 한 번, 기본 데이터베이스에 한 번, 총 두 번 필요하다는 것입니다.
라이트 비하인드(write-behind)라고 알려진 또 다른 전략은 이 문제를 피합니다. 처음에는 캐시만 업데이트하고, 기본 데이터베이스는 나중에 갱신하는 것입니다. 물론 기본 데이터베이스도 결국 업데이트해야 하고 빠를수록 좋지만, 이 경우 사용자는 두 번의 쓰기 '비용'을 치르지 않아도 됩니다. 기본 데이터베이스에 대한 두 번째 쓰기는 비동기적으로(asynchronously), 화면 뒤에서(그래서 이름이 write-behind입니다) 성능에 미치는 영향이 적은 시점에 수행됩니다.
Redis Enterprise의 해결책
캐시 무효화 외에도 라이트 스루와 라이트 비하인드 캐싱은 캐시 일관성을 달성하는 데 도움이 되는 다양한 시나리오를 다룰 수 있습니다. 하지만 문제의 답을 찾는 것과 실제로 구현하는 것은 별개의 문제입니다.

Redis Enterprise의 액티브-액티브(active-active) 지오 듀플리케이션(geo-duplication)은 다중 프라이머리(multiple primaries)를 허용하여 점점 더 무거워지는 부하를 능숙하게 처리할 수 있게 해줍니다. '액티브-액티브'라는 이름은 데이터베이스의 각 인스턴스가 어떤 키에 대해서든 읽기와 쓰기 연산을 모두 수락할 수 있다는 의미입니다. 아무리 멀리 떨어져 있어도 각 데이터베이스 인스턴스는 네트워크상의 대등한(peer) 노드입니다. 따라서 어느 인스턴스에 쓰기가 발생하면 해당 노드는 네트워크상의 다른 모든 인스턴스에 자동으로 메시지를 보내 캐시에서 무엇이 변경되었는지 알리고, 모든 인스턴스가 일관된 캐시 데이터 세트를 유지하도록 보장합니다.
Redis Enterprise의 독특한 액티브-액티브 지오 듀플리케이션은 캐시 불일치로 이어질 수 있는 잠재적 쓰기 충돌을 처리하도록 설계된 정교한 알고리즘을 사용합니다. 이 알고리즘은 충돌 없는 복제 데이터 타입(CRDT, Conflict-free Replicated Data Types)에 기반하여, 여러 복제본의 쓰기를 일관성을 효과적으로 유지하는 방식으로 병합할 수 있도록 보장합니다.
일관성, 어리석은 집착이 아니라 필수 조건입니다
캐시 일관성을 유지하는 과제는 아키텍처가 성장할수록 더욱 복잡해지고 그 파급력도 커집니다. 따라서 비즈니스가 요구하고 고객이 기대하는 일관성을 안정적으로 제공하려면 엔터프라이즈급 캐싱 솔루션이 필요합니다.
에머슨에게 일관성이 '도깨비불(hobgoblin)' 같은 것이었을지 몰라도, 엔터프라이즈급 데이터베이스 캐싱에서 일관성은 그야말로 필수입니다. 그렇기에 Redis Enterprise를 선택하는 것이 현명합니다. 선택하지 않는 것이야말로 어리석은 일이니까요.
캐싱에 대한 전체 이야기가 궁금하다면 리 앳치슨(Lee Atchison)의 저서 Caching at Scale with Redis를 읽어보세요.