서비스가 성장하면 레디스에 필요한 메모리가 커질 수 있다.
이때 scale-up을 통해 서버 스팩을 향상시킬 수 있지만. 단일 서버에서 메모리만 늘리게 되면 이를 처리할 능력에 한계가 오게 되며 CPU도 추가하게 될 것이다.
하지만 레디스는 단일 스레드 기반이기 때문에 CPU를 늘리더라도 이를 활용할 수 없다.
이러한 상황에서는 레디스를 클러스터로 구성해서 처리량을 늘려야 한다.
레디스는 애플리케이션 아키텍처의 변경 없이 여러 레디스 인스턴스간 수평확장이 가능하며, 데이터 분산 처리와 복제, 자동 페일오버 기능을 제공한다.
샤딩은 데이터베이스를 수평 확장하며 서버간 데이터를 분할하는 아키텍처 패턴을 말한다.
레디스의 경우 샤딩과 관련된 모든 메타데이터를 내부에 자체 관리하여 프록시 서버 등이 필요 없다.
따라서 어느 마스터 노드에 특정 데이터를 저장/조회 요청을 보내면 해당 데이터를 담당하는 노드로 자동으로 리다이렉션 시켜준다.
또한 레디스의 클러스터는 안정 해시 대신에 hash slot이라는 개념을 통해 키의 범위를 나눠 가진다.
Redis Cluster does not use consistent hashing, but a different form of sharding where every key is conceptually part of what we call a hash slot.
This makes it easy to add and remove cluster nodes. For example, if I want to add a new node D, I need to move some hash slots from nodes A, B, C to D. Similarly, if I want to remove node A from the cluster, I can just move the hash slots served by A to B and C. Once node A is empty, I can remove it from the cluster completely.
https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/
레디스 클러스터는 일반적으로 3개의 마스터, 복제본 노드를 가진다.
레디스 클러스터의 마스터에 장애가 발생하면 이를 다른 노드들이 인지하고 복제본 노드는 마스터 노드로 승격시킨다.(페일 오버)
레디스 클러스터는 독립적인 TCP 네트워크(클러스터 버스)를 생성하여 각 노드를 연결한다. 이는 모든 노드가 연결되는 풀 메쉬 토폴로지 형태다.
레디스 클러스터에서 각 마스터 노드들은 헤시슬롯을 나눠가진다.
레디스 클러스터에서 마스터 노드간 자유롭게 해시슬롯을 옮길 수 있다.
그러면 같은 범주의 데이터를 저장할 때는 어떻게 해야할까?
예를 들면 사용자의 정보를 저장할 때, 다음과 같이 저장할 수 있을거다
user:1234:profile
user:1234:account
…
하지만 해당 값들을 해싱하고 마스터노드에 저장될 때 서로 다른 노드에 저장될 수 있다. 이럴 경우 레디스 클러스터에서는 두 데이터를 동시에 조회할 수 없다.
그 이유는 해당 데이터들이 서로 다른 마스터 노드에 저장되고 각 노드로 리다이렉션해야 하지만 이를 동시에 처리할 수 없기 때문이다.
그렇다면 어떻게 처리해야할까?
레디스에서는 해시태그기능을 통해 특정 값에 대해서만 해싱을 적용하여 특정 마스터에 같이 저장되도록 할 수 있다.
해시태그는 {}을 통해서 적용할 수 있다. 앞선 예시에 적용해보면 다음과 같이 사용할 수 있다.
{user:1234}:profile
{user:1234}:account
하지만 해시태그를 사용할 때 해싱할 범위를 잘 조정해야한다. 만약 너무 좁은 범위로 해싱을 잡게 된다면 많은 데이터가 특정 마스터 노드에 저장될 수 있기 때문이다.
레디스 클러스터는 센티넬과 다르게 모든 노드가 서로를 감시한다.
레디스 클러스터를 사용할 때 발생하는 재구성은 다음과 같다.
마스터 노드에 장애가 발생한 경우 나머지 마스터 노드들의 투표를 통해 복제본 노드가 마스터 노드로 승격될지 결정한다.
복제본 마이그레이션의 경우 특정 마스터 노드에 연결된 복제본 노드가 하나 이상일때, 즉 잉여 노드가 존재할 때 해당 잉여 노드를 다른 노드로 마이그레이션하는것을 의미한다.
복제본 마이그레이션을 통해 마스터 노드에 장애가 발생해 페일 오버가 되는 상황에서 모든 마스터 노드가 하나 이상의 복제본 노드를 가짐을 보장해주는 방법이다.
레디스 클러스터에서는 기본적으로 데이터를 요청하면 해당 데이터를 가지는 마스터 노드로 리다이렉션시켜준다. 이때 레디스 클러스터에 읽기 부하가 심하다면 마스터 노드들만을 가지고 부하를 감당하기 힘들 수 있다.
레디스 클러스터에서는 READONLY 모드를 통해 클라이언트가 복제본 노드에 읽기 요청을 보낼 수 있도록할 수 있다.
레디스 클러스터 노드간 PING, PONG 패킷을 주고받는데, 두 패킷을 묶어 하트비트 패킷이라 한다.
하트비트 패킷을 통해 다른 노드에 대한 정보를 얻을 수 있으며, 장애 감지 또한 가능하다.
레디스 클러스터는 에포크(epoch)라는 값을 통해 노드간 구성의 정합성을 유지한다. 이는 클러스터의 상태를 변할 때와 페일오버가 발생할 때 동의를 구하기 위해 사용된다.
해시슬롯의 구성은 하트비트와 업데이트 메시지 두 방법을 통해 전파된다.
다른 노드들로부터 해시슬롯 구성을 전달받으면 노드 내의 해시슬롯 구성 정보를 업데이트한다.
해시슬롯 구성 정보는 각 해시값에 대해 소유권을 가지는 노드 정보를 저장한다.
레디스 클러스터에서는 다음과 같은 조건에서 복제본은 페일오버를 직접 시도한다.
위 조건을 만족한 경우 복제본은 마스터로 선출되기 위해 자신의 현재 에포크 값을 1 증가시키고, 마스터 노드들에 투표를 요청한다.
복제본 노드가 마스터 노드들로부터 응답을 받을 때 자신의 에포크 값보다 작은 에포크값들은 무시한다. 또한 정상적으로 들어온 요청이 과반수 이상 올경우 마스터 노드로 승격된다.
천재개발자