redis cluster 架构
1. 架构组成主节点(Master):处理写入和读取请求。从节点(Replica):主节点的副本,提供数据冗余和读取负载平衡。哈希槽(Hash Slots):Redis Cluster 将数据映射到16384个哈希槽中,每个主节点负责一定数量的槽位。2. 节点数量最少要求:至少需要 3 个主节点以确保高可用性。如果希望克服故障并且保持数据可用性,建议配置一个或多个从节点。推荐配置:常见配置是每个主节点有一个或多个从节点。比如,6 个节点的配置为 3 主 + 3 从,或 3 主 + 2 从以提高可用性。3. 扩展性可以根据需求横向扩展,增加主节点数量,同时调整从节点的数量以提升性能和可靠性。4. 故障转移支持自动故障转移和节点的动态添加与移除。5. 节点间通信Cluster Bus 是 Redis Cluster 中专用的通信通道,用于节点间的高速数据传输。
redis cluster 端口
每个 Redis Cluster 节点需要两个开放的 TCP 连接:一个用于客户端服务的 Redis TCP 端口(例如 6379),另一个被称为集群总线端口。默认情况下,集群总线端口是通过将数据端口(例如 6379)加上 10000 来设置的(例如,16379),可以在配置中覆盖这个设置。集群总线是节点之间的通信通道,它使用一个二进制协议,该协议非常适合在节点之间交换信息,因为它占用很少的带宽并且处理时间短。节点使用集群总线进行故障检测、配置更新、故障转移授权等。客户端不应尝试与集群总线端口通信,而应使用 Redis 命令端口。但是,请确保在防火墙中打开这两个端口,否则 Redis 集群节点将无法通信。
要让 Redis Cluster 正常工作,对于每个节点,需要:打开客户端通信端口(通常是 6379),用于与客户端通信,并让所有需要访问集群的客户端以及使用客户端端口进行键迁移的其他集群节点都可以访问它。确保集群总线端口对其他集群节点可达。如果没有打开这两个 TCP 端口,集群将不能按预期工作。
redis cluster 分片
在 Redis Cluster 中,数据分片是通过哈希槽(hash slots)来实现的,而不是使用一致性哈希(consistent hashing)。整个键空间被划分为 16384 个哈希槽。每个键的哈希槽是通过计算键的 CRC16 校验值然后对 16384 取模来确定的。
集群中的每个节点都负责一部分哈希槽。例如,在一个有三个节点的集群中:节点 A 包含从 0 到 5500 的哈希槽。
节点 B 包含从 5501 到 11000 的哈希槽。
节点 C 包含从 11001 到 16383 的哈希槽。
这种设计使得添加和移除集群节点变得非常容易。如果想添加一个新节点,只需要将从其他节点的哈希槽移动到新节点即可。同样,如果想从集群中移除一个节点,只需将该节点负责的哈希槽移动到其他节点。一旦原节点没有负责任何哈希槽,就可以将其从集群中完全移除。值得注意的是,移动哈希槽并不需要停止任何操作。因此,添加和移除节点,或者更改节点持有的哈希槽百分比,都不需要停机。Redis Cluster 支持对多个键进行操作,只要这些键属于同一个哈希槽。用户可以使用名为哈希标签的特性来强制多个键属于同一个哈希槽。哈希标签在 Redis Cluster 规范中有详细说明。其基本思想是,如果键中包含一对大括号 {} 内的子字符串,只有括号内的字符串会被用于哈希计算。例如,键 "user:{123}:profile" 和 "user:{123}:account" 会保证位于同一个哈希槽内,因为它们有相同的哈希标签。因此,可以在同一多键操作中对这两个键进行操作。
Redis Cluster 主-从模型
在 Redis Cluster 中,每个哈希槽有一个主节点(master)和最多 N 个从节点(replica)。这种设计确保了系统在某些主节点发生故障或者无法与大多数节点通信时,依然能够保持可用性。以下是所述模型的关键点:1. 主节点与从节点:每个主节点负责一部分哈希槽,并且可以有一个或多个从节点进行复制。在例子中,节点 A、B、C 是主节点,而 A1、B1、C1 是对应的从节点。2. 故障恢复:如果主节点 B 发生故障且没有可用的从节点,集群将无法继续工作。然而,添加从节点后,如果 B 失败,B1 可以被提升为新的主节点,确保集群可以继续运作。3. 高可用性限制:需要注意的是,如果主节点 B 和它的从节点 B1 同时故障,Redis Cluster 将无法继续工作,因为没有可用的主节点来处理哈希槽 5501-11000。4. 集群扩展性:在创建集群时或之后,可以添加从节点,以提高系统的可靠性和扩展性,通过分散数据并增加冗余,减少单点故障的可能性。
Redis Cluster 一致性
Redis Cluster 不保证强一致性。这意味着在某些条件下,Redis Cluster可能会丢失已经由系统向客户端确认的写操作。这是由Redis Cluster的一些设计和运行机制导致的。首先,Redis Cluster使用异步复制。这意味着在写操作时,会发生以下情况:客户端向主节点B写入数据。主节点B向客户端回复确认(OK)。主节点B将其写入操作复制到其从节点B1、B2和B3。在这个过程中,主节点B不会在从节点B1、B2、B3确认写入之前就回复客户端,因为这样会导致Redis的延迟显著增加。因此,如果你的客户端进行了写操作,主节点B已经确认写入,但在向从节点复制数据之前崩溃,那么一个未接收到写入的从节点可能会被提升为主节点,导致该写操作永久丢失。这种情况类似于大多数配置为每秒将数据刷新到磁盘的数据库系统。你在传统的非分布式数据库系统中遇到的这种情况,也可以应用到Redis Cluster。你可以通过强制数据库在回复客户端之前将数据刷新到磁盘来提高一致性,但这通常会导致性能显著降低。在Redis Cluster的情况下,这相当于同步复制。基本上,性能和一致性之间需要做出权衡。Redis Cluster在绝对需要时支持同步写入,通过WAIT命令实现。这大大降低了丢失写操作的可能性。然而,请注意,即使使用同步复制,Redis Cluster也不实现强一致性:在更复杂的故障情况下,一个未接收到写入的副本仍可能被选为主节点。还有一个可能导致Redis Cluster丢失写操作的场景,那就是网络分区,其中客户端与少数实例(至少包含一个主节点)被孤立。以一个由A、B、C、A1、B1、C1六个节点组成的集群为例,其中有三个主节点和三个副本。假设有一个客户端Z1。网络分区发生后,一种可能是A、C、A1、B1、C1在一个网络分区内,而B和Z1在另一个网络分区内。Z1仍然能够向B写入数据,B也会接受这些写入。如果网络分区在短时间内恢复,集群将恢复正常运行。然而,如果网络分区持续足够长的时间以至于B1在多数分区侧被提升为主节点,那么Z1在期间发送给B的写操作将会丢失。这个丢失写操作的窗口时间取决于Redis Cluster的配置指令——节点超时时间。
redis 集群配置项
cluster-enabled <yes/no>: 如果是,则在特定 Redis 实例中启用 Redis 集群支持。否则,实例将照常作为独立实例启动。cluster-config-file <filename>:请注意,尽管此选项的名称如此,但这不是用户可编辑的配置文件,而是 Redis 集群节点在每次发生更改时自动保留集群配置(基本上是状态)的文件,以便能够在启动时重新读取它。该文件列出了集群中的其他节点、它们的状态、持久变量等内容。通常,由于某些消息接收,此文件会在磁盘上被重写和刷新。cluster-node-timeout <milliseconds>: Redis 集群节点在未被视为失败的情况下不可用的最长时间。如果主节点在超过指定时间内无法访问,则其副本将对其进行故障转移。此参数控制 Redis Cluster 中的其他重要内容。值得注意的是,在指定时间内无法访问大多数主节点的每个节点都将停止接受查询。cluster-slave-validity-factor <factor>: 如果设置为零,则副本将始终认为自身有效,因此将始终尝试故障转移主服务器,而不管主服务器和副本服务器之间的链接保持断开连接的时间长短。如果该值为正数,则最大断开连接时间的计算方法是节点超时值乘以此选项提供的系数,如果节点是副本,则当主链路断开连接的时间超过指定时间时,它不会尝试启动故障转移。例如,如果节点超时设置为 5 秒,有效性因子设置为 10,则与 master 断开连接超过 50 秒的副本将不会尝试故障转移其 master。请注意,如果没有能够对其进行故障转移的副本,则任何不为零的值都可能导致 Redis 集群在主节点发生故障后不可用。在这种情况下,只有当原始 master 重新加入集群时,集群才会恢复可用。cluster-migration-barrier <count>: 主服务器将保持连接的最小副本数,以便另一个副本迁移到不再被任何副本覆盖的主服务器。cluster-require-full-coverage <yes/no>: 如果此项设置为 yes,则默认情况下,如果任何节点未覆盖一定比例的密钥空间,则集群将停止接受写入。如果该选项设置为 no,则集群仍将提供查询,即使只能处理有关键子集的请求。cluster-allow-reads-when-down <yes/no>: 如果此选项设置为 no(默认情况下),则当集群被标记为失败时(当节点无法达到主节点仲裁或未达到完全覆盖时),Redis 集群中的节点将停止提供所有流量。这可以防止从不知道集群中更改的节点读取可能不一致的数据。此选项可以设置为 yes 以允许在 fail 状态期间从节点进行读取,这对于希望优先考虑读取可用性但仍希望防止不一致写入的应用程序非常有用。当使用只有一个或两个分片的 Redis Cluster 时,也可以使用它,因为它允许节点在 master 发生故障但无法自动故障转移时继续提供写入服务。
参考文档
https://redis.io/docs/latest/operate/oss_and_stack/management/scaling/