Redis 와 Memcached 를 가장 크게 구분짓는 특징은 무엇일까요?
간단하게는 아래와 같은 특징들이 있는데

  • Key-Value 만 지원하는 Memcached 에 비해 Key-value , list , hash , set , sorted set 다양한 자료구조를 지원
  • Redis의 데이터를 디스크로 저장하는 Persistent 기능

이번 글에서는 그 중에서도 data 영속성에 대해 다뤄보겠습니다.

RDB

Redis 인스턴스의 현재 메모리에 대한 dump (스냅샷) 를 생성하는 기능

RDB 설정

save ""
#save 900 1
#save 300 10
#save 60 10000

rdbchecksum yes
stop-writes-on-bgsave-error no
rdbcompression yes

dbfilename redis_6001.rdb
  • save : save seconds changes 의 형태
    • save 900 1 => 900초 안에 1번 이상의 변경이 생기면 RDB 생성하겠다는 의미
    • save “” => 자동으로 RDB를 생성하지 않고 수동으로 bgsave , save 커맨드를 통해 생성하겠다는 의미
    • bgsave : RDB 생성 작업을 backgroundd process 로 수행
    • save : redis의 single thread로 RDB 생성작업을 수행하기 때문에 다른 모든 작업이 대기하게됨
  • rdbchecksum : rdb 파일이 정상적으로 저장되었는지 checksum 을 파일의 끝에 넣는 옵션
  • stop-writes-on-bgsave-error : RDB 저장이 실패하는 경우 write blocking 하는 기능으로 read 는 가능함
    • 디스크 여유공간이 없을 때
    • RDB 생성 중 메모리 부족으로 작업 실패
    • 기타 등등의 이유로 실패함
127.0.0.1:6379> bgsave
102:M 08 Mar 2020 06:11:07.159 * Background saving started by pid 125
Background saving started
127.0.0.1:6379> 125:C 08 Mar 2020 06:11:07.160 # Failed opening the RDB file dump.rdb (in server root dir unknown) for saving: No such file or directory
102:M 08 Mar 2020 06:11:07.220 # Background saving error


127.0.0.1:6379>
127.0.0.1:6379> set a 1
    
(error) MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

=> RDB 작업 실패로 write blocking 된 현상

  • rdbcompression : rdb dump파일 압축 여부, 압축 알고리즘은 LZF
  • dbfilename : rdb dump파일의 이름 설정

RDB 관련 info 조회

127.0.0.1:6379> info persistence
# Persistence
loading:0
rdb_changes_since_last_save:1
rdb_bgsave_in_progress:0
rdb_last_save_time:1583647845
rdb_last_bgsave_status:err
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:180224

=> 마지막 RDB 작업 성공 여부, 걸린 시간 등을 파악할 수 있음

RDB 주의할 점

save 커맨드 수행 시엔 조심 !!

  • save 는 single thread로 수행하기 때문에 작업이 완료되기 까지 모든 요청이 대기하게됨
  • bgsave 커맨드로 background 자식 프로세스를 통해 RDB 작업 수행하도록 할 것

bgsave 커맨드 수행 시엔 memory 사용률 조심!!

  • redis 서비스에서 사용중인 데이터는 모두 메모리 위에 있는데 이를 “서비스 영향 없이” 스냅샷으로 저장하기 위해서는 Copy-on-Write(COW) 방식을 사용함
    자식 프로세스 fork() 후 부모 프로세스의 메모리에서 실제로 변경이 발생한 부분만 복사하게 되는데
    write 작업이 많아서 부모 페이지 전부에 변경이 발생하게 되면 부모 페이지 전부를 복사하게 됨

  • 서버 physical memory 10GB, redis memory 6GB 사용하는 서비스에서 RDB 수행 중 COW 발생하여 메모리 두배가 필요하여 2GB 부족한 상황이 되면 swap 이 발생하여 서비스 지연이 발생하게 되므로redis의 max-memory 설정을 주의깊게 할 것!!

  • save 는 redis process가 직접 수행하여 COW 발생하지 않음

AOF

AOF (Append Only File) 는 redis 에서 데이터 변경이 일어나는 커맨드를 AOF 파일에 기록하는 방식
RDBMS WAL (Write Ahead Logging) 처럼 아래와 같은 순서로 동작함

  • client 가 redis로 데이터 변경 관련 (조회 제외 insert,update,delete) 요청
  • Redis 는 해당 command 를 AOF buffer 에 저장함
  • redis memory의 내용 변경
  • appendfsync 설정에 따라 AOF buffer의 내용을 AOF 파일로 내려씀

AOF 설정

appendonly no
appendfsync no

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

appendfilename redis_appendonly_6001.aof
  • appendonly : AOF 기능 사용 여부
  • appendfsync : AOF buffer 의 내용을 AOF file로 내려쓰는 주기 설정
    • always : update 관련 커맨드 마다 fsync 호출하여 AOF 로 내려씀, redis 성능을 지연시킬 수 있음
    • everysec : 매초마다 fsync, 성능 지연은 없으나 1초의 데이터가 유실될 수 있음
    • no : OS에 맡김
  • auto-aof-rewrite-percentage : AOF 파일 다시 쓰는 시점 설정하는 옵션으로 100으로 설정시 이전 AOF파일의 크기 100% 도달 시 다시쓰기 수행
    • AOF 는 데이터 변경 관련 커맨드를 모두 로깅하기 때문에 과거의 데이터 변경 관련 커맨드도 갖고 있어 redis 메모리의 데이터보다도 커질 수 있음
    • bgrewriteaof 커맨드를 통해 수행되며 bg, background로 수행되기 때문에 마찬가지로 COW 발생
  • auto-aof-rewrite-min-size : redis 처음 시작 후 AOF 파일 사이즈가 0일 때 auto-aof-rewrite-percentage 대신 적용됨, ex) AOF 파일 64MB되면 다시쓰기
  • appendfilename : AOF 파일 이름 설정

AOF 관련 info 조회

aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:200704
aof_current_size:152
aof_base_size:102
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
  • aof_base_size , aof_current_size 를 비교하여 aof_current_size가 auto-aof-rewrite-percentage 이상 되면 bgrewriteaof 수행

AOF 와 RDB 무엇을 먼저 읽을까?

  • redis config 상 appendonly yes => AOF 파일 읽음
  • appendonly no => rdb 파일 읽음
void loadDataFromDisk(void) {
    long long start = ustime();
    if (server.aof_state == AOF_ON) {
        if (loadAppendOnlyFile(server.aof_filename) == C_OK)
            serverLog(LL_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000);
    } else {
        rdbSaveInfo rsi = RDB_SAVE_INFO_INIT;
        if (rdbLoad(server.rdb_filename,&rsi) == C_OK) {
            serverLog(LL_NOTICE,"DB loaded from disk: %.3f seconds",
                (float)(ustime()-start)/1000000);

=> redis source code를 보면 AOF on 일 땐 AOF 파일을, off 일 땐 RDB을 읽음
그러나 AOF on 인데 AOF 파일이 없다고 RDB파일을 읽진 않으며 반대도 마찬가지임