From 9b82c3f067a9e9841bb7ea7e6178655d335bb62d Mon Sep 17 00:00:00 2001 From: JunSik Sim Date: Sun, 7 Jan 2024 19:52:51 +0900 Subject: [PATCH 1/2] add persistence.md --- redis/week06/junsik/persistence.md | 97 ++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 redis/week06/junsik/persistence.md diff --git a/redis/week06/junsik/persistence.md b/redis/week06/junsik/persistence.md new file mode 100644 index 0000000..3a2e68e --- /dev/null +++ b/redis/week06/junsik/persistence.md @@ -0,0 +1,97 @@ +- 지속성은 SSD(Solid State Disk)와 같은 `내구성 있는 스토리지에 데이터를 쓰는 것을 의미` + - `RDB` (Redis 데이터베이스): RDB 지속성은 지정된 간격으로 데이터 세트의 특정 시점 스냅샷을 수행 + - `AOF` (Append Only File): AOF 지속성은 서버에서 수신한 모든 쓰기 작업을 기록. 그런 다음 서버 시작 시 이러한 작업을 다시 재생하여 원래 데이터 세트를 재구성. 명령은 Redis 프로토콜 자체와 동일한 형식을 사용하여 기록 + - `No persistence` : 지속성을 완전히 비활성화. 캐싱할 때 가끔 사용 + - `RDB + AOF` : 동일한 인스턴스에서 AOF와 RDB를 결합 + +# RDB 장점 +- RDB 파일은 `백업에 적합`. 예를 들어, 최근 24시간 동안 매시간 RDB 파일을 보관하고 30일 동안 매일 RDB 스냅샷을 저장할 수 있음. 이를 통해 재해 발생 시 `다양한 버전의 데이터 세트를 쉽게 복원 가능` +- RDB는 원거리 데이터 센터나 Amazon S3(암호화 가능)로 전송할 수 있는 단일 압축 파일이므로 재해 복구에 매우 용이 +- Redis 상위 프로세스가 지속하기 위해 수행해야 하는 유일한 작업은 나머지 모든 작업을 수행할 하위 프로세스를 포크하는 것이므로 RDB는 Redis 성능을 극대화. 상위 프로세스는 디스크 I/O 등을 수행하지 않음 +- RDB는 AOF에 비해 대규모 데이터 세트로 더 빠르게 다시 시작 가능 +- 복제본에서 RDB는 재시작 및 장애 조치 후 부분 재동기화 지원 + +# RDB 단점 +- 일반적으로 RDB 스냅샷은 5분 이상마다 생성되므로 어떤 이유로든 Redis가 올바른 종료 없이 작동을 중지하는 경우 `최신 데이터가 손실될 수 있음` +- RDB는 하위 프로세스를 사용하여 디스크에 지속되기 위해 자주 fork()해야 합니다. 포크()는 데이터 세트가 큰 경우 시간이 많이 걸릴 수 있으며, 데이터 세트가 매우 크고 CPU 성능이 좋지 않은 경우 Redis가 몇 밀리초 동안 또는 심지어 1초 동안 클라이언트 서비스 제공을 중지할 수도 있음 + +# AOF 장점 +- AOF를 사용하면 Redis가 훨씬 더 `안정적` +- 다양한 fsync 정책을 설정할 수 있음 +- fsync는 백그라운드 스레드를 사용하여 수행되며, 메인 스레드는 fsync가 진행 중이지 않을 때 쓰기를 수행하려고 시도하므로, `최대 1초 분량의 쓰기만 손실될 수 있음` +- AOF 로그는 추가 전용 로그이므로, 전원 중단이 발생해도 탐색이나 손상 문제가 없음 +- 어떤 이유로 로그가 반쯤 작성된 명령어로 끝나더라도 (디스크가 가득 차거나 기타 이유로) redis-check-aof 도구를 사용하여 쉽게 수정 가능 +- Redis는 AOF가 너무 커지면 백그라운드에서 자동으로 AOF를 다시 작성할 수 있음. 다시 작성하는 과정은 완전히 안전 + +# AOF 단점 +- AOF 파일은 일반적으로 동일한 데이터 세트에 대해 `RBD 파일보다 크기가 큼` +- 정확한 fsync 정책에 따라 AOF는 RDB보다 느릴 수 있음 + +# 그래서 어떤 걸 사용하는게 좋을까? +- 데이터 안전성에 있어 `PostgreSQL이 제공할 수 있는 수준에 가까운 것`을 원한다면, `두 가지 지속성 방법을 모두 사용하는 것이 일반적`인 지침 +- 데이터를 매우 중요하게 생각하지만, 재난 발생 시 몇 분간의 데이터 손실은 감수할 수 있다면, 단독으로 RDB만 사용해도 ok +- `AOF만을 사용`하는 많은 사용자들이 있지만, 데이터베이스 백업을 위해, 더 빠른 재시작을 위해, 그리고 AOF 엔진의 버그 발생 시를 대비하여 가끔씩 RDB 스냅샷을 가지는 것이 좋은 아이디어이므로, `권장하지 않음` + +# 스냅샷 +- 기본적으로 Redis는 `데이터 세트의 스냅샷을 dump.rdb라는 이진 파일로 디스크에 저장` +- 데이터 세트에서 최소 M개의 변경이 있을 경우 N초마다 데이터 세트를 저장하도록 Redis를 구성할 수 있으며, SAVE 또는 BGSAVE 명령을 수동으로 호출 가능 +- ## 작동원리 + - Redis 포크. 이제 부모 프로세스와 자식 프로세스 존재 + - 자식 프로세스가 임시 RDB 파일에 데이터 세트를 쓰기 시작 + - 자식 프로세스가 새 RDB 파일 작성을 마치면, 이 파일이 이전 파일을 대체 + +# AOF +- ## Log rewriting + - Rewriting 은 `완전히 안전`. Redis가 이전 파일에 계속 추가하는 동안, 현재 데이터 세트를 생성하는 데 필요한 최소한의 작업 세트로 완전히 새로운 파일이 생성되며, 이 두 번째 파일이 준비되면 Redis는 두 파일을 교체하고 새 파일에 추가하기 시작 + +- ## How durable is the append only file? + - appendfsync `always`: AOF에 새 명령이 추가될 때마다 fsync를 수행. `매우 느리지만 매우 안전`. 명령어들은 여러 클라이언트의 일련의 명령이나 파이프라인이 실행된 후 AOF에 추가되므로, 이는 단일 쓰기와 단일 fsync를 의미 + - appendfsync `everysec`: 매초 fsync를 수행. 충분히 빠르며(버전 2.4부터 스냅샷 방식만큼 빠를 가능성이 높음), 재난이 발생하면 1초 분량의 데이터를 잃을 수 있음 + - appendfsync `no`: fsync를 전혀 수행하지 않고, 데이터를 운영 체제에 맡김. `가장 빠르지만 가장 안전하지 않은 방법`. 커널의 튜닝에 달려 있음 + - 권장되고 기본적으로 설정된 정책은 `매초 fsync를 수행`. 이는 빠르면서도 상대적으로 안전. always 정책은 실제로 매우 느리지만, 그룹 커밋을 지원하므로 Redis는 여러 병렬 쓰기가 있을 경우 단일 fsync 작업을 수행하려고 시도 + +- ## What should I do if my AOF gets truncated? + - Redis의 최신 주요 버전들은 어쨌든 AOF를 로드할 수 있으며, `파일에서 마지막으로 형식에 맞지 않는 명령어를 단순히 무시` + - 기본 구성을 변경하여 이러한 경우에 Redis가 중단되도록 강제할 수 있지만, 파일의 마지막 명령어가 형식에 맞지 않더라도 재시작 후 가용성을 보장하기 위함 + +- ## What should I do if my AOF gets corrupted? + - AOF 파일이 단순히 잘린 것이 아니라, 중간에 유효하지 않은 바이트 시퀀스로 인해 손상된 경우, 상황은 더 복잡. Redis는 시작 시 이를 감지하고 중단 + - 가장 좋은 방법은 `redis-check-aof 유틸리티를 실행`하는 것. 처음에는 --fix 옵션 없이 실행한 다음 문제를 이해하고, 파일에서 지정된 오프셋으로 이동하여 파일을 수동으로 수리할 수 있는지 확인. AOF는 Redis 프로토콜과 동일한 형식을 사용하므로 수동으로 수정하기가 비교적 간단. 그렇지 않은 경우 유틸리티를 사용하여 파일을 수정할 수 있지만, 그 경우에는 손상된 부분부터 파일 끝까지의 모든 AOF 부분이 버려질 수 있으며, 손상이 파일의 초기 부분에서 발생했다면 대량의 데이터 손실로 이어질 수 있음 + +- ## 작동원리 + - Redis >= 7.0 + - Redis 포크 + - 자식 프로세스가 임시 파일에 새로운 기본 AOF를 작성하기 시작 + - 부모 프로세스는 `새로운 증분 AOF 파일을 열어 업데이트를 계속 작성`. 다시 작성이 실패하더라도, 기존의 기본 및 증분 파일(있는 경우)과 이 새로 열린 증분 파일은 완전히 업데이트된 데이터 세트를 나타내므로 안전 + - 자식 프로세스가 기본 파일의 다시 작성을 마치면, 부모 프로세스는 신호를 받고, 새로 열린 증분 파일과 자식 프로세스가 생성한 기본 파일을 사용하여 임시 매니페스트를 구축하고 영구적으로 저장 + - 이제 Redis는 매니페스트 파일을 원자적으로 교체하여 이 AOF rewriting 의 결과가 적용. Redis는 또한 오래된 기본 파일과 사용되지 않는 증분 파일을 정리 + + - Redis < 7.0 + - Redis 포크 + - 자식 프로세스가 임시 파일에 새로운 기본 AOF를 작성하기 시작 + - 부모 프로세스는 `모든 새로운 변경 사항을 메모리 버퍼에 누적`. 하지만 동시에 이전 추가 전용 파일에 새로운 변경 사항을 작성하므로, 다시 작성이 실패해도 안전 + - 자식 프로세스가 파일의 다시 작성을 마치면, 부모 프로세스는 신호를 받고, 자식 프로세스가 생성한 파일 끝에 메모리 버퍼를 추가 + - 이제 Redis는 새 파일을 이전 파일로 원자적으로 이름을 변경하고, 새 파일에 새로운 데이터를 추가하기 시작 + +- ## How I can switch to AOF, if I'm currently using dump.rdb snapshots? + - RDB 스냅샷을 사용 중인 서버에서 AOF를 활성화하려면, 라이브 서버에서 CONFIG 명령을 통해 AOF를 활성화하여 데이터를 변환해야 함 + - 중요: 이 절차를 따르지 않고 (예: 설정만 변경하고 서버를 재시작하는 경우) 데이터 손실이 발생할 수 있음 + +- ## Interactions between AOF and RDB persistence + - Redis >= 2.4는 RDB 스냅샷 작업이 이미 진행 중일 때 AOF 다시 작성을 트리거하지 않도록 하며, AOF 다시 작성이 진행 중일 때 BGSAVE를 허용하지 않음. 이는 `두 Redis 백그라운드 프로세스가 동시에 무거운 디스크 I/O를 수행하는 것을 방지` + +- ## Backing up Redis data + - 서버에 크론 작업을 생성하여 한 디렉토리에 시간별 RDB 파일 스냅샷을 만들고, 다른 디렉토리에 일일 스냅샷 생성 + - 크론 스크립트가 실행될 때마다 find 명령을 호출하여 너무 오래된 스냅샷이 삭제되는지 확인. 예를 들어, 최근 48시간 동안의 시간별 스냅샷과 한두 달 동안의 일일 스냅샷을 취할 수 있음. 스냅샷에 날짜와 시간 정보를 포함하여 이름을 지정 + - 하루에 최소 한 번은 `데이터 센터 밖으로`, 또는 적어도 Redis 인스턴스를 실행하는 물리적 기계 밖으로 RDB 스냅샷을 전송하는 것을 확실히 할 것 + +- ## Backing up AOF persistence + - automatic rewrites `비활성화` + - 현재 rewriting 이 진행 중인지 확인 + - 여기서 aof_rewrite_in_progress가 0인지 확인. 1이면 다시 작성이 완료될 때까지 대기 + - 이제 appenddirname 디렉토리의 파일들을 안전하게 복사할 수 있음 + - 완료되면 다시 작성을 다시 활성화 + +- ## Disaster recovery + - Amazon S3 및 유사 서비스: Amazon S3와 같은 서비스는 재난 복구 시스템을 구현하는 좋은 방법. 매일 또는 매시간 RDB 스냅샷을 암호화된 형태로 S3로 전송 + - SCP를 사용한 스냅샷 전송: SCP(SSH의 일부)를 사용하여 먼 서버로 스냅샷을 전송하는 것은 간단하고 안전한 방법 \ No newline at end of file From 350c2d9719dabf27f01b48975fe1ee40aeb2e889 Mon Sep 17 00:00:00 2001 From: JunSik Sim Date: Sun, 7 Jan 2024 19:53:04 +0900 Subject: [PATCH 2/2] add scale_with_redis_cluster.md --- .../week06/junsik/scale_with_redis_cluster.md | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 redis/week06/junsik/scale_with_redis_cluster.md diff --git a/redis/week06/junsik/scale_with_redis_cluster.md b/redis/week06/junsik/scale_with_redis_cluster.md new file mode 100644 index 0000000..aaa08ab --- /dev/null +++ b/redis/week06/junsik/scale_with_redis_cluster.md @@ -0,0 +1,59 @@ +- Redis는 Redis Cluster 라는 배포 토폴로지를 통해 수평적으로 확장 + +# Redis Cluster 101 +- 데이터 세트를 `여러 노드에 자동으로 분할` +- 노드의 하위 집합에 오류가 발생하거나 클러스터의 나머지 부분과 통신할 수 없는 경우에도 작업 지속 + +- ## Redis 클러스터 TCP 포트 + - 모든 Redis 클러스터 노드에는 `두 개의 개방형 TCP 연결이 필요` + - Redis TCP 포트, 클러스터 버스 포트 + - `클러스터 버스`는 바이너리 프로토콜을 사용하는 노드 간 통신 채널, 대역폭과 처리 시간이 적기 때문에 `노드 간 정보 교환에 더 적합` + - `클라이언트`는 클러스터 버스 포트와 통신을 시도해서는 안 되며 대신 `Redis 명령 포트를 사용해야 함` + +- ## Redis 클러스터 및 Docker + - 현재 Redis 클러스터는 NAT 환경이나 IP 주소나 TCP 포트가 재매핑되는 환경을 지원하지 않음 + - Docker는 포트 매핑이라는 기술을 사용. Docker 컨테이너 내부에서 실행되는 프로그램은 프로그램이 사용하고 있다고 생각하는 포트와 다른 포트로 노출될 수 있음. 이는 동일한 서버에서 동일한 포트를 사용하는 여러 컨테이너를 동시에 실행하는 데 유용 + - Docker를 Redis 클러스터와 호환되게 하려면, Docker의 호스트 네트워킹 모드를 사용해야 함 + +- ## Redis 클러스터 데이터 샤딩 + - Redis 클러스터는 일관된 해싱을 사용하지 않지만 모든 키가 개념적으로 해시 슬롯 이라고 부르는 것의 일부인 다른 형태의 샤딩을 사용 + - Redis 클러스터에는 16384개의 해시 슬롯 존재 + - 키 모듈로 16384의 CRC16을 사용 + - 키의 {} 대괄호 사이에 하위 문자열이 있는 경우 문자열 내부에 있는 내용만 해시 + ``` + user:{123}:profile 과 user:{123}:account 는 동일한 해시 태그를 공유하므로 동일한 해시 슬롯에 있음이 보장 + ``` + +- ## Redis 클러스터 마스터-복제본 모델 + - 마스터 노드의 하위 집합에 장애가 발생하거나 대부분의 노드와 통신할 수 없는 경우에도 계속 사용할 수 있도록 Redis 클러스터는 모든 해시 슬롯에 1개(마스터 자체)부터 N개의 복제본(N-1)이 있는 마스터-복제본 모델을 사용 + +- ## Redis 클러스터 일관성 보장 + - Redis 클러스터는 `강력한 일관성을 보장하지 않음` + - 기본적으로 `비동기 복제 사용` + ``` + 클라이언트가 마스터 B에 씀 + 마스터 B는 고객에게 OK라고 응답 + 마스터 B는 복제본 B1, B2 및 B3에 쓰기 전파 + + B는 클라이언트에 응답하기 전에 B1, B2, B3의 승인을 기다리지 않음 + ``` + - Redis 클러스터는 꼭 필요한 경우 명령을 통해 구현되는 동기식 쓰기를 지원하지만, 동기식이어도 일관성 보장 안됨 + +# Redis Cluster configuration parameters +- Cluster-enabled`` + - Redis 클러스터 활성화 +- Cluster-config-file`` + - Redis 클러스터 노드가 변경될 때마다 자동으로 클러스터 구성(기본적으로 상태)을 유지하는 파일 +- Cluster-node-timeout`` + - 지정된 시간 이상 마스터 노드에 연결할 수 없으면 해당 복제본에 의해 장애 조치 +- Cluster-slave-validity-factor`` + - 0 으로 설정되면 복제본은 항상 자신이 유효한 것으로 간주하므로 마스터와 복제본 사이의 링크가 연결 해제된 시간에 관계없이 항상 마스터 장애 조치를 시도 + - 노드 시간 초과가 5초로 설정되고 유효성 계수가 10으로 설정된 경우 50초 이상 마스터에서 연결이 끊어진 복제본은 마스터 장애 조치를 시도하지 않음 +- Cluster-migration-barrier`` + - 마스터가 다른 복제본이 더 이상 어떤 복제본에도 포함되지 않는 마스터로 이동할 수 있도록 연결을 유지할 최소 복제본 수 +- Cluster-require-full-coverage`` + - `yes` 로 설정되어 있으면, 키 공간의 일부가 어떤 노드에도 포함되지 않는 경우 클러스터는 쓰기 작업을 수락하지 않음 + - `no` 로 설정된 경우, 클러스터는 키의 일부분에 대한 요청만 처리할 수 있더라도 여전히 쿼리를 처리 +- Cluster-allow-reads-when-down`` + - `yes` 로 설정하면 실패 상태 동안 노드에서 읽기를 허용 + - `no` 로 설정되면 Redis 클러스터의 노드는 클러스터가 실패로 표시되거나 노드가 도달할 수 없을 때 모든 트래픽 제공을 중지 \ No newline at end of file