본문 바로가기
Database , Middleware/Redis

[Redis] Redis 와 RDB, AOF 대해 알아보자

by 방배킹 2024. 10. 22.

가상 면접 사례로 배우는 대규모 시스템 설계 기초 를 읽고 스터디를 진행하면서 프로젝트를 진행하다

Redis에 대해 더 정리를 하게 되었습니다.



Redis

Redis는 메모리 기반의 키-값 저장소이다.

우리가 알고 있는 일반적인 데이터베이스와 다르게 인메모리 데이터베이스로 속도가 매우 빠르고

다양한 데이터 구조를 지원한다.

주요 특징

  • 속도: 인메모리 데이터베이스로 속도가 매우 빠르다. (디스크 I/O가 없다)
  • 데이터 구조: 다양한 데이터 구조를 지원한다.
  • 영속성: 메모리에 데이터가 저장되지만 디스크에 데이터를 주기적으로 저장을 해서 데이터의 손실을 방지한다.

Java에서 HashMap과 뭐가 다른걸까?

둘다 key-value 형식이며 메모리에 저장한다. 디스크보다 빨리 접근 할 수 있다.

 

redis의 장점이자 둘의 차이점은 아래와 같다.

redis의 경우 주기적으로 데이터를 디스크에 저장한다.

또한 분산 환경일 경우 HashMap은 프로세스간 데이터 동기화가 어렵지만

별도의 서버를 구성하고 redis를 사용하면 메모리 기반의 빠른속도와 동기화된 데이터를 사용할 수 있다.

 

 

Redis의 영속성

Redis는 인메모리 데이터베이스 이므로 서버를 껐다가 재시작을 하면 데이터는 당연히 휘발되어야한다.

하지만 Redis는 크게 RDB와 AOF를 통해 데이터를 디스크에 저장해 재시작시 메모리에 다시 로딩시킬수 있다.

RDB

RDB 방식은 특정한 간격으로 메모리에 있는 redis 데이터를 디스크에 저장하는 방식이다.

AOF

AOF는 명령이 실행 될때 마다 데이터를 파일에 기록하는 방식으로 데이터의 손실이 거의 없다.

 

RDB(snapshotting)

RDB 방식은 Redis의 데이터를 특정 시점에서 덤프하여 파일로 저장한다.

일반적으로 설정된 간격에 따라 자동으로 생성된다.

바이너리 파일로 저장되며 (.rdb) 확장자 형식으로 저장된다.

 

장점

  • 성능: 데이터를 덤프하는 과정이 단순하고 빨라 서버의 부하가 적다.
  • 백업 용이성: RDB 파일은 이진 형식으로 되어 있어 다른 Redis 인스턴스로 쉽게 복원 할 수 있습니다.
  • 공간 절약: RDF 파일은 보통 AOF 파일보다 작다.

단점

  • 데이터 손실 가능성: 설정된 간격에 따라 저장되기 때문에, 그 사이의 데이터는 손실될 수 있다.

RDB 방식은 RDBMS를 의미하는것이 아니라 메모리에 있는 내용을 스냅샷을 떠서 disk에 옮기고 생긴 파일의 확장자 이름이다.

AOF(Append only file)

AOF 방식은 Redis의 모든 쓰기 명령을 순차적으로 기록하여 파일로 저장합니다. 이를 통해 데이터 변경 이력을 완전하게 보존할 수 있다.

 

장점

  • 데이터 무결성: AOF는 모든 쓰기 명령을 기록하므로, 데이터 손실 위험이 적다.
  • 복원 용이성: AOF 파일을 통해 데이터 복원이 가능하며, 복원 시 가장 최신 상태로 복구할 수 있습니다.

단점

  • 성능 저하: 모든 쓰기 명령을 기록해야 하므로, 특히 높은 빈도의 쓰기 작업에서 성능에 영향을 줄 수 있다.
  • 파일 크기: AOF 파일은 시간이 지남에 따라 커질 수 있으며, 주기적으로 재작성해야 할 필요가 있다.(파일의 크기 축소를 위해)

정리

RDB 방식은 성능이 좋고 백업이 간편하지만 데이터 손실 위험이 있고,

AOF 방식은 데이터 무결성이 높지만 성능이 떨어질 수 있다.

 

더 자세히 알아보자...

RDB의 저장 방식

RDB의 저장 방식 에는 SAVE와 BESAVE 두 가지가 있다.

  • SAVE는 순차적으로 redis의 동작을 정지시키고 그 snapshot을 디스크에 저장한다. (blocking 방식)
  • BGSAVE는 백그라운드 SAVE 라는 의미로 별도의 자식 프로세스를 띄우고, 명령어 수행 당시의 snapshot을 디스크에 저장하고 redis는 동작을 멈추지 않고 계속 실행된다. (non-blocking 방식)

그러면 비동기적으로 실행하는 BGSAVE가 무조건 좋은건가?

BGSAVE의 동작 과정은 아래와 같다.

1. Child Process를  fork() 한다.

2. Child Process는 데이터를 새 RDB temp 파일에 쓴다.

3. 쓰기가 끝나면 기존 파일을 지우고 이름을 변경한다.

 

SAVE의 동작과정은 아래와 같다.

1. Main Process가 데이터를 새 RDB temp 파일에 쓴다.

2. 쓰기가 끝나면 기존 파일을 지우고, 새 파일로 교체를 한다.

 

BGSAVE 방식은 redis의 데이터를 비동기적으로 성능 저하 없이 스냅샷을 찍을 수 있어

무조건 좋다고 생각할 수 있지만 fork를 하기 때문에 메모리가 부족한 시스템에서 문제가 발생할수도 있다.

(부모 프로세스와 동일한 메모리 페이지를 복사해 일시적으로 메모리 사용량이 2배가 된다.)

또한 즉각적인 저장(서버가 종료되는 전에 저장을 하는)이 필요한 경우 SAVE와 같은 동기적인 처리가 더 적합하다.

 

BGSAVE는 redis의 성능을 유지하면서 데이터를 비동기적으로 저장하는 데 적합하지만,

데이터 손실 위험 메모리 사용량 증가, 즉각적인 저장 요구와같은 상황에서는 제약이 있을수 있다.

(데이터 손실 위험은 BGSAVE나 SAVE 모두 발생할 수 있다.)

 

redis.conf에 아래와 같이 저장 시점을 설정할 수 있다.

# redis.conf에 작섣되는 save 명령은 백그라운드에서 실행된다.

# save [Seconds] [Changes]
save 900 1 # 900초동안 적어도 1개의 데이터가 변경되면 RDB 파일을 생성한다.
save 300 10 # 300초동안 적어도 10개의 데이터가 변경되면 RDB 파일을 생성한다.
save 60 10000 # 60초동안 적어도 10000개의 데이터가 변경되면 RDB 파일을 생성한다.

 

만약  RDB를 저장하지 않으려면 redis.conf 파일의 save를 모두 지워주면 된다.

 

직접 SAVE 또는 BGSAVE 명령어를 통해 수동으로 명령을 실행 시킬 수 있다.

> save
> bgsave

 

AOF 저장 방식

AOF 방식은 redis의 모든 쓰기 작업( 입력, 수정, 삭제 명령)이 실행 될때 마다 해당 내용을 log 파일에 기록한다.

( 모든 write 작업을 기록, 조회는 X )

RDS 처럼 데이터 백업을 주기적인 배치로서 수핼하는 것이 아닌, redis에 쓰기 요청이 들러올때 마다 append한다.

1000번의 쓰기 작업이 발생하면 1000개의 로그 파일이 저장된다.

AOF는 실시간으로 기록되기 때문에 서버 장애가 발생한다면 로그 파일에 기록된 쓰기 작업을 따라해 복구하면된다.

 

그러면 데이터 유실 걱정이 없는 AOF 방식이 무조건 좋은건가?

만약 더하기 작업이 1000번 발생했다고 가정을 하자 이때 AOF 방식을 통해 로그를 읽어와 데이터를 복구한다면

로그를 확인해 1000번의 더하기 작업을 실행해야한다.

하지만 RDB 방식의 경우 1000의 값이 저장되어 있을것이다. 즉 AOF 방식을 사용하면 불필요하게(?) 1000번의 쓰기 작업을 해야하는것이다.

또한 RBD 방식 보다 저장된 파일의 크기도 크고, 서버의 자원도 많이 잡아먹는다.

 

RDB는 바이너리 파일 이므로 수정이 불가능하지만, AOF는 text 파일이라 수정이 가능하다.

 

이러한 단점을 보완하기 위해 AOF에는 rewrite 기능이 있다.

Rewrite의 목적은 다음과 같다.

 

1. 파일 크기 감소

2. 성능 최적화

3. 불필요한 명령 제거

 

redis.conf를 통해 AOF 설정을 할수 있다.

# appendonly 설정을 yes로 변경
appendonly yes

 

또한 redis.conf에서 aof의 주기를 설정할 수있다.

# 모든 쓰기 작업시 fsync( ) 사용
appendfsync always

# 매 초 마다 fsync( )를 호출
appendfsync everysec

# fsync()를 사용하지 않음
appendfsync no

 

always는 모든 쓰기 적업에 대해 fsync()를 호출해서 데이터를 디스크에 즉시 기록한다. 안정성은 매우 높지만 속도가 매우 느리다.

everysec은 매초 마다 호출한다. 충분히 빠른 속도이며 서버가 다운되더라도 1초의 데이터 손실 밖에 일어나지 않는다.

no는 fsync()를 호출하지 않는다. 속도는 제일 빠르지만 안정성이 비교적 낮다. 일반적으로 리눅스는 30초에 한번씩 데이터를 flush한다.

 

일반적으로는 everysec를 추천한다고 한다!

 

fsync()가 뭔가요?

fsync()는 파일 시스템의 특정 파일에 대한 변경 사항을 디스크에 강제로 기록하는 시스템 호출이다.

 

작동방식

  • 버퍼링: 일반적으로 운영 체제는 파일에 대한 쓰기 작업을 메모리의 버퍼에 먼저 기록한다. 이때, 실제 디스크에는 즉시 기록되지 않는다. 이렇게 하면 성능이 향상되지만, 시스템 장애나 전원이 꺼질 경우 데이터 손실이 발생할 수 있다.
  • fsync() 호출: fsync()를 호출하면, 버퍼에 있는 데이터를 디스크에 저장한다.

 

 

마찬가지로 redis.conf를 통해 rewrite 관련 설정을 할 수 있다.

# AOF 파일 이름 설정
appendfilename "appendonly.aof"

# AOF 파일의 크기가 100MB를 초과할 때 rewrite 실행
# 100MB 이하면 rewrite 안함
# 파일이 작을때 너무 자주 rewrite 하는걸 방지
auto-aof-rewrite-min-size 100mb

# AOF 파일이 기존 파일의 100% 이상 증가할 때 rewrite 실행
# AOF 파일 사이즈가 특정 퍼센트 이상 커지면 rewrite 한다.
# 비교 기준은 레디스 서버가 시작한 시점의 AOF파일 사이즈이다.
# 0으로 설정하면 rewrite를 하지 않는다
auto-aof-rewrite-percentage 100

 

어떤 방식을 사용해야 할까?

Redis의 공식문서에서는 RDB와 AOF 방식을 잘 섞어서 사용하라고 권장하고 있다.

몇분의 데이터 손실은 감수 할 수 있다면 RDB 방식만 사용해도 괜찮다.

AOF만 단독으로 사용하는 것은 좋지 않다. 주기적으로 RDB 방식으로 스냅샷을 찍는것은 좋은 방식이기 때문이다.( 빠른 실행과 AOF 버그를 방지을 위해 )

 

AOF 사용시 주의할점

또한 위에서 언급했던 내용인데, 만약 RDB를 BGSAVE 명령어를 통해 background에서 작업을 수행할 경우

Copy-on-Write 방식으로 진행되면 메모리가 2배가 필요하게 되는데

서버 메모리가 10GB 고 redis의 메모리가 6GB 라면 BGSAVE시 2배인 12GB가 필요하게 되는데 이때 swap이 발생해 서비스의 지연이 발생할 수 있다.

 

사용 예시

1. RDB 설정

save 900 1   # 900초(15분)마다 1개의 키 변경 시 저장
save 300 10  # 300초(5분)마다 10개 키 변경 시 저장
save 60 10000 # 60초(1분)마다 10,000개 키 변경 시 저장

 

2. AOF 설정

appendonly yes
appendfsync everysec # 매 초마다 AOF에 동기화

 

3. AOF 자동화 설정

auto-aof-rewrite-min-size 64mb  # 최소 크기 설정
auto-aof-rewrite-percentage 100  # AOF 파일 크기가 100% 커지면 재작성

 

위와 같이 설정을 하고 서버를 재시작하고 테스트를 해보자

 

Reference

https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/

 

Redis persistence

How Redis writes data to disk

redis.io

'Database , Middleware > Redis' 카테고리의 다른 글

[Redis] Redis를 이용한 실시간 조회수 관리  (0) 2024.12.14

댓글