인터뷰는 전혀 어렵지 않습니다 : Redis 클러스터 모드 분석, 해시 슬롯, 클러스터 모드 고 가용성, 일관성, 클라이언트 JedisPool, 클러스터 확장

1 클러스터 모드와 마스터-슬레이브 모드의 차이점

  • 마스터-슬레이브 모드에서 마스터 / 슬레이브 노드에는 캐시 된 데이터의 전체 양이 포함됩니다 (데이터 양이 많으면 확장 병목 현상이 발생 함).
  • 클러스터 클러스터 모드에서 전체 캐시 데이터는 여러 노드에 분산되어 있으며 각 노드에는 전체 캐시 데이터의 일부만 포함됩니다.

2 클러스터 모드에서 노드 데이터 분할

데이터는 해시 슬롯에 따라 분할됩니다.

Redis 클러스터에는 16384 개의 해시 슬롯이 있으며 각 키는 CRC16 및 모듈로 16384에 의해 확인되어 키가 해당하는 슬롯을 결정합니다.

예를 들어 현재 클러스터에는 3 개의 노드가 있습니다.

  1. 노드 A에는 해시 슬롯 0 ~ 5500이 있습니다.
  2. 노드 B에는 해시 슬롯 5501 ~ 11000이 포함됩니다.
  3. 노드 C에는 해시 슬롯 11001 ~ 16384 포함

3 클러스터 모드에는 최소 3 개의 마스터 노드가 필요합니다.

  1. 클러스터 모드는 클러스터 상태를 동기화하기 위해 Gossip 프로토콜을 기반으로하기 때문에 완전히 분산 된 모드입니다.
  2. 따라서 클러스터 상태의 일관성을 유지하려면 "다수"원칙을 따라야합니다 (예 : 노드가 갑자기 연결에 실패하고 대부분의 노드 만 연결할 수 없다고 생각하는 것은 실제로는 그렇지 않습니다. 연결됨)
  3. 따라서 최소 3 개의 노드가 필요합니다.
    1. 분산 투표 시나리오에서 3 노드 클러스터는 하나의 노드 중단 지점을 허용 할 수 있습니다.
    2. Redis에는 cluster-require-full-coverage = no 구성이 있습니다. 한 마스터 노드가 다운 되더라도 다른 마스터 노드는 여전히 서비스를 제공 할 수 있습니다 (= 예, 하나의 마스터 노드가 다운되면 클러스터를 사용할 수 없음).

4 클러스터 모드 클러스터 고 가용성

노드의 고 가용성을 보장하기 위해 일반적으로 마스터-슬레이브 모드가 채택되고 각 마스터 노드에는 슬레이브 노드가 있습니다.

따라서 클러스터는 클러스터 모드에서 가용성이 높고 마스터 3 개와 슬레이브 3 개가 필요합니다.

5 클러스터 모드에서 단일 키 작동

5.1 간단한 클라이언트 redis-cli 작업

redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
  • 현재 작업의 키에 해당하는 슬롯이 현재 클라이언트가 연결된 노드에 없으면 클러스터는 MOVED 오류를 반환하고 올바른 대상 노드를 나타냅니다.
  • 그런 다음 클라이언트는 올바른 대상 노드에 계속 요청을 보냅니다.

5.1.1 올바른 노드로 작업을 전달하기 위해 클라이언트가 서버 대신 리디렉션을 수행하는 이유는 무엇입니까?

추측:

서버가 작업을 올바른 노드로 전달하는 데 도움이되는 경우 :

  • 서버는 차단되고 (클라이언트 요청의 단일 스레드 처리로 인해) 백그라운드는 작업을 다른 서버로 전달하고 결과를 기다립니다.
  • 전체 프로세스에는 4 개의 네트워크 전송이 포함됩니다 (클라이언트 리디렉션 방법과 동일한 네트워크 전송 수).

클라이언트 리디렉션 인 경우 :

  • 서버가 차단하지 않고 리디렉션 명령을 반환 한 후 다른 클라이언트 요청을 계속 처리합니다.
  • 클라이언트 리디렉션, 전체 프로세스에는 4 개의 네트워크 전송이 포함됩니다 (서버 전달 작업 수와 동일).

반대로 클라이언트 리디렉션은 더 저렴합니다.

5.2 Java JedisPool에서 작업

단순 클라이언트 redis-cli 모드에 문제가있어 현재 키에 해당하는 슬롯이 어느 노드인지 미리 알 수 없어 많은 리디렉션이 발생합니다.

JedisPool은 Java redis 커넥션 풀로 <slot, node>의 해당 관계를 캐싱하므로 작업 수행시 먼저 키에 해당하는 슬롯을 계산 한 다음 해당 슬롯에 해당하는 노드를 찾습니다.

6 클러스터 모드에서 다중 키 작동

여러 키가 여러 슬롯에 해당 할 수 있고 여러 슬롯이 서로 다른 노드에 분산되어 있기 때문에 클러스터 모드는 일반적으로 여러 키 관련 작업을 지원하지 않습니다.

// 以 Java Redis 客户端 Jedis 为例:
// 对于 multi keys,要求所有的 key 都对应同一个 slot 才能执行(这个限制更严格,更宽松一点的限制是:可以对应多个 slot,但这些slot 都在一个节点上)
if (keys.length > 1) {
    
    
  int slot = JedisClusterCRC16.getSlot(keys[0]);
  for (int i = 1; i < keyCount; i++) {
    
    
    int nextSlot = JedisClusterCRC16.getSlot(keys[i]); // 计算key对应的 slot
    if (slot != nextSlot) {
    
     // slot 不一致则抛异常
      throw new JedisClusterException("No way to dispatch this command to Redis Cluster "
          + "because keys have different slots.");
    }
  }
}

6.2 해시 태그를 사용하여 키에 해당하는 슬롯 제어

일부 시나리오에서는 여러 키가 하나의 노드에 있기를 바랍니다. 어떻게 제어합니까?

  • redis는 키 해시 태그를 제공합니다.
  • {해시 태그} 키 값
  • 키에 해시 태그가있는 경우 특정 키가 아닌 CRC16을 계산할 때 해시 태그가 사용됩니다.
  • 따라서 여러 키가 동일한 노드 (동일 슬롯)에 있도록하려면 여러 키가 동일한 해시 태그를 사용하도록 할 수 있습니다.

7 비 강력 일관성

이유:

  1. 마스터-슬레이브 동기화.
    1. 비동기 적으로 실행되며 쓰기가 아직 동기화되지 않았는데 마스터가 멈추고 이때 쓰기가 손실 될 수 있습니다.
  2. 네트워크 파티션의 마스터-슬레이브 전환.
    1. 네트워크 파티션은 클러스터 모드로 나타납니다. 마스터 노드와 슬레이브 노드가 다른 파티션에 있고 파티션 슬레이브 노드 중 하나가 마스터로 선택되면 원래 마스터 노드의 쓰기 작업의 일부가 수행되지 않았을 수 있습니다. 네트워크 파티션으로 인해 슬레이브에 동기화됩니다.
假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点。 
其中 A 、B 、C 为主节点, A1 、B1 、C1 为A,B,C的从节点。
还有一个客户端 Z1 。

假设集群中发生网络分区,那么集群可能会分为两方,
大部分的一方包含节点 A 、C 、A1 、B1 和 C1 ,
小部分的一方则包含节点 B 和客户端 Z1 。
Z1仍然能够向主节点B中写入, 
如果网络分区发生时间较短,那么集群将会继续正常运作,
如果分区的时间足够让大部分的一方将B1选举为新的master,那么Z1写入B中得数据便丢失了。

8 클러스터 클러스터 확장 / 재 샤딩

노드 추가, 노드 삭제 및 재분할은 기본적으로 슬롯 마이그레이션 작업의 한 유형입니다.

예를 들어, 새 노드가 추가되면 다른 노드의 일부 슬롯이 새 노드에 할당됩니다.

클러스터 모드에서 데이터 마이그레이션의 기본 단위는 슬롯입니다.

8.1 슬롯 마이그레이션

여기에 사진 설명 삽입

슬롯 마이그레이션 단계 :

  1. 슬롯을 중간 전환 상태로 표시합니다 (위 그림에 표시된 것처럼 노드 A에서 이동하면 A에 표시된 슬롯이 마이그레이션 중 상태이고 노드 B로 이동하면 B의 슬롯 표시가 가져 오기 상태입니다). )
  2. 슬롯의 키에 따라 하나씩 마이그레이션하여 마이그레이션을 동기식으로 차단
    1. A는 슬롯의 키를 B로 보냅니다.
    2. B 데이터 수신 후 로컬에 저장하고 확인 응답
    3. A OK 응답을받은 후 로컬 키를 삭제합니다.
  3. 이 마이그레이션 프로세스의 연결이 끊어진 후 복구 가능

8.2 슬롯 마이그레이션 중 클라이언트의 요청 처리

슬롯 마이그레이션 프로세스로 인해 슬롯의 키 일부는 노드 A에 있고 일부는 노드 B에 있으므로 클라이언트의 요청 처리가 크게 변경됩니다.

  1. 클라이언트는 먼저 슬롯에 해당하는 이전 노드를 방문합니다.
  2. 데이터가 여전히 이전 노드에 있으면 이전 노드가 정상적으로 처리됩니다.
  3. 데이터가 더 이상 이전 노드에 없으면 이전 노드는 요청 B 리디렉션 순서를 클라이언트에 반환합니다.
  4. 클라이언트가 B를 먼저 실행합니다.
  5. 그런 다음 클라이언트는 get 작업을 실행합니다.

리디렉션 할 때 get을 직접 사용할 수 없지만 먼저 ask 명령을 실행하는 이유는 무엇입니까?

슬롯이 노드 B에 속하지 않기 때문에 (여전히 노드 A에 속함) get 명령을 직접 보내면 B가 클라이언트를 A로 리디렉션하여 순환 리디렉션을 유발합니다.

추천

출처blog.csdn.net/hugo_lei/article/details/106390853