Memcached vs Redis: 휘발성 캐싱을 위한 올바른 도구 선택하기

Memcached vs Redis: 휘발성 캐싱을 위한 올바른 도구 선택하기

Memcached는 엄격한 휘발성 캐싱을 위한 최적의 선택입니다

Memcached는 동적 웹 애플리케이션의 속도를 높여 데이터베이스 부하를 완화하기 위해 특별히 설계된 고성능 분산 메모리 객체 캐싱 시스템입니다. 더 많은 기능을 제공하는 대안들과 달리, memcached는 내장된 지속성(persistence)이 없기 때문에 엄격한 "캐시 전용" 사고 모델을 강제하며, 이는 재시작 중 데이터 손실이 허용되고 예상되는 상태 비저장(stateless) 워크로드에 이상적인 선택이 됩니다.

Redis의 "지속성 함정"

Redis가 스택에 캐시로 도입될 때, 종종 기본 데이터 저장소로 오용되는 경우가 많습니다. Redis는 SQL INSERT 문보다 간단한 set 추상화를 제공하고 선택적인 지속성을 제공하기 때문에, 개발자들은 운영 팀의 인지 없이 Redis를 영구적인 데이터베이스로 취급하기 시작할 수 있습니다.

이러한 불일치는 심각한 운영 리스크를 초래합니다:

  • 알림 공백(Alerting Gaps): 운영 팀은 캐시가 휘발성이라고 가정하고 알림을 구성할 수 있지만, 애플리케이션은 영구 데이터를 위해 캐시에 의존할 수 있습니다.
  • 치명적인 데이터 손실: 애플리케이션이 캐시를 데이터베이스로 취급하고 있었다면, 인프라 장애(예: 디스크 장애 또는 노드 마이그레이션)로 인해 영구적인 데이터 손실이 발생할 수 있습니다.
  • 유지 관리 오버헤드: 애플리케이션이 Redis의 지속성 기능과 너무 밀접하게 얽히게 되면, 시스템을 상태 비저장 유틸리티가 아닌 "애완동물(pet)"처럼 모니터링하고 유지 관리해야 합니다.

Memcached의 운영상 이점

Memcached는 단순하고 휘발성인 캐시가 필요한 팀에게 몇 가지 아키텍처적 이점을 제공합니다:

단순화된 다운타임 처리

memcached용 클라이언트 라이브러리는 일반적으로 연결 예외를 무시합니다. 서버가 다운된 경우 get 요청은 일반적으로 기본값 또는 none을 반환하여, 애플리케이션이 기본 데이터 소스로 폴백(fallback)함으로써 우아하게 실패할 수 있도록 합니다.

클라이언트 측 클러스터링

Memcached는 내장된 클러스터링 기능이 없습니다. 대신, 클러스터링은 여러 URL로 구성된 클라이언트 라이브러리에 의해 처리됩니다. 클라이언트는 키를 해싱하여 대상 인스턴스를 선택합니다. 노드가 다운된 것으로 감지되면 클라이언트는 해셔(hasher)에서 해당 노드를 제거하고 일정 기간 후 재연결을 시도합니다. 이는 복잡한 서버 측 합의 메커니즘의 필요성을 제거합니다.

예측 가능한 성능

설계상 거의 모든 memcached 작업은 O(1)입니다. 이는 Redis에서 발생할 수 있는 "무작위 지연(random stalls)"을 방지합니다. Redis에서는 단일 스레드 코어가 임의의 복잡도를 가진 복잡한 작업에 의해 차단될 수 있어 다른 모든 요청을 지연시킬 수 있습니다.

캐시 사용 사례에 따른 Memcached와 Redis 비교

memcached가 단순 휘발성 캐싱에는 우수하지만, Redis는 고급 데이터 구조나 지속성이 필요한 애플리케이션에 더 나은 선택입니다.

Feature Memcached Redis
Persistence None (Strictly volatile) Optional (AOF/RDB)
Clustering Client-side hashing Server-side consensus/clustering
Complexity Low (O(1) operations) High (Supports complex data types)
Primary Use Case Simple K/V caching Persistent data structures, scoreboards, complex state

Redis를 계속 사용하는 경우

커뮤니티 논의에서 언급되었듯이, memcached는 더 큰 규모의 팀에게는 너무 제한적일 수 있습니다. Redis는 다음과 같은 경우에 선호됩니다:

  • 범위 쿼리(Range Queries): Redis는 범위 쿼리(TreeMap과 유사)를 허용하지만, memcached는 키 기반 조회(HashMap과 유사)로 제한됩니다.
  • 복잡한 데이터 구조: Sorted sets와 hashes는 리더보드와 같은 기능을 위해 필수적입니다.
  • 관리형 클러스터링: 클라이언트 라이브러리보다 인프라가 합의와 장애 조치(failover)를를 처리하는 것을 선호하는 팀.

Redis를 캐시로 사용할 때의 모범 사례

Redis를 휘발성 캐시로 사용해야 하는 경우, Redis가 유사 데이터베이스가 되는 것을 방지하기 위해 다음과 같은 운영 가드레일을 권장합니다:

  1. 만료 시간 강제(Enforce Expiries): 클라이언트 라이브러리를 래핑하여 만료 날짜 없이 데이터가 저장되지 않도록 합니다.
  2. 휘발성 데이터 격리(Isolate Volatile Data): 지속성을 완전히 끄거나 영구 데이터와 분리된 전용 데이터베이스 인스턴스를 사용합니다.
  3. 메모리 정책 구성(Configure Memory Policies): 인스턴스가 사용 가능한 시스템 RAM을 모두 소비하지 않도록 엄격한 maxmemory 값을 설정하고 적절한 maxmemory-policy를 설정합니다.
  4. 복잡한 구조 피하기(Avoid Complex Structures): 만료된 hash의 부분 객체 업데이트를 피하기 위해 단순 캐싱을 위해 복잡한 데이터 구조를를 사용하려는 유식을 참아야 합니다.

Sources