前言:
现时兄弟们对“集群横向扩展机制”大概比较注重,我们都想要学习一些“集群横向扩展机制”的相关资讯。那么小编也在网上搜集了一些对于“集群横向扩展机制””的相关文章,希望兄弟们能喜欢,咱们一起来学习一下吧!大纲
1.Redis使用sync命令实现的复制功能
2.Redis使用psync命令实现的复制功能
3.Redis主从服务器之间的心跳检测
4.从服务器如何实现复制主服务器的(复制的实现)
5.Redis的复制拓扑介绍
6.Redis主从复制数据延迟的处理
7.Redis主从复制的问题
8.Redis Sentinel和高可用
9.Redis如何保存更多的数据
10.一个普通Redis服务器的初始化过程
11.一个Sentinel服务器的初始化过程
12.Sentinel如何向主从服务器获取信息和发送信息
13.Sentinel如何检测主客观下线并实现故障转移
14.Sentinel配置优化和部署技巧
15.Sentinel客户端的基本实现原理
16.Sentinel的基本实现原理(哨兵机制的基本流程)
17.Sentinel的高可用读写分离
18.关于Sentinel的一些问题
19.Redis Cluster集群的简介
20.Redis Cluster集群搭建的步骤
21.Redis Cluster集群执行命令的实现原理
22.Redis Cluster集群节点通信的实现原理
23.Redis Cluster集群复制与故障转移的实现原理
24.通过Smart客户端支持Redis Cluster集群
25.Redis Cluster集群的补充说明
26.Redis Cluster集群的倾斜问题
27.Redis Cluster集群的核心问题
1.Redis使用sync命令实现的复制功能
(1)Redis复制功能的两个核心操作
(2)从服务器对主服务器发起同步操作
(3)主服务器对从服务器进行命令传播操作
(4)旧版使用sync命令进行同步操作的问题
(1)Redis复制功能的两个核心操作
Redis的复制功能分为同步和命令传播两个操作。
同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
命令传播操作用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。
(2)从服务器对主服务器发起同步操作
从服务器对主服务器的同步操作,需要通过向主服务器发送sync命令来完成,以下是具体的处理步骤。
步骤一:从服务器向主服务器发送sync命令。
步骤二:主服务器收到sync命令后,便会执行bgsave命令在后台生成一个RDB快照文件,并使用一个客户端输出缓冲区(复制缓冲区)记录从现在开始执行的所有写命令。
步骤三:当主服务器的bgsave命令执行完毕时,主服务器会将bgsave命令生成的RDB快照文件发送给从服务器。从服务器接收并载入这个RDB快照文件,将自己的数据库状态更新至主服务器执行bgsave命令时的数据库状态。
步骤四:主服务器将记录在复制缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令将数据库状态更新至主服务器数据库当前所处的状态。
(3)主服务器对从服务器进行命令传播操作
在同步操作执行完毕后,主从服务器两者的数据库将达到一致状态。此后每当主服务器执行客户端发送的写命令时,为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令传播操作,将自己执行的写命令发送给从服务器执行。
(4)旧版使用sync命令进行同步操作的问题
对于初次复制来说,旧版使用sync命令实现的复制功能能很好完成任务。但对于断线后重复制来说,旧版使用sync命令实现的复制功能的效率却非常低。因为无论主从服务器断开的时间有多短,主从服务器都要重新执行一次sync命令。
sync命令是一个非常耗费资源的操作,原因有三:包括生成RDB、发送RDB、加载RDB。
原因一:主服务器需要执行bgsave命令来生成RDB快照文件,这个生成操作会耗费主服务器大量CPU、内存和磁盘IO
原因二:主服务器需要将生成的RDB快照文件发送给从服务器,会耗费主从服务器大量的带宽和流量
原因三:接收到RDB快照文件的从服务器需要载入RDB快照文件,在载入期间会阻塞主进程而导致无法处理命令请求
(5)为什么主从库间的复制不使用AOF文件
原因一:AOF文件记录的是文本协议格式的内容,RDB文件是经过LZF算法紧凑压缩的二进制文件。无论是把RDB加载到磁盘还是通过网络传输,IO效率都比加载和传输AOF高
原因二:在从库进行恢复时,使用RDB文件进行恢复的效率也高于AOF文件
2.Redis使用psync命令实现的复制功能
(1)新版使用psync命令进行同步操作
(2)实现部分复制功能需要三类变量
(3)主从服务器的复制偏移量
(4)主服务器的复制积压缓冲区
(5)服务器的运行ID
(6)psync命令的整体运行流程
(7)psync命令的全量复制流程
(8)psync命令的部分复制流程
(9)复制缓冲区和复制积压缓冲区对比
(1)新版使用psync命令进行同步操作
从Redis2.8开始,便使用psync命令代替sync命令来执行复制时的同步操作,psync命令具有全量复制和部分复制两种模式。
一.全量复制用于处理初次复制的情况
全量复制的执行步骤和sync命令的执行步骤基本一样,都是通过让主服务器创建并发送RDB快照文件以及向从服务器发送保存在复制缓冲区里面的写命令来进行同步。
二.部分复制用于处理断线后重复制情况
当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并处理这些命令即可。
(2)实现部分复制功能需要三类变量
一.主服务器的复制偏移量和从服务器的复制偏移量
二.主服务器的复制积压缓冲区
三.服务器的运行ID
(3)主从服务器的复制偏移量
参与复制的主从节点都会维护自身的复制偏移量。主服务器每次向从服务器传播N个字节时,就将自己的复制偏移量加上N。从服务器每次收到主服务器传播来的N个字节时,就将自己的复制偏移量加上N。从节点会每秒上报自身的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量。
(4)主服务器的复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度的先进先出队列,默认大小为1MB。当主服务器进行命令传播时,它不仅会将写命令发送给所有从服务器,还会将写命令入队列复制积压缓冲区。主服务器的复制积压缓冲区里,会保存最近传播的写命令,且会为队列中的每个字节记录相应的复制偏移量。
当从服务器重新连上主服务器时,从服务器会通过psync命令将自己的复制偏移量发送给主服务器。如果偏移量之后的数据仍然存在于复制积压缓冲区里,那么主服务器将对从服务器执行部分复制操作,否则主服务器对从服务器执行全量复制操作。
(5)服务器的运行ID
服务器启动时会生成一个运行ID。当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID发送给从服务器,从服务器会保存主服务器的运行ID。当从服务器断线并重新连上一个主服务器时,从服务器将会向当前的主服务器发送之前保存的运行ID。如果从服务器之前保存的运行ID和当前连接的主服务器的运行ID相同,则可以尝试执行部分复制,否则主服务器对重服务器执行全量复制。
如果只使用IP + 端口方式识别主服务器,而不使用服务器的运行ID进行识别,那么主服务器重启后变更的数据库(替换RDB或AOF文件),此时从服务器基于偏移量复制是不安全的。
Redis关闭然后再重启,它的服务器运行ID会随之改变,可以使用debug reload命令重新加载RDB并保持运行ID不变。
(6)psync命令的整体运行流程
步骤一:从服务器接到客户端发来的replicaof命令
步骤二:从服务器判断这是否是第一次执行复制
如果是,则向主服务器发送"psync ? -1",主服务器会返回"+fullresync"执行全量复制。如果不是,则向主服务器发送"psync"。
步骤三:从服务器判断主服务器是否返回"+continue"
如果是 ,则表示主服务器执行部分复制。如果不是,则主服务器返回"+fullresync"执行全量复制。
(7)psync命令的全量复制流程
步骤一:从服务器发送psync命令进行数据同步。由于是第一次复制,从服务器没有复制偏移量和主服务器的运行ID,所以发送"psync ? -1"
步骤二:主服务器根据"psync ? -1"解析出当前为全量复制,于是回复从服务器服务"+fullresync"响应
步骤三:从服务器接收主服务器的响应数据,保存主服务器的运行ID和复制偏移量
步骤四:主服务器执行bgsave命令保存RDB快照文件到本地
步骤五:主服务器发送RDB快照文件给从服务器,从服务器把接收到的RDB快照文件保存在本地并作为自己的数据文件
步骤六:主服务器生成RDB快照文件到从服务器收到RDB快照文件期间,主服务器的写命令会保存在复制缓冲区(客户端输出缓冲区),当从服务器加载完RDB快照文件后,主服务器再把复制缓冲区的数据发给从服务器,从而保证主从服务器之间的数据一致性
步骤七:从服务器收到RDB快照文件后会进行加载,如果从服务器开启了AOF持久化,则会执行bgrewriteaof命令
(8)psync命令的部分复制流程
步骤一:当主从服务器出现网络中断并超过repl-timeout时间,主节点会认为从节点故障并中断复制连接
步骤二:主节点继续响应命令,并会保存一段时间的写命令数据到复制积压缓冲区
步骤三:主从节点重连后,从节点会将之前保存的主服务器运行ID和复制偏移量作为psync命令的参数,发给主节点请求继续复制
步骤四:主节点收到从节点的请求后,会先核对服务器运行ID是否一致,复制偏移量对应的数据是否还在复制积压缓冲区里,然后再决定是执行部分复制还是执行全量复制
(9)复制缓冲区和复制积压缓冲区对比
主节点会把收到的写操作命令,既写到复制缓冲区replication buffer,也写到复制积压缓冲区repl_backlog_buffer。
一.使用AOF缓冲区的原因
由于Redis使用单线程响应命令,如果每次写AOF文件命令都直接追加到硬盘,那么性能则取决于硬盘。先写入AOF缓冲区,Redis可以提供多种AOF缓冲区同步硬盘策略,在性能和安全性上作出平衡。
二.使用AOF重写缓冲区的原因
由于Redis服务器使用单线程来处理命令请求,所以Redis将AOF重写程序放到子进程里执行。子进程在AOF重写完成后,可能会导致数据不一致问题的,因此需要解决数据不一致的问题。
三.使用复制缓冲区的原因
每个从节点都有一个,保证复制期间,主从服务器的数据是一致的。每个客户端连上Redis服务器后,Redis服务器都会分配一个客户端输出缓冲区。主服务器先把数据写到客户端输出缓冲区中,然后再把客户端输出缓冲区里的数据写到客户端套接字中,最后通过网络连接发送给客户端。
所以主从同步和命令传播时,从库作为一个客户端会通过客户端输出缓冲区,保证主从节点数据一致。参数client-output-buffer-limit限制其大小,超过其大小会断开客户端连接,可能引发复制风暴。复制风暴就是多个主服服务器或者一个主服务器被多个从服务器在短时间内进行全量复制。
四.使用复制积压缓冲区的原因
从节点共享,保证主从服务器断连恢复后,可以尽量使用部分复制来提升性能。复制积压缓冲区是为了从节点断连后能找到主从差异数据而设计的环形缓冲区,可以避免全量复制。
3.Redis主从服务器之间的心跳检测
第一:在命令传播阶段,从服务器默认会以每秒一次向主服务器发送"replconf ack"命令,实现实时监测主从节点网络状态以及上报自身偏移量。
第二:主服务器默认每隔10秒对从服务器发送ping请求,判断从服务器的存活性和连接状态。
总结就是:从发主偏移量每秒一次,主发从ping请求每十秒一次。
4.从服务器如何实现复制主服务器的(复制的实现)
步骤一:设置主服务器的地址和端口
从服务器收到命令"replicaof ip port"后,设置其服务器状态。
步骤二:建立套接字连接
从服务器根据设置的IP和端口,创建连向主服务器的套接字连接。如果从服务器创建的套接字能连向主服务器,那么从服务器将为该套接字关联复制处理器。
步骤三:发送ping命令
从服务器成为主服务器的客户端后,做的第一件事就是向主服务器发送一个ping请求,以检查套接字的读写是否正常,确认主服务器能否正常处理命令请求。
步骤四:身份验证
从服务器收到主服务器返回的pong回复后,表明一切正常,开始身份验证。
步骤五:发送端口信息
身份验证通过后,从服务器向主服务器发送从服务器的监听端口号。
步骤六:同步(psync的全量复制和部分复制流程)
从服务器向主服务器发送psync命令执行同步操作。主服务器执行同步操作后,主服务器也会成为从服务器的客户端。如果是全量复制,那么主服务器需要成为从服务器的客户端,才能将复制缓冲区里的写命令发送给从服务器。如果是部分复制,那么主服务器需要成为从服务器的客户端,才能将复制积压缓冲区的写命令发送给从服务器。
步骤七:命令传播(基于长连接的命令传播)
完成同步后,主从服务器会进入命令传播阶段,保证主从服务器的数据一致性。
5.Redis的复制拓扑介绍
(1)一主一从结构(简单)
当应用写命令并发量较高,且需要持久化时,可以只在从节点开启AOF。这样既保证数据安全,又避免持久化对主节点的影响。但要注意主节点重启时,由于主节点是没持久化的,需要从节点先断开与主节点的复制,然后再重启主节点,避免从节点数据清空。
(2)一主多从结构(适合读多不适合写多)
利用多个从节点实现读写分离。对于读占比较大的场景,可以把读请求发送到从节点来分担主节点压力,日常的慢查询命令如keys、sort也可以在其中一台从节点上执行。但对于写并发量较高(写多)的场景,多个从节点会导致主节点的写命令的多次发送,从而过度消耗带宽影响主节点。
注意:复制风暴就是多个主节点或一个主节点被多个从节点短时间全量复制,解决方法是使用树状结构。
(3)树状主从结构(适合写多读多)
从节点不但可以复制主节点的数据,也可以作为其他从节点的主节点继续向下复制。通过引入复制中间层,可以有效降低主节点负载和需要传给从节点的数据量。所以当主节点需要挂载多个从节点时,可以采用树状主从结构降低主节点压力。
6.Redis主从复制数据延迟的处理
Redis复制数据的延迟是由异步复制导致的,无法避免。延迟时间取决于网络带宽和命令阻塞的情况。可以通过监听主从节点的复制偏移量,当延迟较大时触发报警或通知客户端避免读取延迟高的从节点。
说明一:监控程序定期检查主从节点的偏移量,它们的差值就是主从节点延迟的字节量
说明二:当延迟字节量过高时,可以采用ZooKeeper的监听回调机制实现客户端通知
说明三:客户端接到具体的从节点高延迟通知后,修改读命令路由到其他从节点或主节点上。延迟恢复后再次通知客户端,恢复从节点的读命令请求
注意:为了保证复制的数据一致性,从节点自身不会主动删除超时数据,但会检查键的过期时间来决定是否返回数据。
7.Redis主从复制的优缺点
(1)主从复制的好处
(2)主从复制的问题
(3)Redis主从复制模式下的高可用问题
(1)主从复制的好处
好处一:主挂了从可以顶上
好处二:从可以分担主的读压力
(2)主从复制的问题
问题一:一旦主节点出现故障,需要手动将一个从节点晋升为主节点,需要修改应用的主节点地址,需要通过命令修改其他从节点复制新的主节点,整个过程需要人工干预
问题二:主节点的写能力受单机限制
问题三:主节点存储能力受单机限制
问题一是Redis的高可用问题,问题二和问题三是Redis的分布式问题。
(3)Redis主从复制模式下的高可用问题
一旦主节点挂了,需要人工干预,除了带来运维的不方便,应用方也无法实时感知主节点的变化,必然造成一定的写数据丢失和读数据错误,甚至造成应用服务不可用。而且整个故障转移过程人工介入,实时性和准确性无法保障。
即便自动化整个故障转移过程,也存在问题。
问题一:判断主节点不可达的机制是否健全和标准(主节点是否真的挂了)
问题二:如果有多个从节点,怎么保证只有一个被晋升为主节点(选择哪个从节点作为主节点)
问题三:通知客户端新的主节点机制是否足够健壮(怎么把新主节点的信息通知给从节点和客户端)
8.Redis Sentinel和高可用
Redis哨兵主要负责三个任务:监控、选主、通知。
Redis Sentinel是一个分布式架构,其中包含若干个Sentinel节点和若干个Redis数据节点。每个Sentinel节点会对Redis数据节点和其余Sentinel节点进行监控,当它发现节点不可达时,会对不可达节点做下线标识。如果被标识的是主节点,它还会和其他Sentinel节点进行协商。当大多数节点都认为主节点不可达时,这些Sentinel节点会选举出一个Sentinel节点来完成自动故障转移的工作,同时会将这个变化实时通知给Redis的应用方,整个过程是自动的,实现了真正的高可用。
Redis Sentinel比Redis主从复制模式只是多了若干个Sentinel节点,Redis Sentinel并没有针对Redis节点做特殊处理。
9.Redis如何保存更多的数据
(1)纵向扩展
升级单个Redis实例的配置,简单直接,如果不要求持久化,这是不错的选择,会受硬件成本限制。但如果需要持久化,则面临内存实例过大时,fork子进程阻塞的问题。
(2)横向扩展
使用Redis集群进行数据切分,可扩展性好。
切片集群的方案有:
一.基于客户端的分区:ShardedJedis
二.基于代理的Codis、Twemproxy
三.基于服务端的Redis Cluster
10.一个普通Redis服务器的初始化过程
步骤一:初始化服务器状态结构
步骤二:载入服务器配置
步骤三:初始化服务器数据结构
步骤四:还原数据库状态
步骤五:执行事件循环
11.一个Sentinel服务器的初始化过程
步骤一:初始化服务器状态结构
Redis Sentinel本质上还是一个运行在特殊模式下的Redis服务器。
步骤二:使用Sentinel专用代码
比如普通Redis使用6379端口,Sentinel服务器使用26379端口。
步骤三:初始化Sentinel状态
SentinelState代表着一个Sentinel服务器。
步骤四:初始化Sentinel状态的masters属性
masters属性是一个字典。字典的键是被监视主服务器的名字,字典的值是被监视主服务器对应的SentinelRedisInstance结构。masters字典的初始化是根据被载入的Sentinel配置文件来进行的。
步骤五:创建连向主服务器的网络连接
网络连接包括命令连接和订阅连接。命令连接专门用于向主服务器发送命令和接收命令回复,此时Sentinel服务器成为主服务器的客户端。订阅连接专门用于订阅主服务器的__sentinel__:hello频道。
每个SentinelRedisInstance结构代表一个被Sentinel监控的Redis服务器实例,可以是主服务器、从服务器或者另一个Sentinel服务器。
//SentinelState(Sentinel服务器)dict *masters; //保存了所有被这个Sentinel服务器监视的主服务器,masters字典的值指向一个SentinelRedisInstance//SentinelRedisInstancechar *name, *runid;int quorum; //判断自己下线需要的票数int flags; //实例类型(主、从、Sentinel)dict *sentinels; //主的Sentinel名单
12.Sentinel如何向主从服务器获取信息和发送信息
(1)Sentinel获取主服务器信息
(2)Sentinel获取从服务器信息
(3)Sentinel向主服务器和从服务器发送频道信息
(4)Sentinel接收来自主和从服务器的频道信息
(5)Sentinel通过订阅频道更新的认知
(1)Sentinel获取主服务器信息
Sentinel默认会以每10秒一次的频率,通过命令连接向被监视的主服务器发送info命令。通过分析info命令的回复,来获取主服务器的当前信息(服务器ID、角色、所有从服务器信息)。这样,Sentinel就无须用户提供从服务器的地址信息,也可以自动发现从服务器。
主服务器返回的从服务器信息,会被用于更新对应的主服务器SentinelRedisInstance的slaves字典。这个字典记录了主服务器下所有从服务器的名单,字典的值是从服务器对应的SentinelRedisInstance。
主服务器实例结构的flags属性的值为SRI_MASTER,从服务器实例结构的flags属性的值为SRI_SLAVE。主服务器实例结构的name值是用户使用Sentinel配置文件设置的,而从的name值则是自动设置的ip:port。
(2)Sentinel获取从服务器信息
当Sentinel发现主服务器有新的从服务器出现时,Sentinel会:
一.创建新的从服务器相应的实例结构
二.创建连接到新的从服务器的命令连接和订阅连接,然后订阅从服务器的__sentinel__:hello频道
Sentinel默认会以每10秒一次的频率通过命令连接向从服务器发送info命令,通过分析info命令的回复来对从服务器的实例结构进行更新。
(3)Sentinel向主服务器和从服务器发送频道信息
Sentinel默认会以每2秒一次的频率,通过命令连接向所有被监视的主从服务器发送广播命令,即向这些主从服务器的__sentinel__:hello频道发送Sentinel本身的信息和主服务器的信息。
publish __sentinel__:hello "<s_ip>, <s_port>, <s_runid>, <s_epoch>, <m_name>, <m_ip>, <m_port>, <m_epoch>"
(4)Sentinel接收来自主和从服务器的频道信息
当Sentinel与一个主服务器或者从服务器建立起订阅连接后,Sentinel就会通过订阅连接向服务器发送订阅命令。
subscribe __sentinel__:hello
这样每个Sentinel都会订阅每一个服务器__sentinel__:hello频道,Sentinel对每个服务器的__sentinel__:hello频道的订阅会一直持续到Sentinel与该服务器的连接断开为止。
对于每个与Sentinel连接的服务器,Sentinel既通过命令连接向服务器的__sentinel__:hello频道发送信息,又通过订阅连接从服务器的__sentinel__:hello频道接收信息。
对于监视同一个服务器的多个Sentinel来说,一个Sentinel向__sentinel__:hello频道发送的消息,会被其他Sentinel接收到,其他Sentinel接收到这些信息可以更新对发送信息的Sentinel的认知,也可以更新对被监视服务器的认知。
(5)Sentinel通过订阅频道更新的认知
这些认知包括:更新sentinels字典和创建连向新Sentinel的命令连接。
在Sentinel为主服务器创建的实例结构SentinelRedisInstance中的sentinels字典保存了监视该主服务器的所有Sentinel。当Sentinel通过频道信息发现一个新的Sentinel时,它不仅会为新Sentinel在sentinels字典中创建相应的实例结构,还会创建一个连向新Sentinel的命令连接,而新Sentinel也同样会创建连向这个Sentinel的命令连接。使用命令连接相连的各个Sentinel可以通过向其他Sentinel发送命令请求来实现主观下线检测和客观下线检测。
因为一个Sentinel可以通过分析接收到的某服务器的频道信息来获知其他Sentinel的存在,并通过向某服务器发送频道信息来让其他Sentinel知道自己的存在,所以用户在使用Sentinel的时候并不需要提供各个Sentinel的地址信息,监视同一个主服务器的多个Sentinel可以自动发现对方。
13.Sentinel如何检测主客观下线并实现故障转移
(1)检测主观下线状态
(2)检查客观下线状态
(3)选举领头Sentinel
(4)领头Sentinel执行故障转移
(5)Redis Sentinel架构具有的功能
(6)Redis Sentinel架构包含多个Sentinel的好处
(1)检测主观下线状态
Sentinel默认会以每秒一次的频率向所有与它创建了命令连接的实例(主服务器、从服务器、其他Sentinel服务器)发送ping命令,通过实例返回的ping命令回复来判断实例是否在线(将服务器实例结构的flag设为SRI_S_DOWN)。
(2)检查客观下线状态
当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一主服务器的其他Sentinel进行询问。
当Sentinel从其他Sentinel那里接收到足够数量的已下线判断后,Sentinel就会将这个主服务器判断为客观下线(将主服务器实例结构的flag设为SRI_O_DOWN),并对主服务器执行故障转移。
客观下线的判断条件:认为主服务器已进入下线状态的Sentinel数量,超过Sentinel配置中设置的quorum参数的值。
(3)选举领头Sentinel
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作。
(4)领头Sentinel执行故障转移
步骤一:在已下线主服务器下的所有从服务器里挑选出一个从服务器,并将其转换为新的主服务器。从服务器被选中的规则是:先看优先级配置最高的,再看复制偏移量最大的,最后看服务器运行ID最小的。
步骤二:让已下线主服务器下的所有从服务器改为复制新的主服务器。
步骤三:将旧的主服务器设为从服务器。
简单来说就是:首先选新主,然后所有从复制新主,最后监视旧主设旧主为新主的从。
(5)Redis Sentinel架构具有的功能
一.监控功能
Sentinel节点会定期检测Redis数据节点、其余Sentinel节点是否可达。
二.通知功能
Sentinel会将故障转移的结果通知给应用方。
三.故障转移功能
实现从节点晋升为主节点,并维护正确的主从关系。
四.客户端可获取配置的功能
客户端在初始化和切换主节点时,需要和Sentinel节点集合进行交互来获取主节点信息。
(6)Redis Sentinel架构包含多个Sentinel的好处
好处一:节点故障判断由多个Sentinel节点共同完成,可以有效防止误判
好处二:若干个Sentinel节点组成的Sentinel集合,即便个别Sentinel节点不可用,整个Sentinel节点集合仍然健壮
14.Sentinel配置优化和部署技巧
(1)sentinel.conf配置优化说明
(2)Sentinel的部署技巧
(1)sentinel.conf配置优化说明
1.sentinel monitor <m-name> <ip> <port> <quorum><quorum>代表判定主观下线所需票数,一般设为Sentinel节点的一半加1。<quorum>也与Sentinel节点的领导者选举有关,至少要max(quorum, num(sentinels)/2 + 1)个Sentinel选举领导者。2.sentinel down-after-milliseconds <m-name> <times>每个Sentinel节点都要定期发送ping命令来判断Redis数据节点和其余Sentinel节点是否可达,<times>为超时时间。3.sentinel parallel-syncs <m-name> <nums>用来限制在一次故障转移之后,每次向新的主节点发起复制操作的从节点个数。尽管复制操作通常不会阻塞主节点,但多个从节点同时向主节点发起复制,会对主节点造成一定网络和磁盘IO。4.sentinel failover-timeout <m-name> <times>故障转移超时时间。5.sentinel notification-script <m-name> <script-path>故障转移期间,告警级别的Sentinel事件发生时触发的脚本。6.sentinel client-reconfig-script <m-name> <script-path>故障转移结束后,触发对应的脚本。
(2)Sentinel的部署技巧
技巧一:Sentinel节点不应都部署在同一物理机上
技巧二:部署至少三个且奇数个的Sentinel节点
因为领导者选举至少一半加一个节点,奇数个节点可以在满足该条件的基础上节省一个节点。而且节点越多,整个节点集合存在节点故障的概率越大。
技巧三:一般每个主节点配置一套Sentinel
但如果多个主节点是同一个业务的,也可以用一套Sentinel监控多个主节点。
15.Sentinel客户端的基本实现原理
各个语言的客户端需要对Redis Sentinel进行显示的支持。虽然Redis Sentinel可以完成故障转移,但是如果客户端无法获知主节点已经转移了,那么使用Redis Sentinel的意义就不大。
无论哪种编程语言的客户端,如果需要正确连接Redis Sentinel,必须要有Sentinel节点集合和masterName。而在此基础上,实现一个Redis Sentinel客户端的具体步骤如下。
步骤一:遍历Sentinel节点集合获取一个可用的Sentinel节点,Sentinel节点之间可以共享数据,任意一个Sentinel节点都可以获取主节点信息
步骤二:通过sentinel get-master-addr-by-name masterName获取主节点相关信息
步骤三:通过role命令或info replication命令获取当前主节点是否是真正的主节点,防止故障转移期间主节点变化
步骤四:保持和Sentinel节点集合的联系,时刻获取关于主节点的信息
Jedis会为每一个Sentinel节点单独启动一个线程,然后利用Redis的发布订阅功能,每个线程都会去订阅Sentinel节点的"+switch-master"频道(也就是切换主节点频道)。
领头Sentinel节点在结束对主节点故障转移后会发布消息到"+switch-master"频道。此外,Sentinel节点会将故障转移的各个阶段发生的行为都通过这种发布订阅的形式对外提供。
16.Sentinel的基本实现原理(哨兵机制的基本流程)
(1)三个定时监控任务
(2)主观下线和客观下线
(3)领导者Sentinel节点选举
(4)执行故障转移
总结来说包括:三个定时监控任务、主观下线和客观下线、Sentinel领导者选举、故障转移。
(1)三个定时监控任务
第一个定时任务:每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新拓扑结构。
第二个定时任务:每隔2秒,每个Sentinel节点会向主节点和从节点的__sentinel__:hello频道上,发送该Sentinel节点对主节点的判断以及当前Sentinel节点的信息。同时每个Sentinel节点也会订阅该频道,来了解其他Sentinel节点以及它们对主节点的判断。
第三个定时任务:每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点,发送ping命令做一次心跳检测确认可达。
其中,定时任务二可以完成以下两项工作:
工作一:发现新的Sentinel节点,对新的Sentinel保存起来,并与该Sentinel节点创建连接。
工作二:Sentinel节点之间交换主节点的状态,作为后面客观下线和领导者选举的依据。
(2)主观下线和客观下线
一.主观下线
要保证所有Sentinel实例的配置是一致的,尤其是主观下线的判断值down-after-milliseconds。每个Sentinel节点会每隔1秒对主节点、从节点、其他Sentinel节点发送ping命令做心跳检测,当这些节点超过down-after-milliseconds没有进行回复,Sentinel节点就会对该节点做失败判定。
二.客观下线
当Sentinel判定主观下线的节点是主节点时,该Sentinel节点会通过命令sentinel is-master-down-by-addr,向其他Sentinel节点询问对主节点的判断来减少误判,当超过个数则Sentinel节点作出客观下线决定。
(3)领导者Sentinel节点选举
Redis使用了Raft算法实现Sentinel领导者选举,思路说明如下。
说明一:每个在线的Sentinel节点都有资格成为领导者。当它确认主节点客观下线的时候,会向其他Sentinel节点再次发送命令sentinel is-master-down-by-addr,请求将自己设置为领导者。和检测客观下线时发送的命令sentinel is-master-down-by-addr不同,这次发送会带上运行ID。
说明二:收到命令的Sentinel节点,就会根据先到先得的规则,如果没有同意过其他Sentinel节点的命令sentinel is-master-down-by-addr,那么就将同意该请求,否则拒绝。
说明三:如果该Sentinel节点发现自己的票数已经大于等于max(quorum, num(sentinels)/2 + 1),则将会成为领导者,而选举出的Sentinel领导者节点,则需要负责故障转移。如果此过程没有选举出领导者,则会进入下一轮选举。
(4)执行故障转移
首先,在从节点列表中选出一个节点作为新的主节点,选举方法如下:
一.过滤主观下线或断线或断线次数多的节点
二.选择从节点优先级slave-priority最高的节点
三.选择复制平移量最大的节点
四.选择运行ID最小的节点
然后,Sentinel领导者节点会对选出来的从节点执行replicaof no one命令,让其成为主节点。
接着,Sentinel领导者节点会向剩余的从节点发送命令,让它们成为新节点的从节点。
最后,将原来的主节点更新为从节点,并当其恢复后让它去复制新的主节点。
17.Sentinel的高可用读写分离
Redis Sentinel需要客户端实现的有:故障转移通知以及高可用的从节点。
首先,一般的读写分离模型,客户端是直接连接固定的某个从节点,而Redis Sentinel的故障转移只是针对主节点的,并没有实现从节点的高可用。
然后,Redis Sentinel要想实现读写分离的高可用,可以依赖Sentinel节点的消息通知,获取Redis数据节点的状态变化。把所有从节点看作一个资源池,无论下线还是上线从节点,通过感知和从节点变动相关的频道消息,将其从资源池中添加或删除,从而实现从节点的高可用。
常见的Sentinel节点的发布订阅频道:
+switch-master:切换主节点
+sdown:节点主观下线
+covert-to-slave:切换从节点
+reboot:重启了某个节点
18.关于Sentinel的一些问题
(1)问题一
Sentinel(哨兵)实例是否越多越好,如何调整down-after-milliseconds的值?
一.哨兵实例越多,误判率越低,但在判定主库下线和选举领导者时,实例需要拿到的票数也就越多。等待所有哨兵投票完的时间可能也相应增加,主从库切换的时间、故障转移的时间也会变长。从而导致客户端堆积较多的请求,甚至可能会导致客户端请求溢出,造成请求丢失。
二.调大down-after-milliseconds可降低误判,但也意味着主从切换时间变长。
所以实例越多,那么通信次数越多、出现机器故障的风险越大,从而影响选举时间、影响主从切换时间。
(2)问题二
主从切换过程中,客户端能否进行正常的请求操作?如何才能让应用程序不感知服务的中断?
一.如果客户端使用了读写分离,那么读请求可正常在从库执行,但写请求会失败。
二.如果不想让业务感知异常,客户端只能把失败的写请求缓存起来,或写入消息队列中间件中,等哨兵切换完主从后,再把这些写请求发给新的主库,但这种方案只适合对写入请求返回值不敏感的业务。
三.等哨兵完成主从切换后,客户端需及时感知主库发生变更,做法如下:哨兵提升一个从库为新主库后,会把新主库的地址写入自己实例的+switch-master频道中,客户端需要订阅哨兵的这个频道,这样才能感知主库发生变更时拿到最新的主库地址,这属于哨兵主动通知客户端。如果客户端因为某些原因错过了哨兵的通知,客户端也需要主动获取最新的主从地址。所以客户端访问主从库时,不能写死主从库地址,需要能从哨兵集群中获取最新的主从地址。
标签: #集群横向扩展机制