TIL 12 | Redis 알아보기 (1)

dereck·2024년 12월 9일

TIL

목록 보기
12/21

In-memory Database

In-memory Database메모리에 데이터를 적재하여 활용하는 데이터베이스 시스템을 의미한다. 표준 디스크 드라이브(SSD)에 액세스할 필요가 없으므로 응답 시간을 최소화할 수 있다.

주 메모리 데이터베이스(MMDB), 인 메모리 데이터베이스 시스템(IMDS), 실시간 데이터베이스 시스템(RTDB)이라는 용어도 인 메모리 데이터베이스를 가리킨다.

주요 특징

  1. 디스크 대비 매우 빠른 응답 속도
    • 마이크로초의 읽기 지연 시간, 밀리초 단위의 쓰기 지연 시간이라는 빠른 응답 속도를 제공
    • 빠른 응답 속도 기반의 높은 처리량(분당 바이트 수 , 초당 트랜잭션 수)을 제공
  2. 휘발성 데이터
    • 메모리여서 시스템이 다운되면 데이터가 전부 유실될 가능성이 있다
    • 가용성 측면에서 충분한 고려가 필요하고, 백업을 잘해야 함
  3. 다양한 데이터 타입 제공
    • 데이터베이스에 따라 다르지만 RedisString, List, Set, Hash 등의 다양한 데이터 타입을 제공

CPU는 연산처리를 진행하고, Memory는 CPU가 주로 활용하는 주요 저장소이며, Disk
영구 저장 가능한 보조 저장 매체이다.

  • 연산 속도는 CPU > Memory > Disk의 순서로 오른쪽으로 갈 수록 느리다
  • 가격은 Disk > Memory > CPU의 순서로 오른쪽으로 갈 수록 비싸다

대표적인 오픈 소스

  1. Memcached
    • 분산 저장소
    • 단일 데이터 타입 제공
    • 대규모 캐시 데이터 저장 및 질의에 유용
  2. Redis
    • 분산 저장소
    • 다양한 자료 구조 제공
    • 캐시뿐만 아니라 세션 저장소, Pub/Sub, 리더보드, Geospatial 등에 다양하게 활용

오픈 소스이기 때문에 Github Repository에서 내부 구현을 확인할 수 있다

Redis

Redis 란?

RedisREmote DIctionary Server의 줄임말로 In-memory, Key-Value 형식의 데이터 저장을 지원하는 데이터베이스이다.

Persistent On Disk

위에서도 언급했지만 RedisIn-memory 데이터베이스이다. 그럼에도 불구하고 Persistent On Disk메모리에 있는 데이터를 디스크에 저장하여 운용할 수 있다. (가용성 및 백업을 위한 조치)

그래서 서버가 꺼진 후 다시 시작되더라도, Disk에 저장해놓은 데이터를 다시 읽어서 메모리에 로딩하기 때문에 데이터가 유실되지 않는다.

Redis에서는 데이터를 저장하는 방법으로 RDBAOF 두 가지 방식을 지원한다.

RDB

RDB는 Redis DataBase의 줄임말로 snapshot 방식을 의미한다. 좀 더 자세히 말하자면 특정 시점에 전체 데이터베이스를 디스크에 저장하는 방식을 의미한다. 이를 통해 문제가 발생했을 때 백업해놓은 데이터로 복구를 하게 되는 것이다. 이때 특정 시점은 시간 단위가 될 수도 있고, 일일 단위가 될 수도 있지만 텀이 길어질 수록 서비스 장애 발생 시 사라지는 데이터가 많아지게 된다.

하지만 snapshot 과정 자체가 process fork 기반으로 진행되기 때문에 메모리 사용량이 급증되어 모니터링을 할 필요가 있다.

RedisRDB snapshotprocess fork 기반으로 동작할 때 메모리 사용량이 급증하는 이유는 COW(Copy-On-Write) 메커니즘과 관련이 있다.

process fork 기반으로 동작하는 것이 메모리 사용률을 급증하게 하는 이유

  1. Process Fork와 메모리 복사
    RedisRDB snapshot을 생성할 때, 메인 프로세스는 자식 프로세스를 생성한다. 이 과정에서 운영체제의 fork 호출을 통해 메인 프로세스의 메모리 페이지 테이블이 자식 프로세스로 복사하게 된다. 이때, 물리적으로 메모리를 복사하진 않지만 부모와 자식 프로세스가 동일한 메모리를 공유하게 된다.
  2. Copy-On-Write(COW) 동작
    fork 이후, Redis는 쓰기 작업이 발생하면 Copy-On-Write 방식을 사용한다.
    • 부모 프로세스가 데이터를 수정하려고 하면, 기존 메모리를 직접 수정하지 않고 해당 해모리 페이지를 복사한 후 새롭게 수정
    • 자식 프로세스가 snapshot을 생성하는 동안 데이터의 일관성을 유지하기 위함
  3. 메모리 사용량 증가
    COW로 인해 다음과 같은 상황에서 메모리 사용량이 급격히 증가할 수 있다.
    • Redis많은 쓰기 작업을 처리하는 경우, COW로 인해 복사되는 메모리 페이지의 양이 늘어나게 됨
    • Redis 인스턴스에 저장된 데이터가 클수록 더 많은 메모리가 필요
    • 추가적인 복사 작업으로 인해 시스템의 가용 메모리가 부족하다면, 성능 저하나 장애가 발생할 가능성이 높아짐
  4. 성능 영향
    fork 과정 자체도 CPU 리소스를 많이 소모하며, 이로 인해 Redis의 응답 속도가 느려질 수 있다. 또한 COW로 인한 추가적인 메모리 요구는 시스템의 Swap 사용을 유발할 수 있으며 이는 Disk I/O 병목 현상을 초래하여 성능에 부정적인 영향을 미친다.

COW의 장단점

장점

  • 메모리 절약: 데이터가 변경되지 않는 한 동일한 메모리를 공유하여 낭비를 줄인다.
  • 성능 향상: 불필요한 데이터 복사를 방지해 처리 속도를 높인다.

단점

  • 쓰기 작업 증가 시 비용 증가: 쓰기 작업이 빈번하면 매번 데이터를 복사해야 하기 때문에 오히려 성능 저하가 발생할 수 있다
  • 충분한 여유 메모리 필요: 여유 메모리가 부족하면 Swap이 발생해 성능 저하가 일어날 수 있다

Copy-On-Write의 자세한 예시와 설명은 이곳을 참조

AOF

AOF는 Append Only File의 줄임말로 데이터 쓰기 작업 명령어들을 적재하는 방식을 말한다.

Redis는 클라이언트로부터 받은 모든 쓰기 명령(SET, DEL, INCR ...)을 파일에 순서대로 기록한다. 이후 Redis 서버가 재시작되면 AOF 파일에 기록된 명령어를 재실행하여 데이터를 복구한다.

쉽게 말하면 모든 쓰기 명령을 로그 파일에 순차적으로 기록하는 방식이라고 볼 수 있다.

AOF 방식에 대해서 좀 더 자세히 설명하자면 AOF는 다음과 같은 단계를 통해 작동한다.

  1. 명령 기록
    Redis는 클라이언트가 보낸 쓰기 명령을 AOF 파일에 추가한다.

    ```text
    SET key1 value1
    INCR counter
    DEL key2
    ```

    이런 명령들이 AOF 파일에 순서대로 기록된다.

  2. 동기화 (flush)
    Redis는 설정된 정책(appendfsync)에 따라 AOF 파일을 디스크로 동기화한다.

    • always: 모든 쓰기 명령마다 디스크에 동기화 (가장 안전하지만 속도가 가장 느림)
    • everysec: 1초마다 동기화 (default, 성능과 안전성의 균형)
    • no: OS가 디스크로 데이터를 플러시하도록 맡김 (가장 빠르지만 데이터 손실 가능성 있음)
  3. 재작성 (rewrite)
    시간이 지나면서 AOF 파일이 커질 수 있다. RedisAOF 재작성 기능을 통해 오래된 명령을 압축하여 파일 크기를 줄인다.

    ```text
    SET key1 value1
    SET key1 value2
    ```

    위 두개의 명령은 최종 상태만 반영하여 아래처럼 재작성된다.

    ```text
    SET key1 value2
    ```

AOF 장단점

장점

  • 데이터 손실 최소화: RDB보다 더 자주 데이터를 기록할 수 있어 안전성이 높다
  • 가독성: AOF 파일은 사람이 읽을 수 있는 형식으로 저장되어 디버깅이 용이
  • 압축 기능: 오래된 명령들을 압축(=재작성)하여 파일 크기를 줄일 수 있음

단점

  • 디스크 사용량 증가: 모든 쓰기 명령을 기록하므로 RDB보다 더 많은 디스크 공간이 필요하다
  • 복구 속도 느림: 서버 재시작 시 모든 명령을 다시 실행해야 하므로 시간이 오래 걸릴 수 있다
  • 쓰기 성능 저하: 빈번한 디스크 동기화로 인해 쓰기 작업의 성능이 낮아질 수 있다

데이터 타입

Redis는 다양한 데이터 타입을 지원한다. 이때 저장되는 value에 대한 데이터 타입을 의미한다.

Single Thread

클라이언트로부터 전달받은 명령을 싱글 쓰레드로 처리한다.

외부로부터 동시에 여러 명령들을 전달받을 수는 있지만 실제 처리는 순차적으로 하나씩 진행된다. 또한 내부적으로 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


References

0개의 댓글