redis 集群
三种模式:
- 主从模式
- Sentinel模式 (哨兵)
- Cluster模式
主从模式
1.简介
- 在主从复制中,数据库分为两类:主数据库(master)和从数据库(slave),读写分离。
2.工作机制
- 当slave启动后,主动向master发送SYNC命令(全量同步)。master接收到SYNC命令后在后台保存快照(RDB持久化)和缓存保存快照这段时间的命令,然后将保存的快照文件和缓存的命令发送给slave。slave接收到快照文件和命令后加载快照文件和缓存的执行命令。 复制初始化后,master每次接收到的写命令都会同步发送给slave(增量同步),保证主从数据一致性。
- 主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。
3.特点
* 主数据库可以进行读写操作,当读写操作导致数据变化时会自动将数据同步给从数据库
* 从数据库一般都是只读的,并且接收主数据库同步过来的数据
* 一个master可以拥有多个slave,但是一个slave只能对应一个master
* slave挂了不影响其他slave的读和master的读和写,重新启动后会将数据从master同步过来
* master挂了以后,不影响slave的读,但redis不再提供写服务,master重启后redis将重新对外提供写服务
* master挂了以后,不会在slave节点中重新选一个master
* 当master节点设置密码后,客户端访问master需要密码,启动slave需要密码,在配置文件中配置即可,客户端访问slave不需要密码
Sentinel模式
1.简介
- 由于主从模式的弊端就是不具备高可用性,当master挂掉以后,Redis将不能再对外提供写入操作,因此sentinel应运而生
2.工作机制
* 每个sentinel以每秒钟一次的频率向它所知的master,slave以及其他sentinel实例发送一个 PING 命令
* 如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被sentinel标记为主观下线。
* 如果一个master被标记为主观下线,则正在监视这个master的所有sentinel要以每秒一次的频率确认master的确进入了主观下线状态
* 当有足够数量的sentinel(大于等于配置文件指定的值)在指定的时间范围内确认master的确进入了主观下线状态, 则master会被标记为客观下线
* 在一般情况下, 每个sentinel会以每 10 秒一次的频率向它已知的所有master,slave发送 INFO 命令
* 当master被sentinel标记为客观下线时,sentinel向下线的master的所有slave发送 INFO 命令的频率会从 10 秒一次改为 1 秒一次
* 若没有足够数量的sentinel同意master已经下线,master的客观下线状态就会被移除;若master重新向sentinel的 PING 命令返回有效回复,master的主观下线状态就会被移除
* 通过一定的vote算法,从剩下的slave节点中,选一台提升为master,然后自动修改相关配置。
- 备注:虽然sentinel集群中每个sentinel都互相连接彼此来检查对方的可用性以及互相发送消息。但是你不用在任何一个sentinel配置任何其他的snetinel节点。因为sentinel利用了master的发布/订阅机制去自动发现其它监控了统一master的sentinel节点。
哨兵选举(Raft算法)
- Raft是一个用户管理日志一致性的协议,它将分布式一致性问题分解为多个子问题:Leader选举、日志复制、安全性、日志压缩等。Raft将系统中的角色分为领导者(Leader)、跟从者(Follower)和候选者(Candidate):
Leader:接受客户端请求,并向Follower同步请求日式,当日志同步到大多数节点上后告诉Follower提交日志。
Follower:接受并持久化Leader同步的日志,在Leader告知日志可以提交之后,提交日志。
Candidate:Leader选举过程中的临时角色。
- Raft算法将时间划分为任意不同长度的任期(term)。任期用连续的数字进行表示。每一个任期的开始都是一次选举(election),一个或多个候选人会试图成为领导人,如果一个候选人赢得了选举,它就会在该任期的剩余时间担任领导人。在某些情况下,选票会被瓜分,有可能没有选出领导人,那么将会开始另一个任期,并且立刻开始下一次选举。Raft算法保证在给定的一个任期内最多是有一个领导人。
- Raft算法中服务器节点之间通信使用远程过程调用(RPC),并且基本的一致性算法只需要两种类型的RPC,为了在服务器之间传输快照增加了第三种 RPC。
RequestVote RPC:候选人在选举期间发起。
AppendEntries RPC:领导人发起的一种心跳机制,复制日志也在该命令中完成。
InstallSnapshot RPC:领导者使用该RPC来发送快照给太落后的追随者。
选举流程
- 1、某个Sentinel认定master客观下线的节点后,该Sentinel会先看看自己有没有投过票,如果自己已经投过票给其他Sentinel了,在2倍故障转移的超时时间自己就不会成为Leader。相当于它是一个Follower。
- 2、如果该Sentinel还没投过票,那么它就成为Candidate。
- 3、和Raft协议描述的一样,成为Candidate,Sentinel需要完成几件事情
1)更新故障转移状态为start
2)当前epoch加1,相当于进入一个新term,在Sentinel中epoch就是Raft协议中的term。
3)更新自己的超时时间为当前时间随机加上一段时间,随机时间为1s内的随机毫秒数。
4)向其他节点发送is-master-down-by-addr命令请求投票。命令会带上自己的epoch。
5)给自己投一票,在Sentinel中,投票的方式是把自己master结构体里的leader和leader_epoch改成投给的Sentinel和它的epoch。
- 4、其他Sentinel会收到Candidate的is-master-down-by-addr命令。如果Sentinel当前epoch和Candidate传给他的epoch一样,说明他已经把自己master结构体里的leader和leader_epoch改成其他Candidate,相当于把票投给了其他Candidate。投过票给别的Sentinel后,在当前epoch内自己就只能成为Follower。
- 5、Candidate会不断的统计自己的票数,直到他发现认同他成为Leader的票数超过一半而且超过它配置的quorum(quorum可以参考《redis sentinel设计与实现》)。Sentinel比Raft协议增加了quorum,这样一个Sentinel能否当选Leader还取决于它配置的quorum。
- 6、如果在一个选举时间内,Candidate没有获得超过一半且超过它配置的quorum的票数,自己的这次选举就失败了。
- 7、如果在一个epoch内,没有一个Candidate获得更多的票数。那么等待超过2倍故障转移的超时时间后,Candidate增加epoch重新投票。
- 8、如果某个Candidate获得超过一半且超过它配置的quorum的票数,那么它就成为了Leader。
- 9、与Raft协议不同,Leader并不会把自己成为Leader的消息发给其他Sentinel。其他Sentinel等待Leader从slave选出master后,检测到新的master正常工作后,就会去掉客观下线的标识,从而不需要进入故障转移流程。
主节点的选取
- 选择健康状态从节点(排除主观下线、断线),排除5秒钟没有心跳的、排除主节点失联超过 (10 乘 down-after-millisecends)。
- 选择最高优先级中复制偏移量最大的从机。
- 如果还没有选出来,则按照ID排序,获取运行ID最小的从节点。
故障转移
- sentinel的领导者从从机中选举出合适的丛机进行故障转移
- 对选取的从节点进行slave of no one命令,(这个命令用来让从机关闭复制功能,并从从机变为主机)
- 更新应用程序段的链接到新的主节点
- 对其他从节点变更master为新的节点
- 修复原来的master并将其设置为新的master的从机
哨兵监听的几个事件
* +reset-master :主服务器已被重置。
* +slave :一个新的从服务器已经被 Sentinel 识别并关联。
* +failover-state-reconf-slaves :故障转移状态切换到了 reconf-slaves 状态。
* +failover-detected :另一个 Sentinel 开始了一次故障转移操作,或者一个从服务器转换成了主服务器。
* +slave-reconf-sent :领头(leader)的 Sentinel 向实例发送了 [SLAVEOF](/commands/slaveof.html) 命令,为实例设置新的主服务器。
* +slave-reconf-inprog :实例正在将自己设置为指定主服务器的从服务器,但相应的同步过程仍未完成。
* +slave-reconf-done :从服务器已经成功完成对新主服务器的同步。
* -dup-sentinel :对给定主服务器进行监视的一个或多个 Sentinel 已经因为重复出现而被移除 —— 当 Sentinel 实例重启的时候,就会出现这种情况。
* +sentinel :一个监视给定主服务器的新 Sentinel 已经被识别并添加。
* +sdown :给定的实例现在处于主观下线状态。
* -sdown :给定的实例已经不再处于主观下线状态。
* +odown :给定的实例现在处于客观下线状态。
* -odown :给定的实例已经不再处于客观下线状态。
* +new-epoch :当前的纪元(epoch)已经被更新。
* +try-failover :一个新的故障迁移操作正在执行中,等待被大多数 Sentinel 选中(waiting to be elected by the majority)。
* +elected-leader :赢得指定纪元的选举,可以进行故障迁移操作了。
* +failover-state-select-slave :故障转移操作现在处于 select-slave 状态 —— Sentinel 正在寻找可以升级为主服务器的从服务器。
* no-good-slave :Sentinel 操作未能找到适合进行升级的从服务器。Sentinel 会在一段时间之后再次尝试寻找合适的从服务器来进行升级,又或者直接放弃执行故障转移操作。
* selected-slave :Sentinel 顺利找到适合进行升级的从服务器。
* failover-state-send-slaveof-noone :Sentinel 正在将指定的从服务器升级为主服务器,等待升级功能完成。
* failover-end-for-timeout :故障转移因为超时而中止,不过最终所有从服务器都会开始复制新的主服务器(slaves will eventually be configured to replicate with the new master anyway)。
* failover-end :故障转移操作顺利完成。所有从服务器都开始复制新的主服务器了。
* +switch-master :配置变更,主服务器的 IP 和地址已经改变。 这是绝大多数外部用户都关心的信息。
* +tilt :进入 tilt 模式。
* -tilt :退出 tilt 模式。
3.特点
* sentinel模式是建立在主从模式的基础上,如果只有一个Redis节点,sentinel就没有任何意义
* 当master挂了以后,sentinel会在slave中选择一个做为master,并修改它们的配置文件,其他slave的配置文件也会被修改,比如slaveof属性会指向新的master
* 当master重新启动后,它将不再是master而是做为slave接收新的master的同步数据
* sentinel因为也是一个进程有挂掉的可能,所以sentinel也会启动多个形成一个sentinel集群
* 多sentinel配置的时候,sentinel之间也会自动监控
* 当主从模式配置密码时,sentinel也会同步将配置信息修改到配置文件中,不需要担心
* 一个sentinel或sentinel集群可以管理多个主从Redis,多个sentinel也可以监控同一个redis
* sentinel最好不要和Redis部署在同一台机器,不然Redis的服务器挂了以后,sentinel也挂了
Cluster集群模式
1.简介
- sentinel模式基本可以满足一般生产的需求,具备高可用性。但是当数据量过大到一台服务器存放不下的情况时,主从模式或sentinel模式就不能满足需求了,这个时候需要对存储的数据进行分片,将数据存储到多个Redis实例中。cluster模式的出现就是为了解决单机Redis容量有限的问题,将Redis的数据根据一定的规则分配到多台机器。
- cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能,所以如果配置两个副本三个分片的话,就需要六个Redis实例。因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容。使用集群,只需要将redis配置文件中的cluster-enable配置打开即可。每个集群中至少需要三个主数据库才能正常运行,新增节点非常方便
2.工作原理
原理
* 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
* 节点的fail是通过集群中超过半数的节点检测失效时才生效。
* 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
* redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
* Redis集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
实现方案
- 1.Twitter开发的twemproxy
twemproxy架构简单 就是用proxy对后端redis server进行代理 但是由于代理层的消耗性能很低 而且通常涉及多个key的操作都是不支持的 而且本身不支持动态扩容和透明的数据迁移 而且也失去维护 Twitter内部已经不使用了
- 2.豌豆荚开发的codis
redis-cluster是三个里性能最强大的 因为他使用去中心化的思想 使用hash slot方式 将16348个hash slot 覆盖到所有节点上 对于存储的每个key值 使用CRC16(KEY)&16348=slot 得到他对应的hash slot 并在访问key时就去找他的hash slot在哪一个节点上 然后由当前访问节点从实际被分配了这个hash slot的节点去取数据 节点之间使用轻量协议通信 减少带宽占用 性能很高 自动实现负载均衡与高可用 自动实现failover 并且支持动态扩展 官方已经玩到可以1000个节点 实现的复杂度低 总之个人比较喜欢这个架构 因为他的去中心化思想免去了proxy的消耗 是全新的思路
但是它也有一些不足 例如官方没有提供图形化管理工具 运维体验差 全手工数据迁移 并且自己对自己本身的redis命令支持也不完全等 但是这些问题 我觉得不能掩盖他关键的新思想所带来的的优势 随着官方的推进 这些问题应该都能在一定时间内得到解决 那么这时候去中心化思想带来的高性能就会表现出他巨大的优势
- 3.redis官方的redis-cluster
codis使用的也是proxy思路 但是做的比较好 是这两种之间的一个中间级 而且支持redis命令是最多的 有图形化GUI管理和监控工具 运维友好 这个过段时间会详细另外写出来原理 工作机制和搭建实现
redis-cluster投票:容错
- 投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超时(cluster-node-timeout),认为当前master节点挂掉.
- 什么时候整个集群不可用(cluster_state:fail)?
1.如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完整时进入fail状态.
2.redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.
3.如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态.
3.特点
* Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施installation。
* Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低Redis集群的性能, 并导致不可预测的行为。
* Redis 集群通过分区partition来提供一定程度的可用性availability: 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
* Redis集群提供了以下两个好处:
将数据自动切分split到多个节点的能力。
当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。