레디스 최악의 사례 7가지

랏 뜨·2025년 10월 17일

🔎 Overview

  최근 레디스에 대한 개념을 확실하게 이해하고 개발에 사용하기 위해서, 실전 레디스 : 기초, 실전, 고급 단계별로 배우는 레디스 핵심 가이드 도서를 읽으며 내용을 이해하고, 실습하고 있다.

  여러 개념들을 알아가던 중, 굉장히 눈에띄는 문구가 있었다.

레디스 최악의 사례 7가지

  이 얼마나 폭력적인 문장인가. 딱 봐도 레디스 기술 사용에 있어서 굉장히 중요한 요소임을 강조하는 듯하다.

  그런 의미에서, 해당 내용을 블로그에 정리해두기로 결정했다.


1️⃣ 비밀번호 미설정


  • 많은 경우, 레디스에서 비밀번호를 설정하지 않음
  • 비밀번호를 따로 설정하지 않는다면, 해당 레디스에 접속한 어떤 사람이든지 레디스 명령어 사용 가능
    • 레디스 설정을 바꾸거나, 데이터 삭제, 디도스 공격 등 일어나서는 안 되는 일들이 벌어질 수 있음
    • 해킹에 매우 취약

💡 반드시 비밀번호를 설정하자

# redis.conf
requirepass {passwd}
  • 사용하는 conf 설정 파일에서 requirepass 를 반드시 지정
    • 해당 비밀번호를 통해 인증해야만, 레디스 명령어 사용 가능

# redis-cli 에서 명령어 실행하려면
AUTH {passwd}
  • redis-cli 등 클라이언트에서 명령어를 실행하기 위해서는, 반드시 AUTH 를 통해 인증이 완료되어야 함
    • 비밀번호 없이는 레디스 명령어 사용 금지

2️⃣ KEYS 명령어 사용 금지


  • KEYS {pattern} : 레디스 서버에서 사용 중인 들을 전부 확인하는 명령어
  • 키의 개수가 많아지면 많아질수록 성능에 큰 영향

🤔 WHY

  • 레디스는 기본적으로 단일 스레드 구조
    • KEYS 실행 중 다른 작업들은 전부 블로킹
  • KEYS 의 시간복잡도는 O(N)
  • 최대 2의 32승개의 키를 저장 가능
    • 최악의 경우 2의 32승의 시간복잡도
  • 운영 환경에서 잘못 사용한다면, 한 번의 KEYS 명령으로 레디스 서버 전체가 몇 초 ~ 수십 초간 블로킹될 가능성 존재

💡 SCAN 명령어를 사용하자

SCAN 0 MATCH user:* COUNT 100
  • SCAN 명령어는 기본적으로 비동기적 조회
    • 서버를 블로킹하지 않음
  • SCAN 명령어와 인덱스, 카운트 개수를 여러 번 호출하여, 전체 키를 천천히 순회
  • 배치 처리와 유사

3️⃣ SELECT - 번호 기반 DB 사용


  • SELECT {번호} 명령을 사용하면 레디스 내의 각자 다른 데이터베이스를 사용할 수 있음
    • ex) SELECT 0 , SELECT 1
    • 0-based-index
  • 하지만 이런 번호 기반 데이터베이스들은 완전 부리된 데이터베이스가 아님
    • 논리적으로만 다른 데이터베이스

🤔 WHY

  • 같은 키:값DB 0, DB 1에서 각각 별도로 존재할 수 있지만, 내부적으로는 동일한 레디스 인스턴스 자원(CPU, 메모리, 이벤트 루프 등)을 공유
    • DB 0에서 KEYS 명령을 사용하면, 이 명령은 레디스 인스턴스의 이벤트 루프를 블로킹하므로, 같은 인스턴스 내 데이터베이스 또한 모두 블로킹
    • 즉, 독립적인 것처럼 보여도 실제 격리/스케일링 측면에서는 전혀 독립적이지 않음
  • 기술적인 면에서 또한, 클러스터 환경에서는 번호 기반 데이터베이스 미지원
    • 단일 노드에서만 정상 동작 가능
    • 확장 불가
  • 즉, 확장성, 안정성 측면에서 심각한 제약 초래
  • 레디스 창시자 Salvatore Sanfilippo 또한, "레디스에서 만든 최악의 디자인 실수" 라고 평가할 정도

💡 번호 기반 DB 대신, 레디스 인스턴스를 새로 띄워 분리하여 운영하자

  • 레디스는 인스턴스 하나당 메모리 오버헤드가 낮음
  • 따라서 레디스 서버를 따로 띄워 인스턴스를 추가하고 클러스터 버스라는 내부 채널 안에서 노드 간 통신을 하는 레디스 클러스터 방식을 사용하면, 샤딩을 통한 데이터 분리 및 MOVED 명령을 통한 해당 데이터 소유 캐시 노드로의 자동 리다이렉션 또한 가능

4️⃣ HGETALL, LRANGE 같은 무제한 반환 주의


  • 레디스 명령어 중 일부는 모든 데이터를 한 번에 반환
    • HGETALL : Hash 자료형의 모든 field/value 반환
    • LRANGE 0 -1 : List 자료형의 모든 요소 반환
      • 레디스에서 오프셋에 사용되는 0 은 시작 인덱스이며, -1 은 마지막 인덱스
    • SMEMBERS : Set 자료형의 모든 요소 반환
    • ZRANGE 0 -1 : Sorted Set 자료형의 모든 요소 반환
    • etc)...

🤔 WHY

  • 매우 큰 데이터 구조
    • Hash : 필드 수 최대 2의 32승, 값 최대 512MB
    • List : 요소 수 최대 2의 32승, 값 최대 512MB
    • Set / Sorted Set : 요소 수 매우 많을 수 있음
  • 사용 데이터가 누적된다면 기존 예상보다 훨씬 큰 데이터 구조가 될 가능성 존재
  • 이러한 데이터를 한꺼번에 모두 가져온다면, 최악의 경우레디스 서버 자체가 다운

💡 크기를 먼저 체크한 후, 필요한 범위 내에서만 조회하자

  • 데이터 크기 확인
    • Hash : HLEN {key}
    • List : LLEN {key}
    • Set : SCARD {key}
    • Sorted Set : ZCARD {key}
  • 필요한 만큼만 부분 조회
    • List : LRANGE {startIdx} {endIdx}
    • 그 외 : {Xxx}SCAN ...

5️⃣ 하나의 커넥션 당 하나의 명령은 비효율적


  • 대부분의 네트워크 통신 사용 기술에서 공통적으로 명시되는 명제
  • 레디스는 지속 연결 활용을 전제로 설계
    • 레디스 클러스터 사용 시 :
      • OSS Cluster API -> 클라이언트가 노드별 연결 유지
      • Redis Enterprise -> 프록시를 통한 연결 관리, 클러스터 복잡성은 숨김 처리
  • 매 연결 생성 및 해제 시 오버헤드 발생
    • 지속 연결 활용 불가능

💡 지속 연결을 활용하자

  • 연결은 열어둔 채 여러 명령을 수행
  • 필요 시 커넥션 풀 활용
  • REST 스타일 연결 패턴은 피할 것
    • 요청마다 연결 및 해제하기 때문

6️⃣ Hot Keys 문제


  • 레디스는 자주 접근되는 핵심 데이터를 저장할 때 효율 상승
  • 그렇지만 특정 몇 개의 키만 반복해서 접근하게 되면 Hot Keys 문제 발생

🤔 WHY

  • 레디스 클러스터 구조에서는 키가 데이터 저장 위치를 결정
    • 키 해싱을 통해 슬롯 위치를 판단하고, 해당 슬롯을 어느 샤드에 분배할지 결정
  • 하나의 키에 요청 집중 시 :
    • 해당 특정 노드모든 트래픽 집중
    • 클러스터 내의 나머지 노드는 미활용
    • 병목 현상 발생

💡 작은 수의 자주 쓰는 키 집중을 피하자

  • 설계 단계에서 Hot Key 패턴을 방지
    • 키 분산 설계
    • 동일 데이터를 여러 키에 분산 저장
    • 즉, 서로 다른 샤드에 배치
    • etc)...

7️⃣ 레디스를 주 DB 로 사용할 때 주의


  • 레디스를 주 DB로 사용하는 경우, 다운되면 전체 애플리케이션 중단
  • 단순한 레디스 기본 설정으로는 안정적인 주 DB 역할은 기대하기 어려움

💡 적절한 HA와 Durability를 설정하자

  • 고가용성 (High Availability)
    • OSS Redis -> Redis Sentinel 설정
      • 모니터링을 통해 마스터 서버 정상 연결 유무 확인
      • 페일오버를 통해 마스터 서버 장애 시 레플리카를 마스터로 자동 승격
      • 클라이언트에게 승격된 마스터 IP를 마스터 서버로 알림
      • 이러한 과정을 통해, 한 대의 레디스 서버가 죽더라도 서비스 미중단
  • 영속성 (Durability / Persistence)
    • OSS Redis -> RDB 스냅샷 또는 AOF 파일 사용
      - 해당 파일들이 일종의 백업 DB 파일
      - 레디스는 기본적으로 인-메모리 방식이므로 휘발성 메모리(RAM)를 사용하지만, 해당 파일들로부터 데이터를 불러오는 것이 가능

📌 Redis Enterprise 를 사용하는 경우, 별도의 설정 없이도 멀티 노드 클러스터, 복구, 백업이 모두 자동화되므로 바로 주 DB로 사용 가능


Reference :

profile
기록

0개의 댓글