Redis RDB와 AOF는 무엇을 어떻게 지키는가

seonwoo_jung·2026년 6월 1일

1. 도입

지난번에 Redis 자료구조별 시간복잡도를 정리하면서 "이 인메모리 구조가 디스크에는 어떻게 내려갈까"를 다음 숙제로 적어뒀다. Redis는 기본적으로 메모리에 데이터를 들고 있는데, 그렇다면 프로세스가 죽거나 서버가 재부팅되면 데이터는 어떻게 되는가? 캐시로만 쓰면 날아가도 그만이지만, 세션 저장소나 가벼운 영속 저장소로 쓰는 순간 "재시작 후 데이터가 살아있는가"가 중요해진다.

Redis는 이를 위해 두 가지 영속화(persistence) 방식을 제공한다. RDB(스냅샷)AOF(append-only file)다. 이름만 보면 둘 중 하나를 고르는 문제 같지만, 실제로는 트레이드오프가 다른 두 메커니즘이고 함께 켤 수도 있다. 이 글은 두 방식이 각각 무엇을 디스크에 남기는지, 내부적으로 어떤 흐름으로 동작하는지, 그리고 어떤 기준으로 선택하면 되는지를 공식 docs(Redis Persistence 페이지)를 따라가며 정리한 노트다.

이 글은 Redis 7.x 기준으로 정리했다. 버전마다 기본값과 세부 동작이 조금씩 달라서, 확신이 약한 부분은 공식 docs 인용으로 처리했다.

2. 핵심 개념: 스냅샷 vs 연산 로그

두 방식의 본질적인 차이는 "무엇을 저장하는가"에 있다.

  • RDB는 특정 시점의 메모리 상태 전체를 하나의 바이너리 파일(dump.rdb)로 떠서 저장한다. 사진을 찍듯이 그 순간의 데이터셋 스냅샷을 남기는 방식이다.
  • AOF는 데이터를 바꾸는 쓰기 명령(write command)을 순서대로 기록한다. SET, LPUSH, INCR 같은 명령을 로그처럼 차곡차곡 append 하고, 재시작 시 이 명령들을 처음부터 다시 실행해서 상태를 복원한다.

비유하자면 RDB는 "현재 잔액을 통째로 적어둔 장부 사진"이고, AOF는 "입금/출금 거래 내역을 다 적은 원장"이다. 사진은 가볍지만 마지막으로 찍은 이후의 변화는 모른다. 거래 내역은 무거워지지만 모든 변화를 복원할 수 있다.

구분RDBAOF
저장 형태메모리 전체 스냅샷(바이너리)쓰기 명령의 순차 로그
파일 크기작고 조밀상대적으로 큼
복구 속도빠름(바로 로드)느림(명령 재실행)
데이터 유실 위험마지막 스냅샷 이후분설정에 따라 최대 1초 안팎
디스크 I/O 부담주기적, 한 번에지속적, 분산

3. 내부 동작

3.1 RDB — fork와 copy-on-write

RDB 스냅샷은 어떻게 메인 스레드를 멈추지 않고 메모리 전체를 디스크에 쓸까? 핵심은 fork() 다.

SAVE 명령은 메인 프로세스가 직접 스냅샷을 쓰지만 그동안 모든 요청이 멈추므로 운영에서는 거의 쓰지 않는다. 실제로 쓰는 건 BGSAVE다. 흐름을 따라가 보면:

1. 부모(메인) 프로세스가 fork()로 자식 프로세스를 만든다.
2. 자식은 그 순간의 메모리를 보고 dump.rdb를 디스크에 쓴다.
3. 부모는 그동안 계속 클라이언트 요청을 처리한다.
4. 자식이 다 쓰면 임시 파일을 기존 rdb 파일로 원자적 교체(rename).

여기서 "fork 했는데 부모가 데이터를 계속 바꾸면 자식이 보는 메모리도 바뀌는 것 아닌가?"라는 의문이 든다. 이를 막는 게 OS의 copy-on-write(CoW) 다. fork 직후 부모와 자식은 같은 물리 메모리 페이지를 공유하다가, 부모가 어떤 페이지를 수정하려 하면 그때 그 페이지만 복사된다. 덕분에 자식은 fork 시점의 일관된 데이터를 본다고 공식 docs에 설명돼 있다.

단점도 여기서 나온다. 스냅샷 도중 쓰기가 많으면 CoW로 복사되는 페이지가 늘어 순간적으로 메모리 사용량이 최대 2배 가까이 튈 수 있다. fork 자체도 데이터셋이 크면 페이지 테이블 복제 때문에 지연을 만든다고 알려져 있다.

스냅샷 트리거는 redis.confsave 지시어로 정한다.

save 3600 1      # 3600초 동안 1개 이상 변경되면 저장
save 300 100     # 300초 동안 100개 이상 변경되면 저장
save 60 10000    # 60초 동안 10000개 이상 변경되면 저장

3.2 AOF — 버퍼, fsync, 그리고 rewrite

AOF는 쓰기 명령을 받을 때마다 곧장 디스크에 직접 쓰는 게 아니다. 먼저 AOF 버퍼에 명령을 쌓고, 일정 시점에 OS에 write() 한 뒤 fsync()로 디스크에 실제로 내린다. 여기서 "언제 fsync 하느냐"가 데이터 안정성과 성능의 트레이드오프를 결정한다. 이게 appendfsync 설정이다.

정책동작유실 위험성능
always쓰기마다 fsync거의 없음가장 느림
everysec1초에 한 번 fsync최대 약 1초분균형(기본값)
noOS에 맡김OS 버퍼 비울 때까지가장 빠름

공식 docs는 대부분의 경우 everysec를 권장한다고 적고 있다. 최악의 경우라도 1초어치 데이터만 잃는 선에서 성능을 확보하는 절충안이다.

또 하나 중요한 게 AOF rewrite다. 같은 키에 INCR를 1000번 하면 AOF에는 1000줄이 쌓이지만, 최종 상태는 SET key 1000 한 줄로 표현할 수 있다. 파일이 무한정 커지는 걸 막기 위해 Redis는 주기적으로 현재 메모리 상태를 재구성하는 최소 명령 집합으로 AOF를 다시 쓴다. 이 rewrite도 RDB처럼 자식 프로세스를 fork 해서 백그라운드로 진행한다.

auto-aof-rewrite-percentage 100   # 직전 rewrite 대비 100% 커지면 재작성
auto-aof-rewrite-min-size 64mb    # 단, 최소 이 크기는 넘어야 트리거

자주 헷갈리는 지점: AOF rewrite는 기존 로그를 "압축"하는 게 아니라, 현재 데이터셋을 만들어내는 새 명령 시퀀스를 처음부터 다시 생성하는 것이다. 과거 명령을 줄이는 게 아니라 결과만 같은 더 짧은 길을 새로 적는 셈이다.

4. 둘을 함께 쓰기 — 그리고 복구 우선순위

RDB와 AOF는 양자택일이 아니다. 둘 다 켜면 RDB의 빠른 복구와 AOF의 낮은 유실량을 함께 가져갈 수 있다.

여기서 핵심 동작 하나: 둘 다 활성화된 상태로 재시작하면 Redis는 AOF를 우선해서 로드한다. AOF가 일반적으로 더 최신 상태를 담고 있기 때문이라고 공식 docs가 설명한다.

Redis 7부터는 multi-part AOF가 도입됐다고 알려져 있다. AOF가 base 파일(RDB 포맷 스냅샷)과 incremental 파일(이후 명령 로그)로 나뉘어, rewrite 시 베이스를 RDB 형태로 저장하고 그 위에 증분만 쌓는다. 덕분에 "스냅샷의 조밀함 + 로그의 안전함"을 한 메커니즘 안에서 결합한다.

간단한 운영 시나리오를 코드로 그려보면 이렇다.

# 영속성을 최대로: AOF + everysec, RDB도 백업용으로 유지
appendonly yes
appendfsync everysec
save 3600 1 300 100   # RDB 스냅샷도 병행

# 수동 스냅샷 한 번 떠서 백업 보관
redis-cli BGSAVE
# 마지막 저장 시각(유닉스 타임) 확인
redis-cli LASTSAVE

캐시 전용이라 데이터가 날아가도 무방하다면 둘 다 꺼서(save "", appendonly no) fork/디스크 비용을 아예 없애는 선택도 합리적이다. 영속성은 "켜는 게 항상 옳은" 게 아니라 용도에 따른 트레이드오프다.

5. 정리

RDB는 "그 순간의 사진", AOF는 "변경의 일기". 빠른 복구는 RDB, 적은 유실은 AOF, 그리고 보통은 둘을 함께 켠다.

이번에 정리하며 가장 또렷해진 건 세 가지다. 첫째, RDB의 백그라운드 저장은 fork() + copy-on-write라는 OS 기능에 기대고 있고, 그래서 쓰기가 많을 때 메모리가 튀는 비용이 따라온다는 것. 둘째, AOF의 안정성은 결국 appendfsync 정책 하나로 압축되며 everysec가 현실적 기본값이라는 것. 셋째, 둘을 함께 쓰면 복구 시 AOF가 우선되고, Redis 7의 multi-part AOF는 두 방식의 장점을 한 곳에 모으려는 시도라는 것이다.

다음에 더 파고들 만한 주제를 적어둔다.

  • listpack의 실제 바이트 레이아웃 — 연속 메모리 인코딩이 메모리를 아끼는 구체적 방식
  • Redis replication과 PSYNC — RDB 스냅샷이 복제 초기 동기화에서 어떻게 쓰이는가

참고 자료

0개의 댓글