본문 바로가기
개발/DB

[Redis] Redis Cluster의 기초

by 달사쿠 2022. 6. 21.
728x90
반응형

Redis

 

6/21

 

Redis HA Design - Seninel vs Cluster

Redis Cluster를 사용하는 이유

Redis는 다양한 Client들에 대한 요청을 동시에, 빠르게 처리해야 한다.

Redis는 In-Memory 데이터 스토어기 때문에 물리적인 경합이 없음.

근데 왜 Redis에 장애가 날까? event loop 방식으로 처리가 되어있음

-> 병렬로 동작하지 않고 main thread에서 event loop 방식으로 순차적으로 처리가 되고 있음

-> Redis는 Mulitp Process나 Tread가 아닌 Single Thread에서 요청들을 순차적으로 선행으로 실행 (Event loop 처리)

-> 메모리에서 처리되는 빠른 업무로 단일처리로써 문맥교환없이 빠르게 처리하기 위해 Single Thread를 사용

-> 즉, Redis는 Single Thread(Main Thread)로 기본적으로 처리

- Redis는 Client들의 요청을 처리하기 위해 Non-Blocking I/O로서 I/O Multiplexing Module를 적극 활용

- Redis는 ae라이브러리를 구현해서 각 OS에 적합한 함수 I/O를 지원 (select, epoll, kqueue)

 

? Redis도 다른 Database나 Software처럼 Multi Thread로 처리하면 어떻게 될까?

- Redis는 특징적인 이유가 있어서 싱글 스레드로 동작하는게 더 효율적이다.

1. Redis에서 병목현상은 CPU가 아닌, 메모리나 네트워크에서 발생 (Redis특성상 CPU의 처리보단 Memory에 대한 처리/할당, 네트워크 대역폭에서 발생하기 때문, CPU의 병렬의 필요성을 느끼지 못함)

2. Event Loop 패턴을 통해 동시성을 구현, Context-Switch 없이 데이터 처리 가능

3. 공통의 데이터를 조작할 때 Atomic을 보장하기 위해서 별도의 복잡한 메커니즘이나 프로그램 구현이 필요하지 않다.

(싱글 스레드기 때문에 Atomic이 보장)

 

빠른 단일처리를 빠르게 리턴하는 것이 목적이기 때문에, 싱글 스레드의 장점을 살려 활용되고, 순차적으로 처리하고 있다.

 

Redis Mulithread I.O (a.k.a Redis 6.0)

- redis 6.0부터 부분적으로 multithread(Threaded I/O) 도입

- Threaded I/O가 개입할 수 있는 부분: Network전송, 특정 Read 작업, 그 외의 background 처리가 가능한 작업

- Redis의 주요처리에 대해서는 복잡성을 피하기 위해 Atomic이 보장되는 Single Thread로 유지할 계획

 

Single Thread의 장점은 명백하지만, 제약을 해결하기 위해서는?

동시에 여러일이 들어왔을 때 경합하지 않고 대기해서 순차적으로 처리

 

Database에서 한계를 극복하기 위한 방법?

- Scale Up

- Scale Out (Redis 채택)

 

- Redis의 Key가 굉장히 크다면 -> Thread에서 사용되는 시간이 길다. 

- 같은 이유로 부담이 되는 큰 작업들에 대해서도 많은 Client들에게 Delay를 줄 수 있다.

(keys, hgetall, 지나치게 큰 transaction 등에 취약하다)

- 싱글스레드이기 때문에 경합에 취약하고, 그렇기 때문에 단일처리를 빠르게 처리할 수 있도록 구성해야 함

- Multi Thread를 사용하는 대신, Redis는 인스턴스 수를 늘리는 것을 선택 (Scale Out)

-> Client 입장에서 데이터를 분산 저장될 수 있도록 Sharding 로직이 필요

 

- Redis Cluster는 Redis Side에서 sharding이 되어있어 Client의 여러 요청을 자동으로 분산 처리할 수 있는 형태로 구성되어 있다.

- Redis Cluster의 장점: 잘 분산된다면 성증적으로 이점이 있다. (1대의 redis로 5sec가 걸리는 것을 redis cluster로 1sec가 걸리도록 처리)

 

- Redis Cluster의 특징

1. 최대 1천대 까지 선형적으로 확장 가능하여, 여러 Task를 분산처리 가능

(하지만 무작정 1천대까지 연결하면 네트워크 비용도 들기 때문에, 어느 크기가 되면 cluster 단위로 다시 쪼개서 client입장에서 샤딩해서 쓰는 것이 더 낫다)

2. App과 Redis, 그리고 각 노드끼리도 Proxy가 없음, 중계를 따로 두지 않아 성능적으로 우수 (pull mashed 구조, 나를 제외한 n-1개의 노드들과 통신하고 있음)

3. Single Redis와 거의 동일한 Key Command 구현 가능

 

-> Redis 자체는 born to be single thread

-> 빠른 단일처리는 빠르게 처리가능하기 때문에

-> single thread는 동시에 많은 일이 되었을 때 문제가 된다.

-> 이걸 분산해서 여러 instance들이 나누어서 처리하면 더 빠른 처리가 가능

-> 더불어 redis cluster내부에서 sharing까지 제공하기 때문에 쉽게 사용 가능

 

Redis Cluster 구성

- Redis Cluster는 노드들끼리 교류하기 위해서 Redis cluster bus를 통해 ping - poing packet (Heartbeat packet)으로 통신

- ping-pong packet에는 많은 헤더들이 있음

  - Node ID, hash slots info, Epoch(current config), ...

- Redis Cluster 내부적으로 Node ID를 통해 서로를 식별하며, 각 노드들은 서로 정보를 비교하면서 통신하면서, 노드들의 구성정보를 최신 정보로 업데이트 => 결론적으로 cluster내의 모든 redis가 일원화된 최신의 정보로 업데이트 됨

(A가 B를 알고 A가 C를 알면 B는 C에게 gossip protocol을 통해 업데이트)

 

Redis Cluster Spec

- Redis Cluster는 Full mesh 통신 구조로 지속적인 ㅇ통신으로 최신 구성 정보를 일원화하여 보유

- CLUSTER NODES 또는 CLUSTER SLOTS 명령어로 노드들이 어떤 구성으로 이루어져있는지 확인 가능 (Cluster Info.)

- Redis Cluster는 16384개의 slot에 key들이 저장된다. (key들이 저장되는 공간의 단위를 slot이라 하며, 각 key들은 crc16함수를 이용해 계산된 slot에 저장)

- 이런 데이터들을 보관하고 있는 hash slot들은 어떤 cluster 구성이던지 16384개로 구성되어 있다.

- 16384개의 slot들은 각각의 master node들에 분배된다 (ex. 3개의 redis면 5461개 slot씩 분배)

- slot내의 key 충돌에 대해서 성능 저하는 고려하고 있지 않다.

 

6/22

총 16384개의 slot들은 각각의 'Master Node'들에 분배 된다.

HASH_SLOT을 계산하는 공식: CRC16(Key) mod 16384

 

Clients가 Cluster Nod나 Cluster Slots를 활용한 Map Table에 대한 정보가 최신화가 안된 경우엔 어떻게 될까?

- Master Node에서 해당 slot이 없을 때, client로 moved Error를 반환하고 Client는 map table는 moved error에 포함된 위치로 redirection을 해서 이동된 위치의 master node를 찾아감

 

Moved Redirction: Refresh Map Table

- Client에서 moved redirection이 발생하면, map table의 전체를 갱신하는 것을 권장

  - 대부분 구성 정보가 변경되는 이유는 노드 추가, 삭제, failover 등 여러 slot들이 한번에 변경되는 이슈

  - cluster nodes 명령어로 전체 refresh (전체 갱신 작업은 간단하기에 굳이 특정 변경만 update하는게 비효율적)

  - 대부분의 library에서는 리즈너블한 라이브러리면 slot 이동에 대해서도 대응이 되어있음

 

- Moved Redirection: Lettuce

  - Lettuce는 버전에 따라 topology refresh의 관련 옵션(map table을 갱신)이 defalut로 false가 되어있는 경우가 있다.

  - map table은 항상 무조건적으로 최신 상태일 필요는 없지만, 어느 주기로 update를 시켜주는 것이 좋을지는 서비스 특성마다 고려하도록 한다.

  - moved redirection을 잘 처리하고, 주기적으로 config정보를 잘 refresh하는 것 등을 잘 확인하는 것이 필요 (# help_verda에 어떤 옵션처리를 하면 좋은지 적혀있으니 참고)

 

- Ask Redirection

  - Slot이 이동되고 있는 경우에는 moved redirection 대신, asking command를 선행하고 다른 노드로 Query를 전달한다.

 

- Hash Tags: Redis Cluster에 동일한 slot에 key들을 보관할 수 있다.

  - hash tags를 이용해서 {user1000}.xxx 과 같이 표현해서 같은 master node에서 관리할 수 있다.

 

key 분산은 crc16 공식으로 분산시키고,

slot의 위치는 client에서 map table을 만들어서 위치를 파악한다

hash tags를 이용해서 동일한 slot에 여러 key들을 보관할 수 있다.

 

Redis Cluster는 운영 중, 기본적으로 중단없이 노드를 늘리거나 줄일 수 있다.

- Master node를 늘리면, slot들을 새로운 node로 나눠줌

- 삭제하면 가지고 있던 slot을 다른 node로 나눠주고 삭제됨

 

Redis Cluster Reshard

- add, remove, rebalance 등의 작업은 slot의 이동을 이용한 작업

- Slot 이동은 아래 순서대로 수행된다. 

1. cluster setslot importing

2. cluster setslot migrating

3. cluster getkeysinslot

4. migrate

5. cluster setslot node

 

single thread가 atomic하게 동작이 이루어짐 (dump -> restore -> delete)

- 요청은 master1, 처리는 master2 (delete가 될때까지 기다림.)

- 다른 slot들에 대한 처리도 atomic하기 때문에 처리할 때까지 대기를 하고 있음.

- key사이즈가 크면 오래걸려서 좋지 않음 (경우에 따라 장애가 날 수 있음) 권장하는 key사이즈는 1mb 이하 (최대한 key는 간결하게 사용)

- 설계단위에서 key를 잘 설계하는 것이 중요 (add sharding이 제대로 안되면 slot에 big key가 있는지 확인. memory usage 같은 것 확인)

- ask와 moved에 대한 구분을 잘 하기로! (key에 대한 사이즈는 value 사이즈 - Q. resharding 때 map, set 등 key 에 대한 value 사이즈가 커도 문제가 되는걸까요?)

 

Redis Cluster Fault Tolerance

 

Redis HA Configuration

- Redis Cluster에서 Majority는 Master Node를 기준으로 한다. 

만약 각서버에 마스터나 슬레이브를 몰아넣는 경우,

- Master노드가 절반이 죽으면 과반수가 죽었기 때문에 투표를 하지못해 fail over 처리를 못하고 교착상태에 빠진다 (서버가 살아날 때 까지 기다림).
majority에 도달하지 못했기 때문에

- fail over 이후 서버가 돌아오면 manual failover를 이용해 이전 구성으로 바꿔준다.

 

cluster failover(manual failover)는 선거를 하라는 동작 그 이상이 아니다.

cluster failover takeover는 선거없이 master노드로 바꿔버림

 

- 서버가 충분히 늘어나면 그냥 하나의 장비에 마스터나 슬래이브를 몰아넣기도 한다. (관리면에서 지그재그로 관리하는 것 보다 편리)

728x90
반응형

댓글