
In-memory Database는 메모리에 데이터를 적재하여 활용하는 데이터베이스 시스템을 의미한다. 표준 디스크 드라이브(SSD)에 액세스할 필요가 없으므로 응답 시간을 최소화할 수 있다.
주 메모리 데이터베이스(MMDB), 인 메모리 데이터베이스 시스템(IMDS), 실시간 데이터베이스 시스템(RTDB)이라는 용어도 인 메모리 데이터베이스를 가리킨다.
분당 바이트 수 , 초당 트랜잭션 수)을 제공Redis는 String, List, Set, Hash 등의 다양한 데이터 타입을 제공
CPU는 연산처리를 진행하고,Memory는 CPU가 주로 활용하는 주요 저장소이며,Disk는
영구 저장 가능한 보조 저장 매체이다.
- 연산 속도는
CPU > Memory > Disk의 순서로 오른쪽으로 갈 수록 느리다- 가격은
Disk > Memory > CPU의 순서로 오른쪽으로 갈 수록 비싸다
오픈 소스이기 때문에 Github Repository에서 내부 구현을 확인할 수 있다
Redis는 REmote DIctionary Server의 줄임말로 In-memory, Key-Value 형식의 데이터 저장을 지원하는 데이터베이스이다.
위에서도 언급했지만 Redis는 In-memory 데이터베이스이다. 그럼에도 불구하고 Persistent On Disk로 메모리에 있는 데이터를 디스크에 저장하여 운용할 수 있다. (가용성 및 백업을 위한 조치)
그래서 서버가 꺼진 후 다시 시작되더라도, Disk에 저장해놓은 데이터를 다시 읽어서 메모리에 로딩하기 때문에 데이터가 유실되지 않는다.
Redis에서는 데이터를 저장하는 방법으로 RDB와 AOF 두 가지 방식을 지원한다.
RDB는 Redis DataBase의 줄임말로 snapshot 방식을 의미한다. 좀 더 자세히 말하자면 특정 시점에 전체 데이터베이스를 디스크에 저장하는 방식을 의미한다. 이를 통해 문제가 발생했을 때 백업해놓은 데이터로 복구를 하게 되는 것이다. 이때 특정 시점은 시간 단위가 될 수도 있고, 일일 단위가 될 수도 있지만 텀이 길어질 수록 서비스 장애 발생 시 사라지는 데이터가 많아지게 된다.
하지만 snapshot 과정 자체가 process fork 기반으로 진행되기 때문에 메모리 사용량이 급증되어 모니터링을 할 필요가 있다.
Redis의 RDB snapshot이 process fork 기반으로 동작할 때 메모리 사용량이 급증하는 이유는 COW(Copy-On-Write) 메커니즘과 관련이 있다.
Redis가 RDB snapshot을 생성할 때, 메인 프로세스는 자식 프로세스를 생성한다. 이 과정에서 운영체제의 fork 호출을 통해 메인 프로세스의 메모리 페이지 테이블이 자식 프로세스로 복사하게 된다. 이때, 물리적으로 메모리를 복사하진 않지만 부모와 자식 프로세스가 동일한 메모리를 공유하게 된다.COW) 동작fork 이후, Redis는 쓰기 작업이 발생하면 Copy-On-Write 방식을 사용한다.snapshot을 생성하는 동안 데이터의 일관성을 유지하기 위함COW로 인해 다음과 같은 상황에서 메모리 사용량이 급격히 증가할 수 있다.Redis가 많은 쓰기 작업을 처리하는 경우, COW로 인해 복사되는 메모리 페이지의 양이 늘어나게 됨Redis 인스턴스에 저장된 데이터가 클수록 더 많은 메모리가 필요fork 과정 자체도 CPU 리소스를 많이 소모하며, 이로 인해 Redis의 응답 속도가 느려질 수 있다. 또한 COW로 인한 추가적인 메모리 요구는 시스템의 Swap 사용을 유발할 수 있으며 이는 Disk I/O 병목 현상을 초래하여 성능에 부정적인 영향을 미친다.장점
단점
Swap이 발생해 성능 저하가 일어날 수 있다Copy-On-Write의 자세한 예시와 설명은 이곳을 참조
AOF는 Append Only File의 줄임말로 데이터 쓰기 작업 명령어들을 적재하는 방식을 말한다.
Redis는 클라이언트로부터 받은 모든 쓰기 명령(SET, DEL, INCR ...)을 파일에 순서대로 기록한다. 이후 Redis 서버가 재시작되면 AOF 파일에 기록된 명령어를 재실행하여 데이터를 복구한다.
쉽게 말하면 모든 쓰기 명령을 로그 파일에 순차적으로 기록하는 방식이라고 볼 수 있다.
AOF 방식에 대해서 좀 더 자세히 설명하자면 AOF는 다음과 같은 단계를 통해 작동한다.
명령 기록
Redis는 클라이언트가 보낸 쓰기 명령을 AOF 파일에 추가한다.
```text
SET key1 value1
INCR counter
DEL key2
```
이런 명령들이 AOF 파일에 순서대로 기록된다.
동기화 (flush)
Redis는 설정된 정책(appendfsync)에 따라 AOF 파일을 디스크로 동기화한다.
always: 모든 쓰기 명령마다 디스크에 동기화 (가장 안전하지만 속도가 가장 느림)everysec: 1초마다 동기화 (default, 성능과 안전성의 균형)no: OS가 디스크로 데이터를 플러시하도록 맡김 (가장 빠르지만 데이터 손실 가능성 있음)재작성 (rewrite)
시간이 지나면서 AOF 파일이 커질 수 있다. Redis는 AOF 재작성 기능을 통해 오래된 명령을 압축하여 파일 크기를 줄인다.
```text
SET key1 value1
SET key1 value2
```
위 두개의 명령은 최종 상태만 반영하여 아래처럼 재작성된다.
```text
SET key1 value2
```
장점
RDB보다 더 자주 데이터를 기록할 수 있어 안전성이 높다AOF 파일은 사람이 읽을 수 있는 형식으로 저장되어 디버깅이 용이=재작성)하여 파일 크기를 줄일 수 있음단점
RDB보다 더 많은 디스크 공간이 필요하다Redis는 다양한 데이터 타입을 지원한다. 이때 저장되는 value에 대한 데이터 타입을 의미한다.
클라이언트로부터 전달받은 명령을 싱글 쓰레드로 처리한다.
외부로부터 동시에 여러 명령들을 전달받을 수는 있지만 실제 처리는 순차적으로 하나씩 진행된다. 또한 내부적으로 Lock을 사용하지 않아도 순차적으로 실행되기 때문에 원자적 실행이 가능하게 되고, 결과적으로 데이터의 일관성이 보장된다.
하지만 싱글 쓰레드이기 때문에 앞서 내린 명령들이 많은 시간을 잡아먹게 될 경우 뒤에 있는 명령들은 처리되지 않고 대기하게 된다. 이 경우 명령에 대한 응답 속도 지연으로 인해 때때로 서비스 장애로 이어지기 때문에 알고리즘 성능을 유의 깊게 봐야할 필요가 있다 (특히 O(N))
번외 1: Redis 6.0 이후
Redis 6.0 이후부턴 성능 향상을 위해Thread I/O가 도입되었다. 이는I/O부분에 별도의 다수 쓰레드들을 설정해서 사용하는 것으로 대표적으로Network I/O,병렬처리의 가능이 있다.헷갈리면 안되는 것이 그래도 실제 구조와 동작은 싱글 쓰레드로 동작한다는 것이고, 기존 싱글 쓰레드 명령 처리 부분에서 I/O로 지연이 일어나지 않도록 기능이 개선된 것이다.
번외 2: Redis 활용 사례
1. Cache
2. Session Store
3. Pub/Sub
4. Message Queue
5. Geospatial
6. Leader Board