왜 Redis 영속성이 문제가 되는가

Redis는 인메모리 저장소이므로 프로세스가 죽거나 서버가 재시작되면 데이터가 사라진다. 캐시 용도라면 상관없지만, 세션·랭킹·큐·카운터처럼 유실이 곤란한 데이터를 다룬다면 디스크 영속성이 필요하다. 이때 선택지가 RDB 스냅샷과 AOF(Append Only File)다. 둘의 트레이드오프를 모르면 "재시작했더니 최근 몇 분치가 날아갔다"거나 "AOF 리라이트 중 지연 스파이크가 발생했다" 같은 사고를 겪는다.

RDB와 AOF의 동작 원리

RDB는 특정 시점의 전체 데이터셋을 바이너리 파일로 덤프한다. fork()로 자식 프로세스를 만들어 스냅샷을 뜨므로 메인 스레드 영향이 적고, 복구가 빠르며 파일이 작다. 대신 스냅샷 간격 사이의 데이터는 유실된다.

AOF는 쓰기 명령을 로그로 순차 기록한다. appendfsync 정책에 따라 유실 창(window)이 결정되며, everysec이면 최대 1초치만 잃는다. 대신 파일이 커지고 복구 시 명령을 재실행하므로 로딩이 느리다.

정책별 비교

항목RDBAOF(everysec)
최대 유실스냅샷 간격만큼약 1초
복구 속도빠름느림(재실행)
파일 크기작음큼(리라이트로 압축)
런타임 부하fork 시 순간 부하지속적 쓰기 부하

권장 설정: 둘 다 켠다

실무 표준은 RDB와 AOF를 함께 쓰는 것이다. Redis 4.0+는 재시작 시 AOF가 있으면 AOF로 복구하되, AOF 리라이트 시 앞부분을 RDB 포맷으로 저장하는 혼합(hybrid) 모드를 지원한다. 로딩 속도와 유실 최소화를 모두 얻는다.

# redis.conf
save 900 1
save 300 10
save 60 10000

appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

운영 중 상태 점검

실제 유실 위험과 리라이트 상태는 INFO persistence로 확인한다. rdb_last_bgsave_status가 err이거나 aof_last_write_status가 실패면 즉시 조치해야 한다.

#!/bin/bash
# 영속성 헬스체크
redis-cli INFO persistence | grep -E \
  'rdb_last_bgsave_status|aof_last_write_status|aof_rewrite_in_progress|rdb_changes_since_last_save'

# 마지막 저장 이후 변경 건수가 크면 유실 위험 신호
CHANGES=$(redis-cli INFO persistence | awk -F: '/rdb_changes_since_last_save/{print $2+0}')
[ "$CHANGES" -gt 100000 ] && echo "WARN: unsaved changes=$CHANGES"

주의점: fork와 메모리, 디스크

RDB 스냅샷과 AOF 리라이트는 모두 fork()를 쓴다. Copy-on-Write 특성상 쓰기가 몰리면 물리 메모리가 최대 2배까지 늘 수 있으므로, maxmemory는 실제 RAM의 절반 수준으로 잡아 여유를 둔다. 또한 vm.overcommit_memory=1을 설정하지 않으면 fork가 실패해 저장 자체가 안 된다.

# 커널 설정 (fork 실패 방지)
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
sysctl -p

# THP는 지연 스파이크 유발 → 비활성화 권장
echo never > /sys/kernel/mm/transparent_hugepage/enabled

AOF everysec는 디스크가 느리면 fsync가 밀려 쓰기 지연으로 번진다. NVMe 같은 빠른 디스크를 쓰고, 백업 파일은 별도 볼륨이나 오브젝트 스토리지로 주기적으로 옮겨 로컬 디스크 장애에 대비한다.

결론: 데이터 성격으로 결정한다

순수 캐시라면 영속성을 꺼도 된다. 유실 시 재계산 비용이 큰 데이터라면 RDB만으로도 충분할 때가 많고, 유실을 초 단위로 줄여야 하는 데이터라면 AOF everysec를 더한 혼합 모드가 정답이다. 설정을 켰다는 사실보다, INFO persistence를 모니터링에 연결해 실제로 저장이 성공하고 있는지 지속 확인하는 것이 핵심이다.