- Redis는 데이터를 메모리에 들고 있다. 프로세스가 죽으면 그대로 사라지므로, 디스크에 남겨 재시작 후 복원하는 장치가 필요하다. 이것이 **지속성(persistence)**이다.
- 방식은 두 가지다.
- RDB(Redis Database): 특정 시점의 데이터 전체를 파일 하나로 덤프하는 스냅샷.
- AOF(Append Only File): 데이터를 바꾼 쓰기 명령을 순서대로 기록한 로그. 재시작 시 로그를 재생해 상태를 복원한다.
- 둘은 배타적이지 않다. 동시에 켤 수 있고, 데이터를 중요하게 다룬다면 그게 권장 구성이다.
RDB: 스냅샷#
- 어느 순간의 데이터셋 전체를
dump.rdb라는 바이너리 파일 하나로 저장한다. - 언제 저장할지는
save <초> <변경 키 수> 형식의 save point로 정한다. 조건을 만족하면 자동으로 스냅샷을 뜬다.
dir /data
dbfilename dump.rdb
save 900 1 # 900초 동안 1개 이상 변경되면 저장
save 300 10
save 60 10000 # 60초 동안 10000개 이상 변경되면 저장
save ""로 지정하면 자동 스냅샷이 완전히 꺼진다.- 수동으로 뜨려면
BGSAVE를 쓴다. SAVE도 있지만 메인 스레드를 블로킹하므로 운영 중에는 쓰지 않는다.
동작 방식#
- Redis가
fork()로 자식 프로세스를 만든다. - 자식이 임시 파일에 데이터셋을 쓰고, 다 쓰면 기존
dump.rdb를 원자적으로 교체(rename)한다. - 부모 프로세스는 디스크 I/O를 전혀 하지 않고 계속 클라이언트 요청을 처리한다. copy-on-write 덕분에 메모리 복사도 변경된 페이지만 발생한다.
- 완성된 RDB 파일은 그 이후 수정되지 않으므로, 서버가 돌아가는 중에 그냥 복사해도 안전하다. 백업이 쉬운 이유다.
장단점#
- 장점
- 단일 파일이라 컴팩트하다. 시간별·일별로 보관하거나 S3·원격지로 옮기기 좋아 백업과 재해 복구에 적합하다.
- 부모 프로세스가 디스크 작업을 하지 않아 성능 영향이 작다.
- 데이터셋이 클 때 AOF보다 재시작 로딩이 빠르다.
- 단점
- 마지막 스냅샷 이후의 쓰기는 전부 사라진다. 5분 간격으로 뜬다면 최대 5분치 유실을 각오해야 한다.
- 데이터셋이 크면
fork() 자체가 수십 밀리초~1초까지 걸려 순간적으로 응답이 멈출 수 있다.
AOF: 명령 로그#
- 데이터를 변경하는 명령(
SET, DEL, LPUSH 등)을 받을 때마다 파일 끝에 덧붙인다. 형식은 Redis 프로토콜(RESP) 그대로라 사람이 읽을 수 있다. - 재시작하면 이 로그를 처음부터 재생해서 메모리 상태를 복원한다.
appendonly yes
appendfsync everysec
appendfsync - 내구성의 핵심 손잡이#
- 파일에 쓴다고 곧바로 디스크에 안착하는 게 아니다. OS 버퍼에 머무르므로
fsync를 언제 호출하는지가 실제 유실 범위를 결정한다.
| 값 | 동작 | 최대 유실 | 성능 |
|---|
always | 명령 배치마다 fsync | 사실상 없음 | 매우 느림 |
everysec | 1초마다 fsync (기본·권장) | 1초 | 스냅샷과 비슷 |
no | OS에 맡김 | 리눅스 기준 약 30초 | 가장 빠름 |
everysec은 fsync를 백그라운드 스레드에서 수행하고, 메인 스레드는 fsync가 진행 중이 아닐 때 쓰기를 몰아서 처리한다. 그래서 기본값으로 쓸 만하다.always도 그룹 커밋을 지원해, 동시에 들어온 여러 쓰기를 한 번의 fsync로 묶는다.
로그 재작성(rewrite)#
- 카운터를 100번 증가시키면 최종 값은 하나지만 AOF에는 100줄이 쌓인다. 이대로 두면 파일이 무한정 커진다.
- 그래서 Redis는 현재 데이터셋을 만드는 최소 명령 집합으로 로그를 다시 쓴다. 이것이 rewrite다.
- 자동 트리거는
auto-aof-rewrite-percentage(직전 rewrite 대비 증가율)와 auto-aof-rewrite-min-size로 조절하고, 수동으로는 BGREWRITEAOF를 호출한다. - rewrite 중에도 기존 파일에 계속 append하다가 새 파일이 완성되면 교체하므로, 도중에 실패해도 안전하다.
Redis 7.0의 multi-part AOF#
- 7.0부터 AOF가 파일 하나가 아니다.
appenddirname 디렉터리(기본 appendonlydir) 안에 세 종류가 들어간다.- base 파일: rewrite 시점의 스냅샷. 기본 설정에서는 RDB 포맷으로 저장된다(
aof-use-rdb-preamble yes). - incr 파일: base 이후의 증분 명령 로그. 여러 개일 수 있다.
- manifest 파일: 어떤 base와 incr가 유효한지 추적하는 목록.
- 로딩할 때는 base를 읽고 incr를 이어서 재생한다. base가 RDB 포맷이라 순수 명령 로그보다 로딩이 빠르다.
- 백업할 때 파일 하나만 챙기면 안 되고 디렉터리 전체를 떠야 한다는 뜻이기도 하다.
장단점#
- 장점
appendfsync 정책으로 내구성 수준을 고를 수 있다. 기본값에서도 유실이 1초로 제한된다.- append-only라 디스크 seek이 없고, 전원이 나가도 파일 중간이 깨질 일이 거의 없다. 끝이 잘려도
redis-check-aof로 고칠 수 있다. - 텍스트라 사람이 읽고 편집할 수 있다.
FLUSHALL을 실수로 날렸어도 rewrite가 아직 안 일어났다면, 서버를 멈추고 마지막 줄을 지운 뒤 재시작해 복구할 수 있다.
- 단점
- 같은 데이터셋 기준 RDB보다 파일이 크다.
always로 두면 눈에 띄게 느려진다.
둘을 같이 쓰면#
- AOF와 RDB를 모두 켜는 것이 기본 권장 구성이다. PostgreSQL 수준의 데이터 안전성을 원한다면 그렇게 한다.
- 재시작 시에는 AOF를 우선 로드한다. 더 완전한 상태를 담고 있다고 보장되기 때문이다.
- AOF 단독은 권장되지 않는다. RDB 스냅샷은 백업·빠른 재시작·AOF 엔진 버그에 대한 보험 역할을 한다.
- Redis는 RDB 스냅샷과 AOF rewrite가 동시에 돌지 않도록 조정한다. 무거운 디스크 I/O가 겹치는 것을 막기 위해서다.
| RDB | AOF |
|---|
| 저장 단위 | 시점 스냅샷 | 쓰기 명령 로그 |
| 유실 범위 | 마지막 스냅샷 이후 전부 | appendfsync에 따라 0~30초 |
| 파일 크기 | 작다 | 크다 |
| 재시작 속도 | 빠르다 | 상대적으로 느리다 |
| 백업 적합성 | 높다 (단일 파일 복사) | 낮다 (디렉터리 + rewrite 고려) |
| 성능 영향 | fork 순간 지연 | fsync 정책에 비례 |
운영 중 확인과 전환#
- 현재 상태 확인은
INFO persistence로 한다. 주요 필드는 다음과 같다.rdb_last_save_time, rdb_last_bgsave_status: 마지막 스냅샷 시각과 성공 여부.aof_enabled, aof_last_write_status, aof_last_bgrewrite_status: AOF 활성화 여부와 마지막 쓰기·rewrite 결과.loading: 1이면 아직 디스크에서 읽어들이는 중이다.
- 운영 중인 서버에 AOF를 켤 때는 절차를 지켜야 한다. 설정 파일만 고치고 재시작하면 데이터가 날아간다.
redis-cli config set appendonly yes
redis-cli config rewrite # 설정 파일에 반영. 빠뜨리면 재시작 시 원복되어 유실된다
- 재시작 전에
INFO persistence에서 aof_rewrite_in_progress와 aof_rewrite_scheduled가 0이고 aof_last_bgrewrite_status가 ok인지 확인한다. stop-writes-on-bgsave-error yes(기본값)면 스냅샷이 실패한 뒤 Redis가 쓰기를 전부 거부한다. 디스크가 가득 찼을 때 갑자기 쓰기가 막히는 원인이 대개 이것이다.
지속성만으로 안 되는 경우#
- 클러스터·복제 환경에서는 지속성이 켜져 있어도 데이터가 사라질 수 있다. failover가 일어난 뒤 복귀한 옛 마스터는 replica로 강등되면서 디스크에서 복원한 데이터를 버리기 때문이다.
- 자세한 내용은 Redis 클러스터 노드 재시작 시 데이터 유실 막기 참고.
참고 자료#