Redis 정리

이형욱·2025년 7월 4일

Redis란?


  • Remote Dictionary Server의 약자.
  • Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 DBMS.
  • 인메모리 방식
  • String, Set, Sorted Set, Hash, List 다양한 데이터 타입 지원.
  • 싱글스레드 구조.

토큰 관리 기존 방법


  • 서버 메모리 기반 방식
    • 서버의 메모리에서 토큰을 직접 저장하고 관리하는 방식
    • 세션이라고 생각할 수 있다.
    • 빠르지만 서버가 다운 되면 토큰 정보가 사라진다.
  • 데이터베이스 기반 방식
    • 생성한 토큰을 RDB 또는 NOSQL에 저장하고 유효기간, 발행 시점을 관리
    • 사용자가 인증 요청 시 토큰 정보를 조회하거나 갱신
    • 스케줄러 또는 트리거를 활용하여 토큰 유효성 직접 체크해야함.

Redis 를 사용하는 이유


  • Key-value 구조로 데이터 관리.
  • 인메모리 데이터베이스이다.
    • SSD/HDD 기반의 RDB 또는 NOSQL보다 빠른 읽기/쓰기 속도를 제공하여 실시간 인증에 적합하다.
  • 토큰의 유효시간 관리(TTL, Time-To-Live)에 적합하다.
    • 토큰의 만료 시간을 자동으로 관리할 수 있기 때문에, 유효 기간이 지난 토큰을 자동 삭제할 수 있다.
  • 분산 환경의 확장성(스케일 아웃)
    • 클러스터링과 슬레이브 복제를 지원하여 여러 서버에서 동시에 토큰을 관리할 수 있다.
  • 메모리 기반이지만 지속성 옵션 제공
    • AOF(Append Only file) 또는 RDB(Snapshotting) 방식 제공
    • 해당 방식을 이용하여 redis 서버가 다운되더라도 토큰 정보 복구 가능

발생할 수 있는 문제점


  • 토큰 개수 증가 시 메모리 부족 문제가 발생할 수 있다.
    • TTL로 오래된 토큰을 자동으로 삭제하도록 관리
    • LRU(Least Recently Used)알고리즘을 사용하여 메모리에서 가장 오래된 데이터를 제거
    • Redis 클러스터링 기능을 사용하여 수평 확장 진행
  • redis 서버 다운 시 메모리에 저장된 데이터는 사라짐 → 인증 토큰과 같은 중요한 데이터 손실 초래.
    • AOF 또는 RDB 옵션 활성화
      • AOF → 모든 쓰기 명령을 로그에 기록
      • RDB → 주기적으로 스냅샷을 생성
  • redis 서버 다운 시 모든 토큰 정보 손실되고 인증 처리가 중단된다. (싱글 포인트 실패)
    • redis 복제 기능을 활용하여 마스터-슬레이브 구조로 데이터를 복제하고, sentinel을 사용해서 장애 복구를 자동화. 이를 통해 redis가 다운되더라도 다른 인스턴스를 자동으로 사용.
  • 분산 환경에서 redis를 사용할 때, 여러 서버에서 동시에 토큰을 갱신하는 등의 동시성 문제가 발생할 수 있다. 여러 서버가 같은 토큰을 업데이트하려 할 때 일관성 문제 발생.
    • redis의 트랙잭션 기능인 multi/exec 또는 lua 스크립트를 활용하여 원자적인 단위로 작업을 처리함으로써 동시성 문제를 해결하고 토큰 갱신을 안전하게 처리할 수 있다.

서버 다운의 경우, 인증 토큰과 같은 중요한 데이터 손실을 고려해야하는 이유


  • 사용자 경험
    • 서버가 재가동되면 사용자는 재로그인을 해야하기 때문에 불편하다. 인증 상태가 중요한 실시간 시스템이나 금융 서비스에서는 이런 불편을 최소화하는 것이 중요하다.
  • 가용성 문제
    • 서버가 재가동 되고 새로운 토큰이 발급되면 그러한 토큰에 대한 인증 처리를 수행하는데 비용이 많이 발생한다.

Redis Client Lettuce VS Jedis


  • 현재 Lettuce가 기본 클라이언트로 적용 되어 있다.
특성LettuceJedis
기반비동기 I/O(Netty 사용)동기 I/O(블로킹)
스레드 안정성Thread Safe(싱글 스레드에서 공유 가능)Thread Not Safe
비동기 처리지원(비동기 및 논블로킹)미지원
성능높은 성능(대규모 시스템)낮은 성능(단일 스레드 환경)
반응형 지원지원(Refactor와 함께 사용 가능)미지원
클러스터와의 호환성Redis Cluster 및 Sentinel 지원Redis Cluster 및 Sentinel 지원
설정 복잡도상대적 복잡상대적 간단

redis.conf 기본 옵션 정리


네트워크 설정

  • bind
  • protected-mode
  • port
  • tcp-backlog
  • timeout
  • maxclients
  • tcp-keepalive

일반 설정

  • requirepass
  • daemonize
  • supervised
  • pidfile
  • loglevel
  • logfile
  • database
  • always-show-logo

스냅샷 설정

  • save
  • stop-writes-on-bgsave-error
  • rdbcompression
  • rdbchecksum
  • dbfilename
  • dir
  • rdb-del-sync-files

복제 설정

  • replica-serve-stale-data
  • replica-read-only
  • repl-diskless-sync
  • repl-diskless-sync-delay
  • repl-diskless-load
  • repl-disable-tcp-nodelay
  • replica-priority

LAZY FREEING 설정

  • lazyfree-lazy-eviction
  • lazyfree-lazy-expire
  • lazyfree-lazy-server-del
  • replica-lazy-flush

APPEND ONLY MODE 설정

  • appendonly
  • appendfilename
  • no-appendfsync-on-rewrite
  • auto-aof-rewrite-percentage
  • auto-aof-rewrite-min-size
  • aof-load-truncated
  • aof-use-rdb-peamble

SLOW 로그 설정

  • slowlog-log-slower-than
  • slowlog-max-len

지연시간 모니터 설정

  • latency-monitor-threshold

이벤트 알림 설정

  • notify-keyspace-events

ADVANCED 설정

  • 메모리 절약하기 위한 데이터 구조 설정
    • hash-max-ziplist-entries
    • hash-max-ziplist-value
    • list-max-ziplist-size
    • list-compress-depth
    • set-max-intset-entries
    • zset-max-ziplist-entries
    • zset-max-ziplist-value

클라이언트 출력 버퍼 제한

  • 어떤 이유에서든지 서버에서 데이터를 빨리 읽지 못하는 클라이언트 연결 강제 해제
  • client-output-buffer-limit
  • hz
  • dynamic-hz
  • aof-rewrite-incremental-fsync
  • rdb-save-incremental-fsync

redis.conf 설정(스냅샷 저장 방식)


# 연결가능한네트위크(0.0.0.0=Anywhere)
bind 0.0.0.0

# 연결포트
port 6379

# 보호모드-redis가 외부(0.0.0.0)에 바인딩 되어있거나, 비밀번호가 설정되지 않으면 접속 차단
protected-mode yes

# Master노드의기본사용자비밀번호
requirepass redis

# 최대사용메모리용량(지정하지않으면시스템전체용량)
maxmemory 2gb

# 설정된최대사용메모리용량을초과했을때처리방식
# - noeviction:쓰기동작에대해error반환(Default)
# - Volatile-lru:expire가설정된key들중에서LRUalgorithm에의해서선택된key제거
# - allkeys-lru:모든key들중LRUalgorithm에의해서선택된key제거
# - volatile-random:expire가설정된key들중임의의key제거
# - allkeys-random:모든key들중임의의key제거
# - volatile-ttl:expiretime(TTL)이가장적게남은key제거(minorTTL)
maxmemory-policy volatile-lru

# == RDB관련설정 ==
# 저장할RDB파일명
dbfilename backup.rdb

# 15분 안에 최소 1개 이상의 key가 변경 되었을 때
save 900 1
# 5분 안에 최소 10개 이상의 key가 변경 되었을 때
save 300 10
# 60초 안에 최소 10000개 이상의 key가 변경 되었을 때
save 60 10000
# RDB 저장 실패시 write명령 차단 여부
stop-writes-on-bgsave-error no

redis.conf 설정(AOF 저장 방식)


# 연결가능한네트위크(0.0.0.0=Anywhere)
bind 0.0.0.0

# 연결포트
port 6379

# 보호모드-redis가 외부(0.0.0.0)에 바인딩 되어있거나, 비밀번호가 설정되지 않으면 접속 차단
protected-mode yes

# Master노드의기본사용자비밀번호
requirepass redis

# 최대사용메모리용량(지정하지않으면시스템전체용량)
maxmemory 2gb

# 설정된최대사용메모리용량을초과했을때처리방식
# - noeviction:쓰기동작에대해error반환(Default)
# - Volatile-lru:expire가설정된key들중에서LRUalgorithm에의해서선택된key제거
# - allkeys-lru:모든key들중LRUalgorithm에의해서선택된key제거
# - volatile-random:expire가설정된key들중임의의key제거
# - allkeys-random:모든key들중임의의key제거
# - volatile-ttl:expiretime(TTL)이가장적게남은key제거(minorTTL)
maxmemory-policy volatile-lru

# fsync 정책 (쓰기 성능 vs 신뢰성)
# everysec: 매 1초마다 디스크에 기록 (기본값, 추천)
# always: 매 명령어마다 디스크 기록 (신뢰성 높음, 성능 낮음)
# no: OS에 맡김 (속도 높음, 안전성 낮음)
appendfsync everysec

appendonly yes
appendfilename "appendonly.aof"

# AOF 리라이트 조건 - 7.2 버전이후로 삭제됨.
# auto-aof-rewrite-percentage 50      # 기존 AOF 파일보다 2배 커지면 리라이트
# auto-aof-rewrite-min-size 64mb       # 최소 64MB 이상일 때만 리라이트 수행

# 리스타트 시 AOF 파일 복구 옵션 (기본값: yes)
aof-load-truncated yes

# RDB 관련 백업 병행
# 15분 안에 최소 1개 이상의 key가 변경 되었을 때
save 900 1
# 5분 안에 최소 10개 이상의 key가 변경 되었을 때
save 300 10
# 60초 안에 최소 10000개 이상의 key가 변경 되었을 때
save 60 10000

# database 개수 제한(기본값 16, 0~15)
databases 1

# 해킹에 위험한 명령어 무력화
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command DEBUG ""
rename-command CONFIG ""
rename-command SHUTDOWN ""
rename-command SAVE ""
rename-command BGSAVE ""

# 또는 명령어 바꾸기 (관리자만 알고 있는 명령어로)
# rename-command CONFIG "no_one_can_guess_this_123"

Redis 명령어


  • Redis는 기본적으로 인증이 없기 때문에 외부에서 접근할 수 있는 redis 서버에는 반드시 비밀번호를 설정해야 한다.
    • redis.conf 파일에 requirepass에 비밀번호를 설정해야한다.
  • 외부 네트워크와 연결될 수 있는 환경이면 requirepass 외에 IP화이트리스트(bind) 및 방화벽을 적용해야 한다.
  • AUTH
    • redis에 비밀번호 인증을 수행하는 명령어
    • 인증에 성공하면 이후 redis 명령어를 정상적으로 실행할 수 있음.
      AUTH ${비밀번호}
  • config get requirepass
    • 현재 설정된 비밀번호 알아내기
  • config set requirepass ${비밀번호}
    • 비밀번호 설정하기
  • 기본적인 명령어들
    get <key> // <key>는 조회하려는 키 이름
    
    ex) myKey
    
    조회 성공 예시)
    "1234"
    
    조회 실패 예시)
    (nil) // 값이 없는 경우
    
    -------------------------------------------------------------------------------------
    set <key> <value> // <key>는 생성하려는 키 이름, <value>는 저장할 값
    ex) set myKey "1234"
    
    // 만료 옵션 설정
    set <key> <value> EX <ex value> // EX 는 초 단위로 만료 시간 설정
    ex) set myKey "1234" EX 10 // 10초 뒤 자동 삭제
    
    set <key> <value> PX <px value> // PX는 밀리초 단위로 만료 시간 설정
    ex) set myKey PX 5000 // 5초 뒤 자동 삭제
    
    // NX - 키 없을 때만 설정
    // 키가 존재하지 않으면 값 설정. 키 존재하면 아무것도 작업도 수행 안함.
    set myKey "1234" NX
    
    // XX - 키가 있을 때만 설정
    // 키가 존재할 때만 값 설정. 키가 존재하지 않으면 아무것도 수행 안함.
    set myKey "1234" XX
    
    // GETSET - 기존 값 가져오고 새 값 설정
    GETSET myKey "4321"
    (nil) // 기존 키가 없었으면 nil 반환
    "1234" 기존 값이 "1234" 였을 경우 반환.
    
    -------------------------------------------------------------------------------------
    del <key> // <key>는 삭제하려는 키 이름
    
    ex)
    del myKey 또는 del mykey1 mykey2 // 여러 키 삭제 가능
    
    삭제 성공 예시)
    (integer) 1 (하나의 키 삭제 됨)
    
    없는 키 삭제 예시)
    (integer) 0 
    
    -------------------------------------------------------------------------------------

Redis Docker Compose 설정


  • docker-compose.yml
services:
  redis:
    image: redis:latest
    container_name: redis
    environment:
      TZ: "Asia/Seoul"
    ports:
      - "26379:6379"  # 호스트 포트 26379를 컨테이너 포트 6379로 매핑
    volumes:
      - ./data:/data  # Redis 데이터를 저장할 볼륨
    restart: always  # 컨테이너가 종료되면 자동으로 재시작

SpringBoot와 Lettuce


  • build.gradle 설정
    implementation 'org.springframework.boot:spring-boot-starter-data-redis:3.3.5'
    
    // starter-data-redis가 lettuce-core를 컴파일 의존하고 있기 때문에 자동으로 설치됨.
    // implementation 'io.lettuce.core:lettuce-core'

application.properties


  • application.properties에 추가.
    # Redis 서버 호스트 설정
    spring.data.redis.host=localhost
    
    # Redis 서버 포트 설정
    spring.data.redis.prt=26379
    
    # Redis 연결 패스워드 설정
    spring.data.redis.password=96L03o04m$$
    
    # Redis 데이터베이스 번호(기본 0번 데이터베이스 사용)
    spring.data.redis.database=0
    
    # Lecttuce 클라이언트 관련 설정
    
    # 최대 커넥션 수
    spring.data.redis.lettuce.pool.max-active=10
    
    # 최대 유휴 커넥션 수(기본 값: 8, 제한 없음: -1)
    spring.data.redis.lettuce.pool.max-idle=8
    
    # 최소 유휴 커넥션 수(기본 값: 0)
    spring.data.redis.lettuce.pool.min-idle=0
    
    # 커넥션 풀 대기 시간(밀리초) (기본 값: -1, 무기한 대기를 의미)
    # 커넥션 풀에서 새로운 커넥션을 얻기위해 요청을 보냈을 때, 사용한 커넥션 풀이 생길 때까지 기다리는 시간.
    # 커넥션 풀이 고갈되어 더이상 커넥션을 할당 할 수 없으면 설정한 시간 이후 예외를 던진다.
    spring.data.redis.lettuce.pool.max-wait=-1
    
    # 연결 타임아웃 및 소켓 타임아웃 설정
    # redis 서버와의 연결 타임아웃(밀리초)
    spring.data.redis.timeout=2000
    
    # 소켓 통신 타임아웃(밀리초)
    spring.data.redis.connect-timeout=2000
    
    # redis 연결 종료 타임아웃(밀리초) (기본값: 100)
    spring.data.redis.lettuce.shutdown-timeout=100

Redis Clustering


GPT한테 물어볼 것.


직렬화란 무엇이고 왜 필요한지?

역직렬화는 무엇인지?

직렬화 할 때, template.setKeySerializer과 template.setHashKeySerializer의 차이가 무엇인지.

RedisSerializer.json()과 RedisSerializer.java()의 차이가 무엇인지.

TTL

만료된 토큰 처리 블랙리스트 vs 기존 것을 덮어 씌우는 방식.

https 적용방법?

분산된 아키텍처에서 동기화 문제 해결 방법?

→ 분산 락: SETNX 또는 Redisson 같은 분산 락을 활용하여 동시 요청 순차 처리

→ 비즈니스 로직 설계: 재시도 로직 또는 분할 작업

→ 비관적 락: 데이터베이스에서 비관적 락 사용하여 데이터베이스 레벨에서 동시성 문제 처리.

Redis의 기본 Method


  • opsForValue().set() 메서드
    • redisTemplate.opsForValue().set(key, value);
      • key: Redis에서 값을 저장할 키
      • value: REdis에 저장할 값.
      • key에 value 값을 저장.
  • opsForValue().get() 메서드
    • redisTemplate.opsForValue().get(key);
      • key: redis에서 조회할 키
      • key에 해당하는 값을 가져오고 없으면 null 반환
  • delete() 메서드
    • redisTemplate.delete(key)
      • key: 삭제할 redis의 키
      • 지정된 key를 redis에서 삭제함.
  • hasKey() 메서드
    • redisTemplate.haskey(key);
      • key: 존재 여부를 확인할 redis의 키
      • key가 redis에 존재하는지 여부를 boolean으로 반환.

Redis에서 Key & Value 구성


  • key
    • 리프레시 토큰을 고유하게 식별할 수 있는 정보로 구성
    • 주로 사용자 ID으로 토큰 식별.
    • 사용자 ID가 12345인 유저
      • refresh_token:12345 가 key가 됨.
  • value
    • 단순 토큰 저장 용도
    • 관련 정보도 함께 저장
      • 발급 시간, 만료 시간, 사용자 ID 등을 HashMap 같은 데이터 구조를 이용해서 JSON 객체로 저장.

에러 및 경고


WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
  • Linux 커널 메모리 overcommit 정책이 비활성화(vm.overcommit_memory=0) 되어 있어서 redis 의 백그라운드(BGSAVE, AOF rewrite, 복제 등) 이 실패할 수 있다는 경고.

  • overcommit이란?

    • redis는 백그라운드로 데이터를 저장하거나 복제할 때 메모리 스냅샷을 복제하는데, 이 때 시스템이 메모리 부족이 아님에도 fork() 실패할 수 있음.
  • 해결 방법

    1. sudo vim /etc/sysctl.conf
    2. vm.overcommit_memory = 1 맨 아래에 추가.
    3. sudo sysctl - p
profile
바나나는 하드디스크보다 따듯하다.

0개의 댓글