Redis Cluster Tutorial
1-Introduction
Redis Cluster 支持数据自动在多个 Redis 节点间分片。
通过 Redis Cluster,能够实现:
- 自动切分数据集到多个节点(Sharding)
- 当部分节点故障或不可达的情况下,Redis Cluster 能够继续提供服务(High Availability)
Redis Cluster 提供一定程度的高可用,当某些节点失败或者不能访问的情况下能够继续提供服务。但是当大量节点失败的情况下集群也会停止服务(例如大多数主节点不可用)。
2-TCP Ports
每个 Redis Cluster 节点需要打开两个 TCP 端口用于不同的连接。
-
端口 6379:用于提供客户端连接
该端口需要开放给所有与集群交互的客户端;同时,也要开放给集群中的其他节点用于 keys 迁移
-
端口 16379:用于集群总线
该端口需要开放给集群中的其他节点
客户端只能连接 6379,而不能连接 16739;而集群中的节点可以访问 6379 与 16739 两个端口
集群总线用于集群节点之间访问,使用二进制协议,主要用于失败检测、配置升级、故障转移授权等。
二进制协议更适合节点间使用小的带宽和处理时间来交换数据
3-Data Sharding
Redis Cluster 的数据分片不是使用一致性 Hash,而是使用一种 Hash Slot(哈希槽)的形式。
Redis Cluster 中共有 16384 个 Slot,如何决定每个 key 分配到哪个槽呢?
- Slot_Index = CRC16(key) % 16384 计算 Slot 索引
Cluster 中的每个节点负责一部分 Hash Slot,比如集群中有3个节点,则:
- A 存储的范围:0 ~ 5500
- B存储的范围:5501 ~ 11000
- C存储的范围:11001 ~ 16384
这种分配方式便于集群节点的新增与剔除。
- 新增一个节点D:需要把A、B、C中的部分 Hash Slot 数据移到 D 节点
- 删除 A 节点:需要把 A 节点的 Hash Slot 的数据移到 B 和 C 节点;当 A 节点的数据全部被移走后,A 节点就可以完全从集群中删除
Slot 在不同节点之间的迁移不需要暂停服务
通过 Hash Tag 的概念,Redis Cluster 可以通过一个命令(或事务, 或 lua 脚本)同时操作多个 key。
Hash Tag 可以使得相同 Tag 的不同 key 被分配到同一个 Slot 。如:key_1 = “this{foo}”, key_2 = “another{foo}”,这两个 key 的 tag 均为 foo,会被分配到同一个 Slot 中,所以可以在一个命令中操作它们。
4-Master-Replica Model
为了提高 Cluster 的可用性,保证在部分节点故障或网络不通时 Cluster 依然能正常工作,Redis Cluster 使用了主从模型:每个 Hash Slot 有 1(主节点)到 N 个副本( N-1 个从节点)。
在上面的例子中,A, B, C 设为主节点,A1, B1, C1 分别为其从节点。如果 B 不可用,则会将 B1 提升为主节点,从而保证集群能够继续提供服务;但是如果 B1 同时也不可用了,则集群就不能继续工作了。
5-Consistency Guarantees
Redis Cluster 不能保证强一致性:一些已经向 Client 确认写成功的操作,会在某些不确定的情况下丢失。
无法保证强一致性的原因有:
- 主从节点之间使用了异步的方式来同步数据
- 网络分区期间可能导致的写操作数据丢失
当 Client 向主节点 B 节点提交一个写操作后,主节点 B 将数据保存在本地并回复给 Client 操作成功 ,之后 B 异步地将刚才写操作的变更复制到从节点 B1, B2, B3。
由于是异步复制,所以在 B 响应 Client 之后,并且同步给从节点之前,主节点 B 故障了,其中一个没有收到该写操作的从节点会晋升成主节点,该写操作就这样永远丢失了。
为了提高一致性,可以考虑使用同步复制,不过会使得性能降低。
在性能和一致性之间,需要一个权衡
Redis Cluster 支持同步复制,通过 WAIT 命令实现,可以让数据丢失的概率降低。但是即使使用了同步复制,Redis Cluster 仍不是强一致性的。
考虑一种网络分区的情况:集群中存在主节点 A, B, C,从节点 A1, B1, C1,客户端 Z1,其中 Z1 与 B 可以网络互通,A, A1, B1, C, C1 之间网络互通,但是与 Z1, B 网络不通(一共两个网络分区)。
- Z1 可以继续向 B 发起写操作,B 也接受 Z1 的写操作
- 当网络恢复时,如果这个时间间隔足够短,集群仍然能继续正常工作
-
如果时间比较长,以至于 B1 在大多数的这边被重新选为主节点,那么刚才 Z1 发给 B 的写操作都将丢失
Z1 给 B 发送写操作是有一个限制的,如果时间长度达到了大多数节点那边可以选出一个新的主节点时,少数这边的所有主节点都不接受写操作
如何评断网络分区的时间是长还是短?
Redis Cluster 中存在一个节点超时配置。
- 当达到了这个节点超时的时间之后,主节点被认为已经宕机,可以用它的一个从节点来代替
- 同样,在节点超时时,如果主节点依然不能联系到其他主节点,它将进入错误状态,不再接受写操作
6-Appendix
原文地址:redis-io