Redis全称REmote DIctionary Server,是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。它通常被称为数据结构服务器,因为值(value)可以是字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和有序集合(sorted sets)等类型。
Redis经常会被用于数据的缓存,session共享等场景下,Redis的本身的高可用就特别值得关注,我们来针对常用的两种高可用架构进行说明。
◆◆Redis Sentinel(哨兵)◆◆Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现、故障自动转移、配置中心和客户端通知。Redis Sentinel的节点数量要满足2n+1(n>=1)的奇数个。
哨兵模式其实是有2个集群在同时工作,一个是sentinel的集群,一个是数据节点的集群。典型的一个高可用架构如下图所示:
Sentinel架构的主要作用是解决主从模式下主节点的故障转移工作的。这里如果主节点因为故障下线,那么某个sentinel节点发送检测消息给主节点时,如果在指定时间内收不到回复,那么该sentinel就会主观的判断该主节点已经下线,那么其会发送消息给其余的sentinel节点,询问其是否“认为”该主节点已下线,其余的sentinel收到消息后也会发送检测消息给主节点,如果其认为该主节点已经下线,那么其会回复向其询问的sentinel节点,告知其也认为主节点已经下线,当该sentinel节点最先收到超过指定数目(配置文件中配置的数目和当前sentinel节点集合数的一半,这里两个数目的较大值)的sentinel节点回复说当前主节点已下线,那么其就会对主节点进行故障转移工作。转移完成后,sentinel也会通知客户端进行节点的转移。
◆◆客户端实现◆◆客户端从过去直接连接Redis ,变成先连接一个Sentinel实例使用 SENTINEL get-master-addr-by-name master-name 获取Redis地址信息。
连接返回的Redis地址信息,通过ROLE命令查询是否是Master。如果是,连接进入正常的服务环节。否则应该断开重新查询。
(可选)客户端可以通过SENTINEL sentinels 来更新自己的Sentinel实例列表。当Sentinel发起failover后,切换了新的Master,Sentinel会发送 CLIENT KILL TYPE normal命令给客户端,客户端需要主动断开对老的Master的链接,然后重新查询新的Master地址,再重复走上面的流程。这样的方式仍然相对不够实时,可以通过Sentinel提供的Pub/Sub来更快地监听到failover事件,加快重连。
◆◆生产环境推荐◆◆对于一个最小集群,Redis应该是一个Master带上两个Slave,并且开启下列选项:
min-slaves-to-write 1
min-slaves-max-lag 10
这样能保证写入Master的同时至少写入一个Slave,如果出现网络分区阻隔并发生failover的时候,可以保证写入的数据最终一致而不是丢失,写入老的Master会直接失败。
Slave可以适当设置优先级,除了0之外(0表示永远不提升为Master),越小的优先级,越有可能被提示为Master。如果Slave分布在多个机房,可以考虑将和Master同一个机房的Slave的优先级设置的更低以提升他被选为新的Master的可能性。
考虑到可用性和选举的需要,Sentinel进程至少为3个,推荐为5个。如果有网络分区,应当适当分布(比如2个在A机房, 2个在B机房,一个在C机房)等。
◆◆Redis Cluster(集群)◆◆Sentinel模式虽然解决了高可用的问题,但是单机的容量还是受到了限制,无法实现redis的分布式集群,限制了整个集群的容量和并发性能。
Redis Cluster集群节点最小配置6个节点以上(3主3从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。
Cluster模式有众多的优点:• 无中心架构;
• 数据按照slot存储分布在多个节点,节点间数据共享,可动态调整数据分布;
• 可扩展性:可线性扩展到1000多个节点,节点可动态添加或删除;
• 高可用性:部分节点不可用时,集群仍可用。通过增加Slave做standby数据副本,能够实现故障自动failover,节点之间通过gossip协议交换状态信息,用投票机制完成Slave到Master的角色提升;
• 降低运维成本,提高系统的扩展性和可用性。
限制条件看起来很美好,cluster集群模式还是受到了一些使用上的限制:
1.Key批量操作支持有限。目前只支持同slot内的key执行批量操作(如mget,mset)。
2.Key事务操作支持有限。只支持多key在同一个节点上的事务操作,多个key分布在不同节点上时无法使用事务功能。
3.Key作为数据分区的最小粒度,因此不能将一个大的键值对象如hash,list等映射到不同节点。
4.不支持多数据库空间,集群模式下只能使用db0空间。
5.复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。
故障切换过程故障节点变为客观下线后,如果下线节点是持有槽的主节点,则需要在它的从节点中选出一个替换它。从而保证集群高可用。下线主节点的所有从节点承担故障恢复的义务,当从节点通过内部定时任务发现自身复制的主节点进入客观下线时,将会触发故障恢复流程。
Sentinel模式提供了高可用的功能,由于redis本身的性能优异,很多企业内部的系统用这种模式足以应对。如果有些2C的应用,则推荐采用redis的cluster模式。