Redis의 영속화 뜯어보기 (+docker 환경에서 Redis 세팅 법)

2025. 9. 2. 21:41·백엔드/DB

서론

Redis는 대표적인 In-Memory DB다.

In-Memory 이기 때문에 Redis 서버를 재시작할 때 데이터는 영속화되지 않고 날라간다.(휘발성)

이러한 Redis의 In-Memory 성질로 빛을 받았지만 추가적으로 Redis에서는 휘발 되지 않게 영속화 시켜주는 방안을 제시한다.

참고 문헌

  • 책 : 개발자를 위한 레디스:7장
  • 문서 : 레디스 공식 문서

레디스의 영속화

2가지 방안

  • AOF ( Append Only File) : 레디스 인스턴스가 처리한 모든 쓰기 작업을 차례대로 기록, 복원 시에는 파일을 다시 읽어가며 데이터 세트 재구성
  • RDB (Redis DataBase) : 일정 시점에 메모리에 저장된 데이터 전체를 저장(snapshot 방식)

  • 위 예제는 AOF 와 RDB의 저장 예시이다. 
    • AOF는 레디스에서 실행된 모든 쓰기 작업이 기록된다. key1 의 데이터가 다른 값으로 변경된 내역, key2 가 생성됐다가 삭제된 내역 모두 AOF 파일에 기록된다.
    • RDB는 사진을 찍듯 메모리의 데이터를 그대로 내려쓴다.
  • (실제로는 RDB 파일은 바이너리로 우리가 해석할 수 없는 형태이며, AOF 는 레디스 프로토콜 형태로 저장된다)

각 방식의 장단점

RDB

  • 장점
    • 시점 단위로 여러 백업본을 저장할 수 있고 AOF 파일보다 복원이 빠르다는 장점이 있다.
  • 단점
    • 특정 시점으로의 복구는 불가능하다는 단점이 있다.

AOF

  • 장점
    • 원하는 시점으로 복구할 수 있다 ( 조금 더 데이터 유실에 대해 안전하다)
  • 단점
    • 파일의 크기가 크고 주기적으로 압축해 재작성해야 한다.

레디스는 이 파일들을 언제 사용할까

  • 레디스에서 데이터를 복원할 수 있는 시점은 서버가 재시작될 때뿐이며, 레디스 인스턴스의 실행 도중에 데이터 파일을 읽어올 수 있는 방법은 없다.
  • 레디스는 재시작될 때 AOF 파일이나 RDB 파일이 존재하는지 확인한 뒤, 파일이 있을 때에는 파일을 로드한다.
    • 둘 다 있다면 AOF가 더 안전하다고 판단하여 AOF 를 로드한다.

RDB 방식의 데이터 백업

RDB 방식 백업

save 900 1
save 300 10
dir /data
dbfilename dump.rdb
  • redis.conf 에 위와 같은 조건으로 save 옵션을 설정한다면 인스턴스는 다음과 같은 상황에서 RDB 파일을 생성한다.300초 동안 10개 이상의 키가 변경된 경우
  • 900초 동안 1 개 이상의 키가 변경된 경우
  • RDB 방식은 AOF와 다르게 따로 활성화 옵션 없이도 위와 같이 save N M 같은 설정이 있으면 자동으로 활성화된다.

CONFIG REWRITE

레디스 인스턴스가 실행 중인 상태에서 설정 파일을 변경하는 것은 실행 중인 레디스 인스턴스에는 반영되지 않는다.
실행중인 레디스의 파라미터를 수정할 때에는 redis-cli 에서 직접 CONFIG SET 커맨드로 설정을 변경한 뒤,
CONFIG
REWRITE 커맨드를 이용해 설정 파일을 재작성하는 과정을 거쳐야 한다.

 

수동으로 RDB 파일 생성

  • 커멘드에 SAVE , BGSAVE 커멘드를 이용하면 원하는 시점에 직접 RDB 파일을 생성할 수 있다.
  • 두 방식 모두 실행 시점의 메모리 스냅숏을 생성하는 커멘드이지만 동작하는 방식에 차이가 있다.

SAVE

  • 해당 커멘드를 실행하면 파일 생성이 완료될 때까지 다른 모든 클라이언트의 명령을 차단한다.
  • 메모리 전체를 스캔해 파일이 저장되기까지 1분이 걸린다면 그 1분 동안 레디스 인스턴스에 연결된 다른 클라이언트는 아무런 명령도 수행할 수 없는 상황을 맞게 된다.
  • 운영 환경에서는 사용하지 않는 것이 좋다

BGSAVE

  • fork 를 호출해 자식 프로세스를 생성하며 생성된 자식 프로세스가 백그라운드에서 RDB 파일을 생성한 뒤 종료된다.
  • 만약 이미 백그라운드로 데이터가 저장 중이라면 이 명령은 에러를 반환할 수 있다.
    • BGSAVE SCHEDULE 옵션을 사용할 수 이 명령은 일단 OK 를 반환하고 진행중이던 백업이 완료됐을 때 다시 BGSAVE를 실행한다.
    • RDB 파일이 정상적으로 저장됐는지 LASTSAVE 커맨드로 확인할 수 있다.

복제를 사용할 경우 자동으로 RDB 파일 생성

복제본에서 REPLICAOF 커맨드를 이용해 복제를 요청하면 마스터 노드에서는 RDB 파일을 새로 생성해 복제본에 전달한다.

네트워크 등의 이슈로 인해 일정 시간 이상 복제가 끊어졌다가 복구된 경우 복제 재연결이 발생하며, 이럴 경우에도 마스터 노드는 복제본으로 RDB 파일을 전송한다.

 

AOF 방식의 데이터 백업

AOF 방식

  • AOF는 레디스 인스턴스에서 수행된 모든 쓰기 작업의 로그를 차례로 기록한다.
  • 실수로 FLUSHALL 커맨드로 데이터를 모두 날려버렸다 해도, AOF 파일을 직접 열어 FLUSHALL 커맨드만 삭제한 뒤 레디스를 재시작시킨다면 커맨드를 실행하기 직전까지로 데이터를 바로 복구할 수 있다.

AOF 활성화

  • redis.conf 설정 파일에서 appendonly 옵션을 yes로 지정하면 AOF 파일에 주기적으로 데이터가 저장된다.
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"

AOF 는 모든 커맨드의 실행 내역을 저장할까?

  • list 에서 블로킹 기능을 지원하는 BRPOP 커맨드는 AOF 파일에 저장될 때 에는 RPOP로 기록된다 AOF 파일에서 블로킹 기능을 굳이 명시해줄 필요는 없기 때문이다.

AOF 재구성(rewrite)

  • AOF 파일을 이용한 백업 기능을 안정적으로 사용하려면 점점 커지는 파일을 주기적으로 압축시키는 재구성(rewrite) 작업이 필요하다
  • RDB 와 마찬가지로 특정 조건에 자동으로 재구성되도록 설정할 수도 있고, 커맨드로 원하는 시점에 재구성할 수 있다.

AOF 재구성 동작 방식

  • AOF 재구성은 디스크에 저장되어 있는 AOF 를 사용하는 것이 아닌 레디스 메모리에 있는 데이터를 읽어와서 새로운 파일로 저장하는 형태로 동작한다.
  • aof-use-rdb-preamble yes를 no 로 변경하지 않는다면 이 데이터는 RDB 파일 형태로 저장한다. (기본값은 yes)
    • RDB 파일을 저장할 때와 마찬가지로 재구성할 때에도 fork를 이용해 자식 프로세스를 생성하며, 이 자식 프로세스가 AOF 파일을 재구성해 저장한다.
재구성이라고 하면 말이 이해가 안될 수 있는데 AOF의 단점이 파일의 크기가 커지는 것을 보완하기 위한 일종의 압축이라고 생각해도 좋다(사실 zip 같은 압축 알고리즘은 사용하지 않지만)

 

버전 7 이전에서의 AOF 파일

 

버전 7 이전까지는 AOF는 하나의 파일로 관리 됐다

 

AOF 파일의 앞부분은 메모리의 데이터를 읽어와 바이너리 형태로 저장한 RDB 파일이 위치한다.

이후 레디스의 메모리를 변경한 커맨드 로그들은 RESP 형태로 RDB 파일 뒤에 쌓인다.

 

  1. 레디스는 fork를 이용해 자식 프로세스를 생성한다. 생성된 자식 프로세스는 레디스 메모리의 데이터를 읽어와 신규로 생성한 임시 파일에 저장한다.
  2. 백그라운드로 (1) 의 과정이 진행되는 동안 레디스 메모리의 데이터가 변경된 내역은 기존의 AOF 파일과 인메모리 버퍼에 동시에 저장된다.
  3. 1. 의 AOF 재구성 과정이 끝나면 인메모리 버퍼에 저장된 내용을 1. 의 임시 파일 마지막에 추가한다.
  4. 생성된 임시 파일로 기존 AOF 파일을 덮어 씌운다.

 

  • 2 과정에서 생긴 데이터 로그가 AOF 파일과 인메모리 버퍼에 이중으로 저장된다.
  • 하나의 AOF 파일 내에 바이너리 형태와 RESP 의 텍스트 형태의 데이터가 저장돼 수동으로 AOF 파일 처리할 떄 관리가 복잡할 수 있다는 단점이 존재한다.

 

버전 7 이후에서의 AOF 파일

 

  • 7.0 이후에 레디스는 manifest 파일과 RDB 파일 그리고 AOF 파일을 분리하였다.
    • manifest 파일은 현재 레디스가 바라보고 있는 파일이 어떤 것인지 나타내는 매니패스트 파일을 추가적으로 도입했으며 매니페스트 파일은 RDB와 AOF파일이 무엇인지 알려준다.
  1. 레디스 인스턴스는 fork를 이용해 자식 프로세스를 생성한다. 생성된 자식 프로세스는 레디스 메모리의 데이터를 읽어와 신규로 생성한 임시 파일에 저장한다.
  2. 1 과정이 진행되는 동안 레디스 메모리의 데이터가 변경된 내역은 신규 AOF 파일에 저장된다.
  3. 1 의 AOF 재구성 과정이 끝나면 임시 매니페스트 파일을 덮어 씌운 뒤, 이전 버전의 AOF, RDB 파일들을 삭제한다.
  4. 생성된 임시 매니페스트 파일로 기존 매니페스트 파일을 덮어 씌운 뒤 이전 버전의 AOF ,RDB 파일들을 삭제한다.

위는 실제로 AOF 방식으로 영속화를 했을 때 생기는 기본 파일들이라

rdb 파일인 base 와 그 뒤에 AOF 방식으로 저장되는 incr.aof 그리고 manifest 가 저장되는 것을 볼 수 있다.

 


aof-use-rdb-preamble 옵션에 의해 압축되는 데이터 파일은 RDB 형태로 저장된다고 언급했다.

이를 no로 변경한다면 베이스 파일은 .base.rdb 형태가 아닌 .base.aof라는 이름으로 저장되며, 저장되는 형태도 RESP 프로토콜 형태의 텍스트로 변경된다.

 

AOF 구성의 효율성

  • AOF 파일의 재구성 과정은 모두 순차 입출력만 사용하기 때문에 디스크에 접근하는 모든 과정이 굉장히 효율적이다.

자동 AOF 재구성

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

auto-aof-rewrite-percentage 는 AOF 파일을 다시 쓰기 위한 시점을 정하기 위한 옵션이다

  • 이전 재구성 전 aof 파일의 크기에서 위 설정으로 설정한 퍼센티지만큼 현재 aof 파일의 크기가 커진다면 재구성을 시작한다.

auto-aof-rewrite-min-size 는 레디스가 처음 시작했을 때는 이전 aof 파일의 크기를 모르기에 0으로 설정된다 따라서 초반에 너무 많은 재구성이 일어날 수 있다.

위 설정으로 설정된 크기 이전에는 재구성이 이루어지지 않는다.

 

 

AOF 파일의 안정성

운영체제에서 애플리케이션이 파일에 데이터를 저장하고자 할 때, 곧바로 디스크에 데이터가 저장되진 않는다.

  • 그림과 같이 WRITE라는 시스템 콜을 이용해 애플리케이션에서 파일에 데이터를 저장하겠다 하면 데이터는 커널 영역의 OS 버퍼에 임시로 저장한다.
  • 운영체제가 판단하기에 커널이 여유 있거나, 최대 지연 시간인 30초에 도달하면 커널 버퍼의 데이터를 실제로 디스크에 내려 쓴다.

FSYNC

FSYNC는 커널의 OS 버퍼에 저장된 내용을 실제로 디스크에 내리도록 강제하는 시스템 콜이다.

OS에 부하가 있더라도 FSYNC가 호출되면 데이터는 무조건 디스크에 플러시 된다.

레디스에서 AOF 파일을 저장할 때 APPENDFSYNC 옵션을 이용하면 FSYNC 호출을 제어할 수 있으며, 즉 파일 저장의 내구성을 제어할 수 있다.

  • APPENDFSYNC no: AOF 데이터를 저장할 때 WRITE 시스템 콜을 호출한다. 데이터는 커널 영역에 데이터가 잘 저장되는지만 확인하기 때문에 쓰기 성능이 가장 좋다.
  • APPENDFSYNC always: AOF 데이터를 저장할 때 항상 WRITE 와 FSYNC 시스템 콜을 함께 호출한다.
  • 항상 데이터가 파일에 정확하게 저장되는 것을 기다리기 때문에 쓰기 성능은 가장 느리다.
  • APPENDFSYNC everysec: 데이터를 저장할 때 WRITE 시스템 콜을 호출하며, 1초에 한 번씩 FYNC 시스템 콜을 호출한다. 성능은 no 옵션을 사용했을 때와 거의 비슷하다고 한다.

 

백업을 사용할 때 주의할 점

RDB와 AOF 파일을 사용하는 경우 인스턴스의 maxmemory 값은 실제 서버 메모리보다 여유를 갖고 설정하는 것이 좋다.

 

이유는 레디스는 RDB 파일을 저장하거나 AOF 재구성을 진행할 때 fork를 이용해 자식프로세스를 생성하고 생성된 자식 프로세스는 레디스의 메모리를 그대로 파일에 저장해야하는데 이때 메모리의 데이터를 copy on write(COW) 로 그대로 메모리에 하나 더 복사한다.

 

 

 

따라서 레디스의 메모리는 최악의 경우 2배를 사용하게 될 수 있어 만약 maxmemory 값을 너무 크게 설정하면 OS의 OOM 문제로 서버가 다운될 수 있다.

 

 

레디스 백업 활용(+docker 환경 설정)

이번 챕터는 글쓴이가 나중에 보기 위한 docker container 에서 레디스를 운영할 때 사용할 커맨드와 설정을 작성할 예정이다.

 

redis.conf 및 백업 파일 마운팅 

docker run -d   \\
	--name redis-persistent \\
    -p 6311:6379  \\
    -v $(pwd)/data:/data \\
    -v $(pwd)/redis.conf:/usr/local/etc/redis/redis.conf  \\
    redis:7.0-alpine   \\
    redis-server /usr/local/etc/redis/redis.conf

redis 컨테이너를 실행시킬 때 host 의 redis.conf 와 data 디렉터리를 컨테이너 내부 os 파일 시스템과 연결하도록 container를 실행한다.

 

이렇게 실행하면 컨테이너 외부 OS에서 redis.conf를 편집할 수 있다.

 

 

RDB 복원 세팅

save 900 1       # 900초(15분) 동안 1개 이상 키 변경 → RDB 저장
save 300 10      # 300초(5분) 동안 10개 이상 키 변경 → RDB 저장
save 60 10000    # 60초 동안 10000개 이상 키 변경 → RDB 저장

dbfilename dump.rdb # 파일 이름
dir /data # dir 세팅 (docker 기본 경로)

 

redis.conf 설정 예시이다.

 

RDB 세팅은 save 조건이 있다면 기본으로 활성화 된다.

 

AOF 복원 세팅

appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"


# rewrite 세팅

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# FSYNC

appendfsync everysec

 

AOF 는 appendonly yes 설정을 해줘야 한다.

 

 

 

 

레디스 데이터 복원 사용 가이드(개인적인 생각)

복원 꼭 필요한가?

  • 복원은 꼭 필요하다는 고민해 볼 필요가 있다.
  • 레디스를 캐시만을 위해 사용한다면 굳이 필요한가 싶기도 하지만 모든 상황에 적용되는 이론은 없다고 생각한다. 트레이드 오프를 잘 판단하자

RDB vs AOF 뭘 사용할까?

  • RDB 와 AOF의 장단점을 생각하자
  • RDB는 복원이 빠르지만 안정성은 AOF에 비해 낮고 COW 위험이 있다는 점이 단점이다.
  • AOF는 command 명령 자체를 저장하기 때문에 RDB에 비해 용량이 크다는 단점이 있지만 순차 디스크 접근을 하기에 빠르고 COW 위험이 없을 수 있다 그리고 복원 데이터의 손상 위험도가 RDB에 비해서 적다.
  • 무엇을 사용할지는 엔지니어의 선택이다.

RDB 와 AOF 둘 다 사용하는 것도 방식이다.

  • rewrite 설정을 통해 AOF 의 큰 용량을 RDB로 compact 시키고 AOF를 통해서 디스크 접근을 빠르고 안정적으로 하는 것을 추천한다. (공식이도 추천하는 듯)
  • 하지만 이 또한 선택이다 트레이드 오프를 잘 고려하자

 

 

 

 

 

 

 

'백엔드 > DB' 카테고리의 다른 글

Spring Data Redis에서 Redis Pub/Sub 사용하기  (0) 2025.06.18
관계형 DB의 트랜잭션(Transaction)  (2) 2025.05.25
[데이터베이스] InnoDB 스토리지 엔진 아키텍처 딥다이브  (3) 2024.10.17
[데이터베이스] MySQL 아키텍처  (2) 2024.10.17
[데이터베이스] 동시성 제어? 락? 2PL? 그게 뭔데  (0) 2024.10.10
'백엔드/DB' 카테고리의 다른 글
  • Spring Data Redis에서 Redis Pub/Sub 사용하기
  • 관계형 DB의 트랜잭션(Transaction)
  • [데이터베이스] InnoDB 스토리지 엔진 아키텍처 딥다이브
  • [데이터베이스] MySQL 아키텍처
천방지축 개발자
천방지축 개발자
기록용 블로그
    250x250
  • 천방지축 개발자
    KKanging
    천방지축 개발자
  • 전체
    오늘
    어제
    • 분류 전체보기 (127)
      • 백엔드 (32)
        • Spring framework (4)
        • SpringSecurity (6)
        • JPA (4)
        • DB (6)
        • Spring Cloud (2)
        • CI CD (0)
        • 아키텍처 & 패러다임 & 디자인 패턴 (6)
        • 시스템 설계 & 성능 개선 (4)
      • JAVA (10)
        • 언어 (3)
        • JVM (4)
      • cs (57)
        • 운영체제 (8)
        • 컴퓨터네트워크 (6)
        • 자료구조 (15)
        • 알고리즘 (8)
        • http (20)
      • 인공지능 (5)
        • Reinforcement Learning (5)
      • 기타 (9)
        • 백준 (2)
        • python (2)
        • 백준 장학금 (5)
      • 회고 (5)
        • 토덕-리팩터링 (2)
      • 아티클 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    heapq
    연결리스트 종류
    운영체제
    프로세스
    이분탐색이란
    강화학습
    JPA
    백준장학금
    자료구조
    posix
    연결리스트
    백준 장학금
    점근적 표기법
    완전이진트리
    MSA
    엔티티 그래프
    jpa n+1 문제
    spring
    멀티프로세서
    알고리즘
    SpringSecurity
    HTTP
    최소힙
    최대 힙
    AVL트리
    python
    스케줄링
    힙트리
    JVM
    Kruskal
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
천방지축 개발자
Redis의 영속화 뜯어보기 (+docker 환경에서 Redis 세팅 법)
상단으로

티스토리툴바