redis有三种集群方式:主从复制,哨兵模式和集群。
一,主从复制
主从复制是指让一个服务器去复制另一个服务器的数据,使得双方的数据保存一致,其中被复制的服务器为主服务器,复制的服务器为从服务器。当主服务器的数据发生改变时,主服务器会通知从服务器,保存数据的一致性。
在Redis中,使用slaveof命令来执行主从复制。
(一)旧版的主从复制实现
在旧版中,Redis的复制功能分为两步:同步和命令传播。
同步操作用于将从服务器的数据状态更新为主服务器的数据状态。
命令传播操作用于在主服务器的数据被修改时,通知从服务修改对应的数据,从而达到数据一致。
从服务器向主服务器发送slaveof命令后:
1. 从服务器向主服务器发送sync命令,主服务器会执行bgsave命令,在后台生成一个RDB文件,并用一个缓冲区记录从现在开始的所有写命令。
2. 从服务器接收并载入RDB文件,更新自己的数据。更新完成之后,主服务器会发送缓冲区中的命令,从服务器执行这些命令,最终主从服务器的数据保存一致。
3. 主从服务器保存一致后,当主服务器的数据发生修改时,会对从服务器执行命令传播操作,即将修改命令发送给从服务器,使得数据继续保存一致。
缺陷:
旧版的主从复制的实现有个很大的缺陷:在从服务器发生断线并重连之后,主从服务器之间会重新执行同步操作,即将主服务器的所有数据重新传到从服务器中。但实际上,在重连之后,主从服务器之间可能只有少量数据不同,大部分保存一致。这就使得有很多数据是无效的,效率极低。
(二)新版的主从复制实现
为了解决主从复制效率底下的问题,Redis从2.8开始,使用psync命令替代sync。
psync命令有两种模式:完整重同步和部分重同步。
完整重同步用于初次复制情况,和同步操作一致。
部分重同步用于断线重连后复制情况。
部分重同步的实现:
部分重同步,当从服务器断线重连后,如果条件允许,主服务器可以将从服务器断线期间执行的写命令发送给从服务器,从服务器只要接收并执行命令,就可以更新数据,更主服务器实现数据一致。
部分重同步使用了复制偏移量和复制挤压缓冲区来实现。
复制偏移量:主服务器和从服务器都各自维持着一个复制偏移量。主服务器每次向从服务器发送N个字节的数据时,就会在自己的复制偏移量上加N,从服务器每次接受都主服务器的N个字节的数据时,就会在自己的复制偏移量上加N。通过对比主从服务器的复制偏移量就很容易知道主从服务器的数据是否处于一致。
当从服务器断线重连后,根据主从服务器之间复制偏移量的差,主服务器就可以发送相应的数据给从服务器,即从服务器在断线之后被修改的数据。
而主服务器发送给从服务器的数据是存在复制积压缓冲区中。
复制积压缓冲区是一个固定长度的先进先出队列,由于其长度固定,当队列已满时,在数据入队时,队列最前面的数据必须要先出队,即复制积压缓冲区值保留固定大小的数据。
当主服务器进行命令传播操作时,不仅将写命令发送给从服务器,还会写入到复制积压缓冲区中,并记录下缓冲区中每个字节数据的复制偏移量。当从服务器重连后,如果从服务器的复制偏移量大于缓冲区中队首的复制偏移量,就会以部分重同步的方式来进行复制;如果从服务器的复制偏移量小于缓冲区中队首的复制偏移量,则会以完整重同步的方式来进行复制。
二,Redis哨兵模式(Sentinel)
(一)哨兵模式
哨兵模式是Redis高可用性的解决方案:通过一个或多个sentinel组成sentinel系统,监控任意多个主服务器,以及这些主服务器下的所有从服务器,并在被监控的主服务器下线后,自动将主服务器下的一个子服务器升级为新的主服务器,然后由新的主服务器执行命令。
Sentinel系统主要有三个功能:
监控(Monitoring): Sentinel会以一定的频率检查主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
(二)监控方式
每隔10s,每个哨兵节点会向主节点和从节点发送info命令获取最新的拓扑结构。
每隔2s,每个哨兵节点通过订阅连接向服务器频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个Sentinel节点也会订阅该频道,并接收到信息。注意:Sentinel在连接主服务器或从服务器时,会同时建立命令连接和订阅连接,但连接其他Sentinel节点时,只会创建命令连接;这是因为Sentinel通过服务器的订阅连接来发现新的Sentienel和更新其它Sentinel的状态,而对于已知的Sentinel,可以直接使用命令连接来通信。
每隔1s,每个哨兵节点会向主节点、从节点、其余哨兵节点发送一条ping命令做一次心跳检测(心跳检测机制),来确认这些节点当前是否可达。
(三)判断主服务器是否下线
判断主服务器是否下线有两步骤:主观下线和客观下线。
主观下线:单个Sentinel认为服务器已经下线。
客观下线:多个Sentinel认为服务器已经下线。
主观下线:
当一个实例(包括主从节点,哨兵节点)在一定时间对于Sentinel的回复为无效回复(除了+PONG,-LOADING,-MASTERDOWN这三种回复之外的所有回复,以及没有回复),则该Sentinel会把该实例标为主观下线。
注意:由于每个Sentinel设置的超时时间不同,所以可能有的Sentinel认为服务器已经主观下线,但另外一些Sentinel认为服务器没有主观下线,即还处于存活状态。
客观下线(只有主服务器才会进行客观下线判断):
当Sentinel将一个主服务器判断为主观下线后,会向其它同样监视着该主服务器的Sentinel进行询问,看他们是否认为主服务器已经进入了下线状态(可以是主观下线或者是客观下线)。当Sentinel收到一定数量的肯定回复后,会将该服务器标识为客观下线,并对主服务器执行故障转移操作。
注意:每个Sentinel设置的肯定回复数量不同,所以可能有的Sentinel认为服务器已经客观下线,而有的Sentinel认为服务器还没客观下线,甚至还有的Sentinel认为服务器还处于存活状态。但只要一个 Sentinel 认为某个主服务器进入了客观下线状态, 就会对失效的主服务器执行自动故障迁移操作。
(四)选举领头Sentinel
当一个主服务器被判断为主观下线后,监视这个主服务器的所有Sentinel会进行协商,选举出一个领头Sentinel,并由他来对下线主服务器执行故障迁移操作。
选举的原则是先到先得:每个判断主服务器为客观下线的Sentinel都会想其他Sentinel发送请求,要求成为领头Sentinel。而一个Sentinel只要接收到了其他Sentinel发送的选举请求,就会将其选举为领头Sentinel,并拒绝之后所有的选举请求。
(五)故障转移
在选举出领头Sentinel之后,领头Sentinel会对已下线的主服务器执行故障转移操作,该操作包含三个步骤:
1) 在已下线主服务器的从服务器中,挑选一个从服务器,并将其转换为主服务器。
2) 让已下线主服务器下的所有从服务器改为复制新的主服务器。
3) 将已下线主服务器设置为新的主服务器的从服务器,当其重新上线时,它将成为新的主服务器的从服务器。
三,Redis集群
Redis集群通过分片的方式来保存数据,集群中的所有数据都被分为16384个槽(slot),数据库中每个数据都属于这16384个槽中的一个,集群中的每个节点可以处理0-16384个槽。每个数据属于哪个槽是通过hash算法得出的,并且只有当16384个槽都有节点在处理的时候,集群才会处于上线状态;只要有一个槽没有节点在处理,集群就处于下线状态。
(一)槽指派
每个Node被平均分配了一个Slot段,对应着0-16384,Slot不能重复也不能缺失,否则会导致对象重复存储或无法存储。并且所有节点都会通知其他节点自己所负责的Slot段。
(二)命令执行
当对数据库中的16384个槽都进行指派后,集群就处于上线状态。当客户端向节点发送指令时,接收命令的节点会判断指令中操作的数据是否位于自己所负责的槽中。如果不属于,节点会返回一个MOVED错误,指引客户端将命令转向正确的节点。客户端在接收到MOVED错误后,会向正确的节点再次发送命令。
(三)重新分片
一旦有节点下线或者加入,会按照Slot为单位做数据的迁移。例如Node1如果掉线了,0-5640这些Slot将会平均分摊到Node2和Node3上,由于Node2和Node3本身维护的Slot还会在自己身上不会被重新分配,所以迁移过程中不会影响到5641-16384Slot段的使用。
节点下线的判断是:集群中超过半数的节点认为该节点已经掉线。
(四)主从节点
在集群中,每个节点都可以是一个主从节点(由一个主服务器和多个从服务器组成),这样就保障了集群的高可用。
如果集群中的一个节点是主从节点,那么当主节点发生故障时,不会将主节点复制的Slot段重新分片,而是从从节点中选举出一个节点,作为新的主节点。选举的规则是:从节点询问集群中其他的主节点,只要有超过一半的集群节点同意,则从节点被选举为主节点,继续执行命令。
注意:在集群模式下,节点只能使用db0数据库,而单机情况下,我们可以使用16个数据库(db0 ~ db15)。
四,三种Redis结构的优缺点
(一)主从复制
优点:
1) 读写分离,由主节点复制写,从节点负责读,适合高并发。
2) 可以通过增加从节点的方式来提高并发读的能力。
缺点:
1) 主节点的写能力有限,主从复制结构的写并发取决于主节点的写性能。
2) 不具备自动容错和恢复功能,主机从机的宕机都会导致部分读写请求失败。
(二)哨兵模式
优点:
1)哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。
2)主从可以自动切换,系统更健壮,可用性更高。
缺点:
1) 同样存在写性能不足的情况。
(三)集群
优点:
1)和哨兵模式一样具有高可用,读写分离的优点。
2) 每个节点都存储着不同的数据,并且每个节点都可以进行读写。解决了其他结构中的读性能不高的问题。
缺点:
1) 每个节点都由一个服务器群(一个主节点和多个从节点)组成,可能会造成浪费。