Redis集群(一)
一、简介
- redis是一个开源的key value存储系统,受到了广大互联网公司的青睐。redis3.0版本之前只支持单例模式,在3.0版本及以后才支持集群,我这里用的是redis3.0.0版本;
- redis集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点;
- redis集群是没有统一的入口的,客户端(client)连接集群的时候连接集群中的任意节点(node)即可,集群内部的节点是相互通信的(PING-PONG机制),每个节点都是一个redis实例;
- 为了实现集群的高可用,即判断节点是否健康(能否正常使用),redis-cluster有这么一个投票容错机制:如果集群中超过半数的节点投票认为某个节点挂了,那么这个节点就挂了(fail)。这是判断节点是否挂了的方法;
- 那么如何判断集群是否挂了呢? -> 如果集群中任意一个节点挂了,而且该节点没有从节点(备份节点),那么这个集群就挂了。这是判断集群是否挂了的方法;
- 那么为什么任意一个节点挂了(没有从节点)这个集群就挂了呢? -> 因为集群内置了16384个slot(哈希槽),并且把所有的物理节点映射到了这16384[0-16383]个slot上,或者说把这些slot均等的分配给了各个节点。当需要在Redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果。再把这个结果对16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的slot就无法使用,那么就会导致集群无法正常工作。
- 综上所述,每个Redis集群理论上最多可以有16384个节点。
二、三种集群模型
1、主从模型
在主从复制中,数据库分为两类:主数据库(master)和从数据库(slave)。
当slave启动后,主动向master发送SYNC命令。master接收到SYNC命令后在后台保存快照(RDB持久化)和缓存保存快照这段时间的命令,然后将保存的快照文件和缓存的命令发送给slave。slave接收到快照文件和命令后加载快照文件和缓存的执行命令。
为了在主节点子集发生故障或无法与大多数节点通信时保持可用,Redis Cluster使用主从模型,其中每个哈希槽具有从1(主节点本身)到N个副本(N个) -1个其他从属节点)。在具有节点A,B,C的示例集群中,如果节点B失败,则集群将无法继续,因为我们不再有办法为5501-11000范围内的哈希槽提供服务。
但是,在创建集群(或稍后)时,我们向每个主节点添加一个从属节点,以便最终集群由作为主节点的A,B,C和作为从属节点的A1,B1,C1组成,如果节点B发生故障,系统将能够继续。
节点B1复制B,并且B发生故障,群集会将节点B1提升为新的主节点,并将继续正常运行。
但是请注意,如果节点B和B1同时失败,则Redis Cluster无法继续运行。
解决问题:
解决Redis单例下,数据体量大与数据备份造成的性能瓶颈问题,redis cluster 主从模型很好的解决这个问题。可以将读写操作分离到不同redis实例上,提高系统的吞吐量
引入新的问题:
1、配置重连问题
不同的redis实例,需要不同的ip和端口对应,如果某个实例下线了,需要重新更改配置进行重连
2、故障转移问题
如果某个结点故障下线,无法进行故障转移,比如某个master下线,对应的slave结点也只能进行读操作,无法进行写操作,替代不了master的功能。
特点如下:
- 主数据库可以进行读写操作,当读写操作导致数据变化时会自动将数据同步给从数据库
- 从数据库一般都是只读的,并且接收主数据库同步过来的数据
- 一个master可以拥有多个slave,但是一个slave只能对应一个master
- slave挂了不影响其他slave的读和master的读和写,重新启动后会将数据从master同步过来
- master挂了以后,不影响slave的读,但redis不再提供写服务,master重启后redis将重新对外提供写服务
- master挂了以后,不会在slave节点中重新选一个master
缺点如下:
master节点在主从模式中唯一,若master挂掉,则redis无法对外提供写服务,不具备高可用性。
2、哨兵模型
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance)。
监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会进行选举,将其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
解决问题:
Sentinel哨兵模式,确实实现自动故障切换。提供稳定的服务,解决主从模型引入的新问题。
未解决的问题:
在哨兵模式中,仍然只有一个Master节点。当并发写请求较大时,哨兵模式并不能缓解写压力。
特点如下:
- Sentinel可以监控任意多个Master和该Master下的Slaves。(即多个主从模式)
- 同一个哨兵下的、不同主从模型,彼此之间相互独立。
- Sentinel会不断检查Master和Slaves是否正常。
- 监控同一个Master的Sentinel会自动连接,组成一个分布式的Sentinel网络,互相通信并交换彼此关于被监视服务器的信息,在sentinel网络中,只要还有一个sentinel活着,就可以实现故障切换。当只有一个sentinel的时候,如果这个sentinel挂掉了,那么就无法实现自动故障切换了。
- 故障转移:投票(半数原则),当任何一个Sentinel发现被监控的Master下线时,会通知其它的Sentinel开会,投票确定该Master是否下线(半数以上,所以sentinel通常配奇数个)。
- 故障转移:选举,当Sentinel确定Master下线后,会在所有的Slaves中,选举一个新的节点,升级成Master节点。其它Slaves节点,转为该节点的从节点。
- 原Master重新上线,当原Master节点重新上线后,自动转为当前Master节点的从节点。
3、Redis cluster 集群
从Redis 3.0
之后版本支持 Redis Cluster
集群,Redis Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。
目标:
- 高达1000个节点的高性能和线性可扩展性。没有代理,使用异步复制,并且不对值执行合并操作。
- 可接受的写安全程度:系统尝试(以尽力而为的方式)保留所有来自与大多数主节点连接的客户端的写操作。通常,有一些小窗口,在这些小窗口中,可能会丢失已确认的写入。当客户端位于少数分区中时,丢失已确认写入的Windows更大。
- 可用性:Redis Cluster能够在大多数主节点可访问且每个不再可用的主节点上至少有一个可访问的从节点的分区中生存。而且,通过使用副本迁移,不再由任何从属复制的主将从一个由多个从属覆盖的主接收一个。
高性能:
- 采用了异步复制机制,向某个节点写入数据时,无需等待其它节点的写数据响应。
- 无中心代理节点,而是将客户端直接重定向到拥有数据的节点。
- 对于N个 Master 节点的 Cluster ,整体性能理论上相当于单个 Redis 的性能的N倍。
高可用:
采用了主从复制的机制,Master 节点失效时 Slave 节点自动提升为 Master 节点。如果 Cluster 中有N个 Master 节点,每个 Master 拥有1个 Slave 节点,那么这个 Cluster 的失效概率为 1/(2*N-1),可用概率为 1-1/(2*N-1)。
高可扩展:
可支持多达1000
个服务节点。随时可以向 Cluster 中添加新节点,或者删除现有节点。Cluster 中每个节点都与其它节点建立了相互连接
一致性:
Redis Cluster无法保证强一致性。实际上,这意味着在某些情况下,Redis Cluster可能会丢失系统认可给客户端的写入。
Redis Cluster可能丢失写入的第一个原因是因为它使用异步复制。这意味着在写入期间会发生以下情况:
-
- 您的客户写信给主B。
- 主B向您的客户答复“确定”。
- 主机B将写操作传播到其从机B1,B2和B3。
B在回复客户端之前不会等待B1,B2,B3的确认,因为这会对Redis造成延迟性的延迟,因此,如果您的客户端写了一些东西,B会确认写,但是在崩溃之前崩溃由于能够将写操作发送到其从属服务器,因此一个从属服务器(未接收到写操作)可以升级为主服务器,从而永远丢失该写操作。
特点如下:
- 所有的 Redis 节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- 节点的fail是通过集群中超过半数的节点检测失效时才生效。
- 客户端与 Redis 节点直连,不需要中间Proxy层,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
- Redis Cluster 把所有的物理节点映射到[0-16383] slot(哈希槽) 上(不一定是平均分配),Cluster 负责维护node <-> slot <-> value。
- Redis 集群预分好 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384 的值,决定将一个 key 放到哪个桶中。
主要组件:
- 密钥分配模型
密钥空间被划分为16384个插槽,有效地设置了16384个主节点的群集大小的上限(但是建议的最大节点大小约为1000个节点)。
群集中的每个主节点都处理16384个哈希槽的子集。当没有正在进行的集群重新配置时(即哈希槽从一个节点移动到另一个节点),该集群是稳定的。当群集稳定时,单个哈希槽将由单个节点提供服务(但是,服务节点可以具有一个或多个从属设备,在发生网络分裂或故障的情况下可以替换该从属设备,并且可以用于扩展)可接受过时数据的读取操作)。
键映射到哈希槽的基本算法:HASH_SLOT = CRC16(key) mod 16384
- 键哈希标签
哈希标签是一种确保在同一哈希槽中分配多个密钥的方法。这用于在Redis Cluster中实现多键操作。
为了实现哈希标签,在某些情况下,密钥的哈希槽以略有不同的方式计算。如果密钥包含一个“{…}”图案仅之间子 {
和}
,以获得散列时隙被散列。但是,由于可能存在多次出现{
或}
算法由以下规则很好地指定:
-
-
如果键包含一个
{
字符。 -
如果有一个
}
字符的右{
-
AND如果在的第一次出现
{
和的第一次出现之间存在一个或多个字符}
。
-
如果键包含一个
- 集群节点属性
每个节点在集群中都有唯一的名称。节点名称是160位随机数的十六进制表示形式,是在节点首次启动时获得的(通常使用/ dev / urandom)。节点将其ID保存在节点配置文件中,并将永久使用相同的ID,或者至少在系统管理员未删除节点配置文件或通过CLUSTER RESET命令请求硬重置的情况下使用该ID 。
节点ID用于标识整个集群中的每个节点。给定节点可以更改其IP地址,而无需也更改节点ID。群集还能够检测IP /端口的更改,并使用在群集总线上运行的八卦协议进行重新配置。
节点ID并不是与每个节点关联的唯一信息,而是唯一始终全局一致的信息。每个节点还具有以下关联的信息集。一些信息与该特定节点的集群配置详细信息有关,并且最终在整个集群中保持一致。某些其他信息(例如上次对节点执行ping操作)则是每个节点本地的。
每个节点都维护着有关群集中其他节点的以下信息:节点ID,节点的IP和端口,一组标志,如果将节点标志为slave
,则该节点的主节点是什么?对节点执行ping操作,最后一次接收到pong时,将显示该节点的当前 配置时期(在本规范的后面部分进行说明),链接状态以及最终服务的哈希槽集。
- 集群总线
每个Redis Cluster节点都有一个额外的TCP端口,用于接收来自其他Redis Cluster节点的传入连接。此端口与用于从客户端接收传入连接的普通TCP端口处于固定偏移量。要获得Redis Cluster端口,应在常规命令端口中添加10000。例如,如果Redis节点正在端口6379上侦听客户端连接,则群集总线端口16379也将打开。
节点到节点的通信仅使用群集总线和群集总线协议进行:群集协议是由不同类型和大小的帧组成的二进制协议。未公开记录集群总线二进制协议,因为它不打算供外部软件设备使用该协议与Redis Cluster节点通信。但是,您可以通过阅读Redis Cluster源代码中的cluster.h
和cluster.c
文件来获取有关集群总线协议的更多详细信息 。
- 集群拓扑
Redis Cluster是一个完整的网格,其中每个节点都使用TCP连接与其他每个节点连接。
在N个节点的群集中,每个节点都有N-1个传出TCP连接和N-1个传入连接。
这些TCP连接始终保持活动状态,并且不会按需创建。当节点希望对集群总线中的ping做出回应时,会在等待足够长的时间以将节点标记为不可访问之前进行Pong响应,它将尝试通过从头开始重新连接来刷新与该节点的连接。
虽然Redis Cluster节点形成一个完整的网格,但是节点使用八卦协议和配置更新机制以避免在正常情况下在节点之间交换太多消息,因此交换的消息数量不是指数级的。
- 节点握手
节点始终接受群集总线端口上的连接,即使收到ping节点不受信任,甚至会在收到ping时回复ping。但是,如果不将发送节点视为群集的一部分,则接收节点将丢弃所有其他数据包。
一个节点仅以两种方式将另一个节点作为群集的一部分:
这意味着只要我们在任何连接图中加入节点,它们最终将自动形成完全连接图。这意味着群集能够自动发现其他节点,但前提是存在系统管理员强制建立的信任关系。
这种机制使群集更加健壮,但可以防止更改IP地址或其他与网络相关的事件后,不同的Redis群集意外混合。
参考链接:
官网:https://redis.io/topics/cluster-spec 集群规范