Redis数据库笔记——Cluster集群模式
大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Redis数据库的Cluster集群模式,包括工作原理,哈希槽,路由和配置原理等。
文章目录
什么是 Redis Cluster 集群?
Redis Cluster 在 3.0 版本中引入,是 Redis 的集群模式解决方案。提供了一种原生的分布式集群解决方案,用于解决 Redis 的水平扩展(sharding)问题【类似MySQL的分库分表】,自动将数据划分为多个分片(Shards),每个分片由一个主节点(Master)负责。每个主节点可以有多个从节点(Slave)用于数据冗余备份。
Redis Cluster 由多个节点组成,节点之间通过内部通信协议进行数据交换和协作。Redis Cluster 采用分布式哈希(hashing) 方式来管理数据,通过将数据分片并分配给不同的节点,确保每个 Redis 节点只管理一部分数据。整个集群由多个 Redis 实例(包括主节点和从节点)组成,数据在集群中的多个节点之间分布。
上图假设有三个主节点,Redis Cluster 的关键部件包括:
- 分片(Sharding):Redis Cluster 将整个数据集划分为 16384 个槽,每个槽可以存储一个键值对。每个节点负责一部分槽,并根据哈希算法决定每个键的槽。
- 主从节点:每个分片有一个主节点和多个从节点。从节点用于数据备份和故障转移。
- 主节点(Master Node):负责处理数据存储、命令请求、读写操作,并将数据分配到对应的槽。
- 从节点(Replica Node):从主节点同步数据并提供只读服务,主节点宕机时自动提升为新的主节点。
为什么需要 Redis Cluster 集群?
-
水平扩展(Sharding):
Redis 是一个高性能的单机内存数据库,单机模式下,由于内存和 CPU 的限制,数据量和并发处理能力会受到限制。Redis Cluster 通过数据分片(sharding)技术,将数据分散到多个节点上,从而实现水平扩展(scale-out)。这种方式可以大大提高 Redis 的存储容量和处理能力。 -
容错能力及高可用性【类似哨兵机制】:
在传统的 Redis 主从复制架构中,如果主节点故障,需要手动恢复或切换到备份节点,这样会导致系统停机。Redis Cluster 通过自动故障转移机制来提高系统的高可用性。在 Redis Cluster 中,如果某个主节点故障,集群会自动将某个从节点提升为新的主节点,保证数据的持续可用。 -
负载均衡【类似主从复制】:
Redis Cluster 可以自动将数据分布到多个节点上,不同的节点处理不同的请求,这样可以均衡地分担负载,避免某个节点成为瓶颈。客户端请求会根据数据的哈希值路由到正确的节点,从而分摊了处理压力。 -
减少单点故障(SPOF):
在没有 Redis Cluster 的情况下,如果某个 Redis 实例发生故障,整个系统会变得不可用,导致单点故障(SPOF)。Redis Cluster 通过将数据分片并在多个节点间分配,避免了单点故障的发生,从而提高了集群的可用性和可靠性。
Redis Cluster 的工作原理
数据分片(Sharding)
- Redis Cluster 使用一致性哈希算法将数据划分为 16384 个槽,每个槽负责一个数据范围。
- 通过
hash slot
算法,Redis 会根据键的哈希值将其映射到一个特定的槽。例如,key1
被映射到槽 1024,key2
被映射到槽 2048。 - Redis Cluster 会将这些槽分配到集群中的主节点上。每个主节点负责一个或多个槽。
数据路由
- 当客户端发起请求时,Redis Cluster 会根据键的哈希值确定请求的目标节点。客户端会通过 槽映射 来确定请求的主节点地址。
- 如果客户端请求的数据不在当前节点上,节点会返回一个 MOVED 错误,告知客户端数据所在的实际节点地址。客户端会根据该信息重新发送请求。
故障转移【类似哨兵机制】
- Redis Cluster 提供了内置的故障转移机制。每个主节点有一个或多个从节点用于备份数据。
- 当一个主节点宕机时,Redis Cluster 会自动选举一个从节点来替代它。这是通过 投票机制 完成的,通常选择最新同步的从节点。
- 故障转移是透明的,客户端无感知,确保系统高可用。
扩容和缩容
- Redis Cluster 支持动态扩展和缩减节点。通过
reshard
操作,可以将槽从一个节点移动到另一个节点,从而平衡负载或增加集群容量。 - 扩容时,可以通过 增加节点 来将槽分配到新的节点上。缩容时,可以通过将槽迁移到其他节点来减少节点数量。
哈希槽数据分片
普通哈希(Hashing)
普通哈希(或传统的分片机制)是一种简单的方式,它通过计算某个键(key)的哈希值,将其映射到特定的服务器或节点上。典型的实现方式是通过对哈希值求模,确定数据存储的节点。
这种方法简单且易于实现,但当集群规模发生变化(比如增加或移除节点)时,存在几个显著的问题:
- 数据迁移问题:
- 节点增加时:普通哈希算法在节点增加时,通常需要重新计算现有数据的哈希值,并根据新的节点数重新分配数据。这会导致大量的数据需要被重新分配和迁移,造成很大的性能开销,尤其是在大规模的系统中。
- 节点减少时:同样,如果移除一个节点,所有由该节点负责的数据也需要被重新分配到剩余节点,这个过程可能同样导致大量的数据迁移。
- 扩展性差:
- 由于每次增加或减少节点时,数据的重新分配会非常繁琐且开销巨大,这使得使用普通哈希在动态扩展集群时显得不够高效和灵活。
- 负载不均衡:
- 在节点数较少的情况下,普通哈希可能导致负载不均,某些节点可能存储了大量的数据,而其他节点存储的数据较少。当节点数发生变化时,负载均衡的调整并不灵活。
解决这些问题的方法是使用一致性哈希。
一致性哈希
一致性哈希 是一种解决分布式系统中数据分配和负载均衡问题的算法,尤其适用于节点动态变化的情况(例如,增加或减少节点)。它的核心思想是将节点和数据映射到一个虚拟的环形空间中,而不是简单地通过哈希值对节点数取模。
一致性哈希的基本概念:
-
哈希环:一致性哈希将数据和节点映射到一个哈希环上,哈希环上的位置由哈希函数决定。每个节点和数据都会计算一个哈希值,然后被放置到环的某个位置上。
-
数据分配:数据会根据哈希值顺时针找到第一个节点进行存储。如果某个节点失效,数据会转到顺时针方向的下一个节点,从而确保数据的高可用性。
-
节点变化:当增加或删除节点时,一致性哈希只需要迁移哈希环上一小部分的数据,而不是全部数据,极大减少了数据迁移的量。
一致性哈希的优势:
-
减少数据迁移:
- 一致性哈希的最大优势是,在节点增加或减少时,只有一部分数据会被迁移。即使增加了新的节点,只有一小部分数据会从其他节点迁移到新节点,而绝大部分数据保持不变。
- 这是因为一致性哈希利用了虚拟节点的概念,将多个虚拟节点映射到哈希环上,这样每个实际节点只会占据环上的某一小段范围。
-
更好的负载均衡:
- 一致性哈希通过虚拟节点的方式,使得每个物理节点在哈希环上分布得更加均匀,从而实现更好的负载均衡。每个节点负责多个虚拟节点,减少了负载不均的情况。
-
扩展性:
- 一致性哈希允许动态扩展集群。当需要增加节点时,只需为新节点分配适当数量的虚拟节点,其他节点的数据分布几乎不受影响。节点移除时,只需要将该节点的数据重新分配给相邻的节点。
但是,一致性哈希也存在一些局限性:
-
虚拟节点的管理的复杂性:
- 一致性哈希引入了虚拟节点的概念。虽然虚拟节点能带来更均匀的负载,但也增加了系统的复杂性。虚拟节点的数量需要根据负载情况灵活调整,而这在实现上可能会增加一定的管理和计算成本。
-
节点之间的负载差异:
- 虽然虚拟节点能在一定程度上减少负载不均衡的情况,但一致性哈希本身并不保证绝对均衡。如果哈希环上的虚拟节点分布不均,仍然可能存在某些节点负载过重的情况。
-
迁移逻辑复杂:
- 在节点增加或移除时,数据需要根据一致性哈希算法重新分配,这虽然减少了迁移量,但依然存在一定的数据迁移,特别是在节点数变化较大的情况下。
Redis 集群使用哈希槽
Redis 集群采用了 哈希槽(Hash Slots)的方式,避免了纯粹依赖一致性哈希的复杂性。Redis 集群将所有的键通过哈希计算分配到 16384 个固定的槽(slots) 中。每个 Redis 节点负责一定数量的哈希槽。
哈希槽的优势
-
简单而有效的扩展机制:
- Redis 集群通过固定数量的哈希槽(16384个)来分配数据。每个节点只负责这些哈希槽中的一部分。这使得节点的增加或移除非常简单。扩展时,只需要将部分哈希槽迁移到新节点,数据迁移量小,且几乎不会影响其他节点的工作。
-
自动负载均衡:
- 哈希槽的数量是固定的,因此所有节点的负载能够更加均匀地分配。如果有一个节点加入集群,只需要将部分哈希槽重新分配给它,负载就能均匀地分布到所有节点。
-
减少数据迁移:
- 在 Redis 集群中,只有在增加或移除节点时,才需要迁移数据。每个哈希槽都被一个特定节点管理,因此集群的扩展不会造成系统的大规模数据迁移,减少了开销。
-
精确的控制:
- 哈希槽为每个节点分配了明确的职责范围,因此 Redis 集群可以在扩展时进行精确的哈希槽迁移。与一致性哈希相比,哈希槽能提供更加明确和稳定的管理方式。
哈希槽的工作原理
-
Redis 集群中的所有键都通过
CRC16
算法计算一个哈希值,然后通过对 16384 取模来映射到某一个哈希槽。每个哈希槽由集群中的一个节点负责。 -
哈希槽数量固定为 16384,因此 Redis 集群能够确保数据的均匀分布,并且扩展时不会造成过多的数据迁移。
-
节点增加时,Redis 只需要将部分哈希槽迁移到新节点即可;节点移除时,Redis 会将该节点的哈希槽迁移到其他节点。
为什么RedisCluster会设计成16384个槽【 0 ~ 16383 】呢?
对于常见的
CRC16
实现(如CRC-16-ANSI
或CRC-16-IBM
),它们使用 16 位的校验和,因此可以有 2^16 = 65536 种不同的余数(哈希值)。为什么 Redis 集群使用 16384 个槽位?
antirez(Redis 的贡献者)在 2015年5月12日 评论道: 原因是:
- 正常的心跳包携带节点的完整配置,这些配置可以通过幂等的方式替换旧配置。也就是说,它们包含节点的槽位配置,以原始形式表示,使用 2k 的空间,具有 16k 个槽位,但如果使用 65k 个槽位,将会占用 8k 的空间,代价非常高。
- 同时,考虑到 Redis 集群的其他设计权衡,Redis 集群不太可能扩展到超过 1000 个主节点。
因此,16k 是一个合适的范围,确保每个主节点有足够的槽位,同时最大支持 1000
个主节点,但又足够小,可以轻松地将槽位配置表示为原始位图。请注意,在小型集群中,位图很难压缩,因为当节点数N
较小时,位图中会有
槽位/N
个比特被设置为 1,而这占用了大量的比特位。
- 槽位数 16384 既能保证带宽和内存的合理利用,又能适应最多 1000 个主节点的设计。
- 心跳包大小 是选择槽位数的一个重要因素,避免了大规模槽位带来的性能和带宽问题。
- 位图压缩 在节点数较少时的效率较低,但 16384 个槽位在多数情况下可以实现良好的压缩和性能平衡。
以下是对每个要点的详细解释和确认:
- 心跳消息过大
-
槽位为 65536 时,消息头过大:当槽位数为 65536 时,表示需要一个 65536 ÷ 8 = 8192 字节(8 KB)的位图来表示节点所负责的槽。这会导致心跳消息的大小过大,增加带宽负担,因为 Redis 节点需要频繁发送心跳消息(例如每秒一次)。如果每个消息头都达到 8 KB,对于网络带宽和性能来说,会产生显著的影响。
-
为什么 16384 是合适的:如果将槽位数减少到 16384(2^14),位图的大小将是 16384 ÷ 8 = 2 KB,这样可以有效减少心跳消息的负担,不会造成不必要的带宽浪费。
每个槽位 1 bit → 每 8 个槽位 1 字节。所以 “÷ 8”。
- 集群主节点数量限制
-
主节点数量限制为 1000:Redis 集群的主节点数量理论上可以更多,但实际设计中,Redis 的作者认为超过 1000 个主节点会导致其他问题,比如网络拥堵和复杂性增加。随着集群中节点数量的增加,心跳消息的传输开销也会增加,因此建议在实际部署中,主节点数量不要超过 1000。
-
16384 个槽位与节点数量的匹配:在 1000 个主节点以内,16384 个槽位足以满足需求,因为每个主节点平均分配到 16 个槽位。这是一个合理的分配,既保证了每个节点的负载适中,又不会浪费内存或带宽。使用 65536 个槽位会导致每个主节点需要管理更多槽位,甚至可能使某些主节点的负载不均。
- 槽位数与位图(Bitmap)压缩
-
节点数少时,压缩率低:位图的压缩效果与槽位的填充率有关。当集群中的节点数(N)较少时,位图的填充率较高(槽位数 / 节点数),导致大部分位都被设置为 1,这时位图的压缩效率较低。反之,节点数较多时,位图的填充率低,压缩效果更好。
-
16384 个槽位与压缩率:在一个相对较小的集群中(如少量节点),16384 个槽位使得位图的填充率适中,能够在保证性能的同时有效压缩。比如,假设有 100 个节点,每个节点负责大约 163 个槽位,位图的压缩效率更高,不会浪费太多空间。
总结
- 普通哈希 的问题:节点增加或减少时,需要大规模迁移数据,导致性能下降和系统负载不均。
- 一致性哈希 的优势:减少数据迁移、提升扩展性,但增加了虚拟节点的管理复杂度,并且在节点数量较多时,可能仍然出现负载不均的情况。
- 哈希槽 是 Redis 集群解决数据分片的核心。通过固定数量的哈希槽,Redis 集群能够高效地管理数据分配,简化节点的扩展、负载均衡和故障恢复。
Redis 集群的哈希槽机制在保证扩展性的同时,避免了使用一致性哈希时可能带来的复杂性和性能问题,是一个适应大规模、高并发环境下的高效分布式方案。
数据路由(Data Routing)
在 Redis Cluster 中,数据路由 是指根据客户端请求的 key
,将请求路由到存储该数据的正确 Redis 节点的过程。由于 Redis Cluster 使用 哈希槽 来分散数据到不同的节点,因此每个请求都需要通过哈希值确定该数据存储在哪个节点。当客户端请求的 key
不在当前节点的哈希槽范围内时,节点会返回 MOVED 错误,指示客户端应该向目标节点发起请求。客户端能够根据这个信息自动调整,确保数据请求能够成功完成。
其流程如下:
-
CLUSTER NODES 命令:
- 当客户端连接到 Redis Cluster 时,通常会通过
CLUSTER NODES
命令获取集群节点的信息。通过该命令,客户端可以知道哪些节点负责哪些哈希槽,从而进行适当的路由。 - 在 Redis Cluster 中,集群中的每个节点都有一个唯一的标识符,并且每个节点会跟踪集群中其他节点的状态和哈希槽分配情况。客户端会根据这些信息来决定如何分配请求。
- 当客户端连接到 Redis Cluster 时,通常会通过
-
哈希槽和键值映射:
- Redis Cluster 中的数据根据 哈希槽(slot)分布在不同的节点上。集群总共有 16,384 个哈希槽(编号从 0 到 16,383)。每个键(
key
)通过计算其 哈希值 来确定它应该存储在哪个哈希槽内,进而确定它应该存储在哪个节点上。 - 计算哈希槽的方式是通过 CRC16 校验算法对
key
进行哈希运算,然后通过对 16,384 取模来获得对应的哈希槽。
slot = CRC16(key) % 16384
每个 Redis 节点(主节点)会负责一定范围的哈希槽。客户端会根据哈希值,自动将请求路由到相应的节点。
- Redis Cluster 中的数据根据 哈希槽(slot)分布在不同的节点上。集群总共有 16,384 个哈希槽(编号从 0 到 16,383)。每个键(
-
客户端请求处理:
- 客户端在发送请求时,首先会计算
key
的哈希槽值,然后检查当前连接的节点是否负责该哈希槽。如果负责,则该节点会处理该请求并返回结果。 - 如果客户端请求的
key
不在当前节点负责的哈希槽范围内,当前节点会返回一个 MOVED 错误。这个错误包含目标节点的地址,告诉客户端该请求应该发送到哪个节点。 - 客户端收到
MOVED
错误后,会根据错误信息自动重新路由请求到目标节点。
例如:
-
假设客户端连接的是一个负责哈希槽范围
[0, 5461]
的节点,但客户端请求的数据key = "foo"
的哈希槽值是7000
,即该数据应该存储在另一个节点上。当前节点会返回一个类似的错误信息:MOVED 7000 192.168.1.100:7001
这意味着
key = "foo"
应该存储在192.168.1.100:7001
节点上。客户端会根据此信息重新连接到目标节点并重新发起请求。
- 客户端在发送请求时,首先会计算
-
请求转发:
- 由于客户端的自动路由机制,客户端在收到
MOVED
错误后会根据新的目标节点地址重新发送请求。这样,客户端在发生MOVED
错误时,能够自我调整,避免集群中节点之间的路由问题,保证数据请求的顺利进行。
- 由于客户端的自动路由机制,客户端在收到
-
多键操作:
- Redis Cluster 中的多键操作(如
MSET
、MGET
等)具有一定的限制。为了保证原子性,这些操作要求所有相关的key
必须位于相同的哈希槽内。也就是说,如果请求的多个key
的哈希槽不同,操作会失败,客户端会收到 ASK 错误,提示该操作需要路由到不同的节点。
- Redis Cluster 中的多键操作(如
Redis Cluster 配置与管理
配置
每个 Redis 节点都有一个配置文件(redis.conf
),通过以下配置来启用集群模式:
cluster-enabled yes
:启用集群模式。cluster-config-file nodes.conf
:指定集群的配置文件存储位置。cluster-node-timeout 15000
:指定节点超时的最大时间,超过此时间认为节点不可用。
集群的创建与管理
-
创建集群:Redis 提供了
redis-cli
工具来创建和管理集群。通过redis-trib.rb
或redis-cli --cluster
命令,可以创建和配置 Redis Cluster。-
可以通过以下命令启动多个 Redis 实例并组成一个 Redis 集群:
redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000
-
-
扩展集群:可以通过
redis-cli --cluster add-node
来扩展集群,添加新节点。 -
监控集群状态:可以通过
redis-cli --cluster check
命令检查集群的健康状态和分布情况。 -
集群管理:
- 使用
redis-trib
工具可以方便地管理 Redis 集群,如创建集群、添加节点、删除节点、重分片等。
- 使用
故障恢复与重分片
- 故障恢复:如果某个节点宕机,集群会自动进行故障转移,将从节点提升为新的主节点。管理员可以通过监控工具和日志检查故障发生的原因。
- 重分片:当节点的负载不均时,Redis Cluster 提供了
redis-trib.rb reshard
命令来进行槽的重新分配,平衡节点的存储负载。
Redis Cluster 的优点与缺点
优点
- 水平扩展:通过增加节点,Redis Cluster 能够动态扩展容量和处理能力。
- 高可用性:通过主从复制和自动故障转移,保证了集群的高可用性。
- 负载均衡:自动将数据分片到不同的节点上,避免单个节点的负载过重。
- 数据高可用:每个主节点都有从节点备份,主节点宕机时可以自动进行故障转移。
缺点
- 复杂性:集群模式的配置和管理相对较为复杂,需要了解节点的配置、分片机制和故障转移机制。
- 部分操作限制:一些 Redis 操作(如
MULTI/EXEC
事务)在集群模式下受到限制,跨分片的操作可能会导致性能问题。 - 单点故障风险:尽管 Redis Cluster 提供了故障转移,但如果集群的管理节点(如某个重要的主节点)发生故障,可能会导致服务中断。
总结
Redis Cluster 是一个高效、可扩展的分布式解决方案,它通过数据分片、主从复制、故障转移等机制提供了高可用性和可扩展性。它适用于需要处理大量数据和高并发的应用场景,尽管它的配置和管理相对复杂,但在现代分布式系统中,Redis Cluster 提供了非常强大的支持。
历史文章
MySQL数据库
- MySQL数据库笔记——数据库三范式
- MySQL数据库笔记——存储引擎(InnoDB、MyISAM、MEMORY、ARCHIVE)
- MySQL数据库笔记——常见的几种锁分类
- MySQL数据库笔记——索引介绍
- MySQL数据库笔记——事务介绍
- MySQL数据库笔记——索引结构之B+树
- MySQL数据库笔记——索引潜规则(回表查询、索引覆盖、索引下推)
- MySQL数据库笔记——索引潜规则(最左前缀原则)
- MySQL数据库笔记——常见慢查询优化方式
- MySQL数据库笔记——日志介绍
- MySQL数据库笔记——多版本并发控制MVCC
- MySQL数据库笔记——主从复制
Redis
- Redis数据库笔记——数据结构类型
- Redis数据库——Redis雪崩、穿透、击穿
- Redis数据库——内存淘汰机制
- Redis数据库笔记——内存分配器
- Redis数据库笔记——内存预分配
- Redis数据库笔记—— Hash(哈希)的扩容机制(rehash)
- Redis数据库笔记——ZSet的底层实现(跳表)
- Redis数据库笔记——布隆过滤器(BloomFilter)
- Redis数据库笔记——持久化机制
- Redis数据库笔记——部署模式
- Redis数据库笔记——主从复制
- Redis数据库笔记——Sentinel哨兵机制
原文地址:https://blog.csdn.net/haopingbiji/article/details/145001688
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!