>  기사  >  백엔드 개발  >  Redis 클러스터 사양 지식에 대한 자세한 설명

Redis 클러스터 사양 지식에 대한 자세한 설명

小云云
小云云원래의
2017-12-14 14:56:251534검색

이 글에서는 Redis 클러스터 사양에 대한 자세한 설명을 중심으로 Redis 클러스터가 무엇인지, 그리고 Redis 클러스터의 기능에 대해 노드 장애 감지, 클러스터 상태 감지, 슬레이브 노드 선택 및 기타 관련 내용을 설명합니다. 좀 더 자세하게, 필요하신 친구들에게 참고하시면 되니, 모두에게 도움이 되었으면 좋겠습니다.

소개

이 문서는 개발 중인 Redis 클러스터 기능에 대한 사양 문서입니다. 문서는 두 부분으로 나누어집니다.

첫 번째 부분에서는 불안정한 브랜치에 구현된 기능을 소개합니다.
두 번째 부분에서는 아직 구현되지 않은 기능을 소개합니다.

클러스터 기능의 디자인이 수정됨에 따라 문서의 각 부분의 내용이 변경될 수 있습니다. 그 중 구현된 기능보다 구현되지 않은 기능이 수정될 확률이 높습니다.

이 사양에는 클라이언트 라이브러리를 작성하기 위해 알아야 할 모든 내용이 포함되어 있지만 여기에 나열된 세부 정보 중 일부는 향후 변경될 수 있다는 점에 유의하세요.

Redis 클러스터란 무엇인가요?

Redis 클러스터는 내결함성이 있는 분산형 Redis 구현입니다. 클러스터가 사용할 수 있는 기능은 일반 독립 실행형 Redis가 사용할 수 있는 기능의 하위 집합입니다.

Redis 클러스터에는 중앙 노드나 프록시 노드가 없습니다. 클러스터의 주요 설계 목표 중 하나는 선형 확장성을 달성하는 것입니다.

Redis 클러스터는 일관성을 보장하기 위해 일부 내결함성을 희생합니다. 시스템은 가능한 한 네트워크 연결 끊김(순 분할) 및 노드 오류(노드 오류)에 대한 제한된 저항을 보장하기 위해 최선을 다합니다.

클러스터는 노드 오류를 네트워크 연결 끊김의 특수 사례 중 하나로 처리합니다.

클러스터의 내결함성 기능은 마스터 노드(마스터)와 슬레이브 노드(슬레이브)의 두 가지 역할을 가진 노드를 사용하여 달성됩니다.

마스터 노드와 슬레이브 노드는 정확히 동일한 서버, 기능을 사용하여 구현됩니다. 정확히 동일하지만 슬레이브 노드는 일반적으로 실패한 마스터 노드를 교체하는 데만 사용됩니다.
그러나 "먼저 쓰기, 나중에 읽기" 작업의 일관성(쓰기 후 읽기 일관성)을 보장할 필요가 없는 경우 슬레이브 노드를 사용하여 읽기 전용 쿼리를 실행할 수 있습니다.

Redis 클러스터에 의해 구현되는 기능의 하위 집합

Redis 클러스터는 독립형 Redis에서 단일 데이터베이스 키를 처리하는 모든 명령을 구현합니다.

합집합 연산, 집합 집합 연산 등 다중 데이터베이스 키에 대한 복잡한 계산 연산은 구현되지 않으며, 이론적으로 다중 노드에서 다중 데이터베이스 키를 사용해야 하는 명령도 구현되지 않습니다.

향후에는 사용자가 MIGRATE COPY 명령을 사용하여 클러스터 계산 노드의 여러 데이터베이스 키에 대해 읽기 전용 작업을 수행할 수 있지만 클러스터 자체에서는 여러 데이터베이스 키가 필요한 작업을 구현하지 않습니다. 여러 노드를 이동하기 위한 복잡한 다중 키 명령입니다.

Redis 클러스터는 독립형 Redis와 같은 다중 데이터베이스 기능을 지원하지 않습니다. 클러스터는 기본 데이터베이스 번호 0만 사용하며 SELECT 명령을 사용할 수 없습니다.

Redis 클러스터 프로토콜의 클라이언트 및 서버

Redis 클러스터의 노드에는 다음과 같은 책임이 있습니다.

키-값 쌍 데이터 보관.
올바른 노드에 대한 키 매핑을 포함하여 클러스터 상태를 기록합니다.
다른 노드를 자동으로 검색하고, 제대로 작동하지 않는 노드를 식별하고, 필요한 경우 슬레이브 노드에서 새 마스터 노드를 선택합니다.

위에 나열된 작업을 수행하기 위해 클러스터의 각 노드는 다른 노드와 "클러스터 버스"를 설정했습니다. 이 연결은 TCP 연결이며 통신에 바이너리 프로토콜을 사용합니다.

Gossip 프로토콜은 노드 간에 다음 작업을 수행하는 데 사용됩니다.

클러스터에 대한 정보를 전파하여 새 노드를 검색합니다.
PING 패킷을 다른 노드로 보내 대상 노드가 정상적으로 작동하는지 확인합니다.
특정 이벤트가 발생하면 클러스터 정보를 보냅니다.

또한 클러스터 연결은 클러스터의 정보를 게시하거나 구독하는 데에도 사용됩니다.

클러스터 노드는 명령 요청을 프록시할 수 없기 때문에 노드가 -MOVED 또는 -ASK 리디렉션 오류를 반환하면 클라이언트는 명령 요청을 다른 노드에 직접 전달해야 합니다.

클라이언트는 클러스터의 모든 노드에 자유롭게 명령 요청을 보낼 수 있고 필요한 경우 조정 오류에서 제공한 정보를 기반으로 올바른 노드에 명령을 전달할 수 있으므로 이론적으로 클라이언트는 클러스터 상태 정보를 저장할 필요가 없습니다.

그러나 클라이언트가 키와 노드 간의 매핑 정보를 저장할 수 있다면 가능한 리디렉션 횟수를 효과적으로 줄여 명령 실행 효율성을 높일 수 있습니다.

키 배포 모델

Redis 클러스터의 키 공간은 16384개의 슬롯으로 나뉘며, 클러스터의 최대 노드 수도 16384개입니다.

권장되는 최대 노드 수는 약 1,000개입니다.

각 마스터노드는 16384개의 해시 슬롯 중 일부를 처리하는 역할을 담당합니다.

클러스터가 "안정" 상태에 있다는 것은 클러스터가 재구성 작업을 수행하지 않고 각 해시 슬롯이 하나의 노드에서만 처리된다는 의미입니다.

재구성은 특정/특정 슬롯을 한 노드에서 다른 노드로 이동하는 것을 의미합니다.

마스터 노드에는 여러 개의 슬레이브 노드가 있을 수 있습니다. 이러한 슬레이브 노드는 네트워크 연결이 끊어지거나 노드에 장애가 발생할 때 마스터 노드를 대체하는 데 사용됩니다.

다음은 키를 슬롯에 매핑하는 알고리즘입니다.

HASH_SLOT = CRC16(key) mod 16384


다음은 알고리즘에서 사용하는 매개변수입니다.

알고리즘 이름: XMODEM(ZMODEM 또는 ZMODEM이라고도 함) CRC-16/ ACORN)
결과 길이: 16비트
Poly: 1021(즉, x16 + x12 + x5 + 1)
초기화 값: 0000
Reflect 입력 바이트: False
출력 CRC 내보내기(Reflect Output CRC) ): False
Xor CRC 출력 값에 대해 CRC를 출력하는 상수: 0000
입력 "123456789"에 대한 이 알고리즘의 출력: 31C3

부록 A는 사용된 CRC16 알고리즘의 클러스터 정보 구현을 제공합니다.

CRC16 알고리즘으로 생성된 16비트 출력 중 14비트가 사용됩니다.
테스트에서 CRC16 알고리즘은 다양한 유형의 키를 16384개의 슬롯에 원활하게 배포할 수 있습니다.

클러스터 노드 속성

각 노드에는 클러스터의 고유한 ID가 있습니다. ID는 노드가 처음 시작될 때 /dev/urandom에 의해 생성되는 16진수로 표시되는 160비트 난수입니다.

노드는 구성 파일에 해당 ID를 저장합니다. 구성 파일이 삭제되지 않는 한 노드는 항상 이 ID를 사용합니다.

노드 ID는 클러스터의 각 노드를 식별하는 데 사용됩니다. 노드는 노드 ID를 변경하지 않고도 IP와 포트 번호를 변경할 수 있습니다. 클러스터는 IP/포트 번호의 변경 사항을 자동으로 식별하고 Gossip 프로토콜을 통해 이 정보를 다른 노드에 브로드캐스트할 수 있습니다.

다음은 각 노드가 가지고 있는 관련 정보이며, 노드는 이 정보를 다른 노드로 보냅니다.

노드가 사용하는 IP 주소와 TCP 포트 번호.
노드 플래그.
노드가 처리를 담당하는 해시 슬롯입니다.
노드가 클러스터 연결을 사용하여 PING 패킷을 보낸 마지막 시간입니다.
노드가 응답으로 PONG 패킷을 마지막으로 수신한 시간입니다.
클러스터가 노드를 오프라인으로 표시하는 시간입니다.
이 노드의 슬레이브 노드 수입니다.
노드가 슬레이브 노드인 경우 마스터 노드의 노드 ID를 기록합니다. 마스터 노드인 경우 마스터 노드 ID 열의 값은 0000000입니다.

위 정보 중 일부는 클러스터의 모든 노드(마스터 노드 또는 슬레이브 노드)에 CLUSTER NODES 명령을 보내면 얻을 수 있습니다.

다음은 세 개의 노드로 구성된 클러스터의 마스터 노드에 CLUSTER NODES 명령을 보내는 예입니다.

$ redis-cli cluster nodes
d1861060fe6a534d42d8a19aeb36600e18785e04 :0 myself - 0 1318428930 connected 0-1364
3886e65cc906bfd9b1f7e7bde468726a052d1dae 127.0.0.1:6380 master - 1318428930 1318428931 connected 1365-2729
d289c575dcbc4bdd2931585fd4339089e461a27d 127.0.0.1:6381 master - 1318428931 1318428931 connected 2730-4095

위에 나열된 세 줄의 정보는 각각 왼쪽에서 오른쪽으로 필드에는 노드 ID, IP 주소 및 포트 번호, 플래그, 마지막으로 PING을 보낸 시간, 마지막으로 PONG을 받은 시간, 연결 상태, 노드가 처리를 담당하는 슬롯이 있습니다.

노드 핸드셰이크(구현됨)

노드는 PING 패킷이 신뢰할 수 없는 노드에서 오는 경우에도 항상 클러스터 연결 포트의 연결 요청을 수락하고 수신된 PING 패킷에 응답합니다.

그러나 PING을 제외하고 노드는 클러스터 노드에서 오지 않는 다른 모든 패킷을 거부합니다.

다른 노드가 동일한 클러스터에 속해 있음을 노드가 인식하게 하려면 다음 두 가지 방법밖에 없습니다.

한 노드는 다른 노드에 MEET 메시지를 보내서 메시지를 받는 노드가 MEET 메시지를 보내는 노드가 이를 인식하도록 강제할 수 있습니다. 메시지는 클러스터의 일부가 되십시오입니다. 노드는 관리자가 명시적으로 CLUSTER MEET ip port 명령을 보내는 경우에만 다른 노드에 MEET 정보를 보냅니다.
또한 신뢰할 수 있는 노드가 타사 노드의 정보를 다른 노드에 전파하는 경우 정보를 수신하는 노드도 해당 타사 노드를 클러스터의 구성원으로 식별합니다. 즉, A가 B를 알고 B가 C를 알고 B가 C에 대한 정보를 A에게 전파하면 A도 C를 클러스터의 구성원으로 인식하고 C에 연결을 시도합니다.

이는 새 노드를 클러스터에 추가하면 이 새 노드가 결국 클러스터에 이미 있는 다른 모든 노드에 연결된다는 의미입니다.

이는 관리자가 CLUSTER MEET 명령을 사용하여 신뢰 관계를 명시적으로 지정하는 한 클러스터가 자동으로 다른 노드를 검색할 수 있음을 보여줍니다.

이 노드 식별 메커니즘은 IP 주소 변경이나 기타 네트워크 이벤트로 인해 서로 다른 Redis 클러스터가 예기치 않게 결합(혼합)되는 것을 방지하여 클러스터를 더욱 강력하게 만듭니다.

노드의 네트워크 연결이 끊어지면 알려진 다른 노드에 적극적으로 연결됩니다.

이동한 차례

一个 Redis 客户端可以向集群中的任意节点(包括从节点)发送命令请求。 节点会对命令请求进行分析, 如果该命令是集群可以执行的命令, 那么节点会查找这个命令所要处理的键所在的槽。

如果要查找的哈希槽正好就由接收到命令的节点负责处理, 那么节点就直接执行这个命令。
另一方面, 如果所查找的槽不是由该节点处理的话, 节点将查看自身内部所保存的哈希槽到节点 ID 的映射记录, 并向客户

端回复一个 MOVED 错误。

以下是一个 MOVED 错误的例子:

GET x
-MOVED 3999 127.0.0.1:6381

错误信息包含键 x 所属的哈希槽 3999 , 以及负责处理这个槽的节点的 IP 和端口号 127.0.0.1:6381 。 客户端需要根据这个 IP 和端口号, 向所属的节点重新发送一次 GET 命令请求。

注意, 即使客户端在重新发送 GET 命令之前, 等待了非常久的时间, 以至于集群又再次更改了配置, 使得节点 127.0.0.1:6381 已经不再处理槽 3999 , 那么当客户端向节点 127.0.0.1:6381 发送 GET 命令的时候, 节点将再次向客户端返回 MOVED 错误, 指示现在负责处理槽 3999 的节点。

虽然我们用 ID 来标识集群中的节点, 但是为了让客户端的转向操作尽可能地简单, 节点在 MOVED 错误中直接返回目标节点的 IP 和端口号, 而不是目标节点的 ID 。

虽然不是必须的, 但一个客户端应该记录(memorize)下“槽 3999 由节点 127.0.0.1:6381 负责处理“这一信息, 这样当再次有命令需要对槽 3999 执行时, 客户端就可以加快寻找正确节点的速度。

注意, 当集群处于稳定状态时, 所有客户端最终都会保存有一个哈希槽至节点的映射记录(map of hash slots to nodes), 使得集群非常高效: 客户端可以直接向正确的节点发送命令请求, 无须转向、代理或者其他任何可能发生单点故障(single point failure)的实体(entiy)。

除了 MOVED 转向错误之外, 一个客户端还应该可以处理稍后介绍的 ASK 转向错误。

集群在线重配置(live reconfiguration)

Redis 集群支持在集群运行的过程中添加或者移除节点。

实际上, 节点的添加操作和节点的删除操作可以抽象成同一个操作, 那就是, 将哈希槽从一个节点移动到另一个节点:

添加一个新节点到集群, 等于将其他已存在节点的槽移动到一个空白的新节点里面。

从集群中移除一个节点, 等于将被移除节点的所有槽移动到集群的其他节点上面去。

因此, 实现 Redis 集群在线重配置的核心就是将槽从一个节点移动到另一个节点的能力。 因为一个哈希槽实际上就是一些键的集合, 所以 Redis 集群在重哈希(rehash)时真正要做的, 就是将一些键从一个节点移动到另一个节点。

要理解 Redis 集群如何将槽从一个节点移动到另一个节点, 我们需要对 CLUSTER 命令的各个子命令进行介绍, 这些命理负责管理集群节点的槽转换表(slots translation table)。

以下是 CLUSTER 命令可用的子命令:

CLUSTER ADDSLOTS slot1 [slot2] ... [slotN]
CLUSTER DELSLOTS slot1 [slot2] ... [slotN]
CLUSTER SETSLOT slot NODE node
CLUSTER SETSLOT slot MIGRATING node
CLUSTER SETSLOT slot IMPORTING node

最开头的两条命令 ADDSLOTS 和 DELSLOTS 分别用于向节点指派(assign)或者移除节点, 当槽被指派或者移除之后, 节点会将这一信息通过 Gossip 协议传播到整个集群。 ADDSLOTS 命令通常在新创建集群时, 作为一种快速地将各个槽指派给各个节点的手段来使用。

CLUSTER SETSLOT slot NODE node 子命令可以将指定的槽 slot 指派给节点 node 。

至于 CLUSTER SETSLOT slot MIGRATING node 命令和 CLUSTER SETSLOT slot IMPORTING node 命令, 前者用于将给定节点 node 中的槽 slot 迁移出节点, 而后者用于将给定槽 slot 导入到节点 node :

当一个槽被设置为 MIGRATING 状态时, 原来持有这个槽的节点仍然会继续接受关于这个槽的命令请求, 但只有命令所处理的键仍然存在于节点时, 节点才会处理这个命令请求。

如果命令所使用的键不存在与该节点, 那么节点将向客户端返回一个 -ASK 转向(redirection)错误, 告知客户端, 要将命令请求发送到槽的迁移目标节点。

当一个槽被设置为 IMPORTING 状态时, 节点仅在接收到 ASKING 命令之后, 才会接受关于这个槽的命令请求。

如果客户端没有向节点发送 ASKING 命令, 那么节点会使用 -MOVED 转向错误将命令请求转向至真正负责处理这个槽的节点。

上面关于 MIGRATING 和 IMPORTING 的说明有些难懂, 让我们用一个实际的实例来说明一下。

假设现在, 我们有 A 和 B 两个节点, 并且我们想将槽 8 从节点 A 移动到节点 B , 于是我们:

向节点 B 发送命令 CLUSTER SETSLOT 8 IMPORTING A
向节点 A 发送命令 CLUSTER SETSLOT 8 MIGRATING B

每当客户端向其他节点发送关于哈希槽 8 的命令请求时, 这些节点都会向客户端返回指向节点 A 的转向信息:

如果命令要处理的键已经存在于槽 8 里面, 那么这个命令将由节点 A 处理。
如果命令要处理的键未存在于槽 8 里面(比如说,要向槽添加一个新的键), 那么这个命令由节点 B 处理。

这种机制将使得节点 A 不再创建关于槽 8 的任何新键。

与此同时, 一个特殊的客户端 redis-trib 以及 Redis 集群配置程序(configuration utility)会将节点 A 中槽 8 里面的键移动到节点 B 。

键的移动操作由以下两个命令执行:

CLUSTER GETKEYSINSLOT slot count

上面的命令会让节点返回 count 个 slot 槽中的键, 对于命令所返回的每个键, redis-trib 都会向节点 A 发送一条 MIGRATE 命令, 该命令会将所指定的键原子地(atomic)从节点 A 移动到节点 B (在移动键期间,两个节点都会处于阻塞状态,以免出现竞争条件)。

以下为 MIGRATE 命令的运作原理:

MIGRATE target_host target_port key target_database id timeout

执行 MIGRATE 命令的节点会连接到 target 节点, 并将序列化后的 key 数据发送给 target , 一旦 target 返回 OK , 节点就将自己的 key 从数据库中删除。

从一个外部客户端的视角来看, 在某个时间点上, 键 key 要么存在于节点 A , 要么存在于节点 B , 但不会同时存在于节点 A 和节点 B 。

因为 Redis 集群只使用 0 号数据库, 所以当 MIGRATE 命令被用于执行集群操作时, target_database 的值总是 0 。
target_database 参数的存在是为了让 MIGRATE 命令成为一个通用命令, 从而可以作用于集群以外的其他功能。

我们对 MIGRATE 命令做了优化, 使得它即使在传输包含多个元素的列表键这样的复杂数据时, 也可以保持高效。

不过, 尽管 MIGRATE 非常高效, 对一个键非常多、并且键的数据量非常大的集群来说, 集群重配置还是会占用大量的时间, 可能会导致集群没办法适应那些对于响应时间有严格要求的应用程序。

ASK 转向

在之前介绍 MOVED 转向的时候, 我们说除了 MOVED 转向之外, 还有另一种 ASK 转向。

当节点需要让一个客户端长期地(permanently)将针对某个槽的命令请求发送至另一个节点时, 节点向客户端返回 MOVED 转向。

另一方面, 当节点需要让客户端仅仅在下一个命令请求中转向至另一个节点时, 节点向客户端返回 ASK 转向。

比如说, 在我们上一节列举的槽 8 的例子中, 因为槽 8 所包含的各个键分散在节点 A 和节点 B 中, 所以当客户端在节点 A 中没找到某个键时, 它应该转向到节点 B 中去寻找, 但是这种转向应该仅仅影响一次命令查询, 而不是让客户端每次都直接去查找节点 B : 在节点 A 所持有的属于槽 8 的键没有全部被迁移到节点 B 之前, 客户端应该先访问节点 A , 然后再访问节点 B 。

因为这种转向只针对 16384 个槽中的其中一个槽, 所以转向对集群造成的性能损耗属于可接受的范围。

因为上述原因, 如果我们要在查找节点 A 之后, 继续查找节点 B , 那么客户端在向节点 B 发送命令请求之前, 应该先发送一个 ASKING 命令, 否则这个针对带有 IMPORTING 状态的槽的命令请求将被节点 B 拒绝执行。

接收到客户端 ASKING 命令的节点将为客户端设置一个一次性的标志(flag), 使得客户端可以执行一次针对 IMPORTING 状态的槽的命令请求。

从客户端的角度来看, ASK 转向的完整语义(semantics)如下:

如果客户端接收到 ASK 转向, 那么将命令请求的发送对象调整为转向所指定的节点。
先发送一个 ASKING 命令,然后再发送真正的命令请求。
不必更新客户端所记录的槽 8 至节点的映射: 槽 8 应该仍然映射到节点 A , 而不是节点 B 。

一旦节点 A 针对槽 8 的迁移工作完成, 节点 A 在再次收到针对槽 8 的命令请求时, 就会向客户端返回 MOVED 转向, 将关于槽 8 的命令请求长期地转向到节点 B 。

클라이언트에 버그가 발생하고 슬롯 8이 노드 B에 조기에 매핑되더라도 클라이언트가 ASKING 명령을 보내지 않는 한 클라이언트는 명령 요청을 보낼 때 MOVED 오류가 발생하고 다시 리디렉션됩니다. 노드 A.

Fault Tolerance

노드 오류 감지

다음은 노드 오류 감지가 구현되는 방법입니다.

한 노드가 다른 노드에 PING 명령을 보냈지만 대상 노드가 해당 노드 내에서 PING 명령을 반환하지 못하는 경우 주어진 시간 제한 응답 시 명령을 보내는 노드는 대상 노드를 PFAIL(실패 가능, 실패했을 수 있음)로 표시합니다.
PING 명령의 응답을 기다리는 시간 제한을 "노드 시간 초과"라고 하며 노드별 설정입니다.
노드가 다른 노드에 PING 명령을 보낼 때마다 자신이 알고 있는 노드에 대한 세 가지 정보를 무작위로 브로드캐스트합니다. 정보 중 하나는 해당 노드가 PFAIL 또는 FAIL로 표시되었는지 여부입니다.
노드가 다른 노드로부터 정보를 받으면 다른 노드에서 실패한 것으로 표시된 노드를 기록합니다. 이를 실패 보고서라고 합니다.
노드가 노드를 PFAIL로 표시하고 노드가 수신한 명시적인 오류 보고서에 따라 클러스터의 다른 대부분의 마스터 노드도 해당 노드가 실패 상태로 전환되었다고 판단하면 노드는 해당 노드의 상태를 업데이트합니다. 실패한 노드는 FAIL로 표시됩니다.
한 노드가 FAIL로 표시되면 해당 노드의 실패에 대한 정보가 전체 클러스터에 전파되고, 이 정보를 받은 모든 노드는 실패한 노드를 FAIL로 표시합니다.

간단히 말하면, 노드가 다른 노드를 무효로 표시하려면 먼저 다른 노드에게 의견을 묻고 마스터 노드 대다수의 동의를 얻어야 합니다.

만료된 실패 보고서는 삭제되므로 마스터 노드가 노드를 FAIL로 표시하려면 가장 최근에 수신된 실패 보고서를 기반으로 해야 합니다.

다음 두 가지 상황에서는 노드의 FAIL 상태가 제거됩니다.

FAIL로 표시된 노드가 슬레이브 노드인 경우 해당 노드가 다시 온라인 상태가 되면 FAIL 표시가 제거됩니다.
슬레이브 노드의 FAIL 상태를 다시 설정하는 것은 의미가 없습니다. 슬레이브 노드가 FAIL 상태인지 여부에 따라 필요할 때 슬레이브 노드가 마스터 노드로 승격될 수 있는지 여부가 결정됩니다.
마스터 노드가 FAIL로 표시된 후 노드 시간 초과 기간의 4배에 10초가 더해진 후에도 마스터 노드의 슬롯에 대한 장애 조치 작업이 완료되지 않은 경우 마스터 노드가 다시 온라인 상태가 된 것입니다. 이 노드에 대한 FAIL 표시입니다.

두 번째 경우, 장애 조치가 성공적으로 완료되지 않고 마스터 노드가 다시 온라인 상태가 되면 클러스터는 원래 마스터 노드를 계속 사용하므로 관리자 개입이 필요하지 않습니다.

클러스터 상태 감지(부분적으로 구현됨)

클러스터에 구성 변경이 있을 때마다(해시 슬롯 업데이트이거나 노드가 실패 상태에 들어갈 수 있음) 클러스터의 각 노드는 상태 스캔을 확인합니다. 알려진 노드.

구성이 처리되면 클러스터는 다음 두 가지 상태 중 하나에 들어갑니다.

FAIL: 클러스터가 제대로 작동할 수 없습니다. 클러스터의 노드가 실패 상태가 되면 클러스터는 명령 요청을 처리할 수 없습니다. 각 명령 요청에 대해 클러스터 노드는 오류 응답을 반환합니다.
OK: 클러스터가 정상적으로 작동하고 있으며, 16384개 슬롯 전체를 처리하는 노드 중 FAIL로 표시된 노드가 없습니다.

이는 클러스터의 해시 슬롯 중 일부만 사용되지 않는 경우에도 전체 클러스터가 모든 명령 처리를 중지한다는 의미입니다.

그러나 노드에 문제가 발생한 이후 FAIL로 표시될 때까지의 기간 동안 클러스터는 계속 정상적으로 작동하므로 어느 시점에서는 클러스터가 여전히 16384 슬롯의 하위 집합에 대한 명령을 처리할 수 있습니다. 묻다.

다음은 클러스터가 FAIL 상태에 진입하는 두 가지 상황입니다.

이 슬롯 처리를 담당하는 노드가 FAIL 상태에 진입했기 때문에 하나 이상의 해시 슬롯을 사용할 수 없습니다.
클러스터에 있는 대부분의 마스터 노드가 오프라인 상태가 되었습니다. 대부분의 마스터 노드가 PFAIL 상태로 전환되면 클러스터도 FAIL 상태로 전환됩니다.

노드를 PFAIL 상태에서 FAIL 상태로 변경하려면 대다수의 마스터 노드가 투표해야 하기 때문에 두 번째 확인이 필요합니다. 그러나 클러스터의 대부분의 마스터 노드가 실패 상태에 들어가면 노드를 표시할 방법이 없습니다. 한두 개의 노드만 FAIL 상태로 설정합니다.

따라서 두 번째 확인 조건을 사용하면 클러스터에 있는 대부분의 마스터 노드가 오프라인 상태가 되는 한 클러스터는 이러한 마스터 노드의 의견을 요청하지 않고도 해당 노드를 FAIL 상태로 판단할 수 있습니다. 전체 클러스터에서 명령 요청 처리를 중지합니다.

슬레이브 노드 선거

一旦某个主节点进入 FAIL 状态, 如果这个主节点有一个或多个从节点存在, 那么其中一个从节点会被升级为新的主节点, 而其他从节点则会开始对这个新的主节点进行复制。

新的主节点由已下线主节点属下的所有从节点中自行选举产生, 以下是选举的条件:

这个节点是已下线主节点的从节点。
已下线主节点负责处理的槽数量非空。
从节点的数据被认为是可靠的, 也即是, 主从节点之间的复制连接(replication link)的断线时长不能超过节点超时时限(node timeout)乘以 REDIS_CLUSTER_SLAVE_VALIDITY_MULT 常量得出的积。

如果一个从节点满足了以上的所有条件, 那么这个从节点将向集群中的其他主节点发送授权请求, 询问它们, 是否允许自己(从节点)升级为新的主节点。

如果发送授权请求的从节点满足以下属性, 那么主节点将向从节点返回 FAILOVER_AUTH_GRANTED 授权, 同意从节点的

升级要求:

发送授权请求的是一个从节点, 并且它所属的主节点处于 FAIL 状态。

在已下线主节点的所有从节点中, 这个从节点的节点 ID 在排序中是最小的。

这个从节点处于正常的运行状态: 它没有被标记为 FAIL 状态, 也没有被标记为 PFAIL 状态。

一旦某个从节点在给定的时限内得到大部分主节点的授权, 它就会开始执行以下故障转移操作:

通过 PONG 数据包(packet)告知其他节点, 这个节点现在是主节点了。

通过 PONG 数据包告知其他节点, 这个节点是一个已升级的从节点(promoted slave)。

接管(claiming)所有由已下线主节点负责处理的哈希槽。

显式地向所有节点广播一个 PONG 数据包, 加速其他节点识别这个节点的进度, 而不是等待定时的 PING / PONG 数据包。

所有其他节点都会根据新的主节点对配置进行相应的更新,特别地:

所有被新的主节点接管的槽会被更新。

已下线主节点的所有从节点会察觉到 PROMOTED 标志, 并开始对新的主节点进行复制。

如果已下线的主节点重新回到上线状态, 那么它会察觉到 PROMOTED 标志, 并将自身调整为现任主节点的从节点。

在集群的生命周期中, 如果一个带有 PROMOTED 标识的主节点因为某些原因转变成了从节点, 那么该节点将丢失它所带有的 PROMOTED 标识。

发布/订阅(已实现,但仍然需要改善)

在一个 Redis 集群中, 客户端可以订阅任意一个节点, 也可以向任意一个节点发送信息, 节点会对客户端所发送的信息进行转发。

在目前的实现中, 节点会将接收到的信息广播至集群中的其他所有节点, 在将来的实现中, 可能会使用 bloom filter 或者其他算法来优化这一操作。

附录 A: CRC16 算法的 ANSI 实现参考

/*
 * Copyright 2001-2010 Georges Menie (www.menie.org)
 * Copyright 2010 Salvatore Sanfilippo (adapted to Redis coding style)
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *   * Neither the name of the University of California, Berkeley nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/* CRC16 implementation acording to CCITT standards.
 *
 * Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
 * following parameters:
 *
 * Name            : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
 * Width           : 16 bit
 * Poly            : 1021 (That is actually x^16 + x^12 + x^5 + 1)
 * Initialization       : 0000
 * Reflect Input byte     : False
 * Reflect Output CRC     : False
 * Xor constant to output CRC : 0000
 * Output for "123456789"   : 31C3
 */
static const uint16_t crc16tab[256]= {
  0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
  0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
  0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
  0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
  0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
  0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
  0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
  0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
  0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
  0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
  0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
  0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
  0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
  0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
  0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
  0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
  0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
  0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
  0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
  0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
  0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
  0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
  0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
  0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
  0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
  0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
  0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
  0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
  0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
  0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
  0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
  0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t crc16(const char *buf, int len) {
  int counter;
  uint16_t crc = 0;
  for (counter = 0; counter < len; counter++)
      crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
  return crc;
}

相关推荐:

Redis集群规范(一)

Redis集群搭建全记录

redis集群实战

위 내용은 Redis 클러스터 사양 지식에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.