当我们使用redis 的主从架构+哨兵时,只能保障redis的高可用和水平扩充读并发上限,并不能水平扩展redis的存储容量。每一个(主节点和从节点)保存的信息量是一样的。
如果我系统中要缓存的数据量不多,几个G的话,建议使用redis主从+哨兵架构。
如果系统中要缓存海量数据,则使用redis cluster架构。
1.redis cluster基本架构图:
2. redis cluster 架构特点:
海量数据存储 + 高可用 + 高并发的支持
海量数据存储: 可以通过水平扩展主节点来支持海量数据。最多16384个主节点
高可用 : 在redis cluster架构中,每个主节点都有一个或多个从节点做为冷备(默认情况下从节点不支持读、写操作的)。当一个主节点宕了,从节点会切换成主节点,继续提供读写服务。我们也可以给集群增加冗余的从节点。无论哪个主节点下的从节点挂掉后,这些冗余节点就会自动迁移到当前的主节点下做为他的从节点。
高并发: 不同的请求会分散到不同的主节点上,每一个节点的并发压力会很小。
3.数据分布算法:
3.1.hash算法:使用这种算法可以将数据平均分布在不同的节点上。如果某一个节点出现故障,那么数据基本等于全部“丢失”。
3.2 一致性hash算法:将每个节点虚拟出很多虚拟节点,然后均匀的散落在一个圆环上,当一个请求过来时,将key计算出hash值,落在圆环上,然后顺时针找到第一个虚拟节点,再根据虚拟节点和实际节点的映射关系可得到真实节点进行操作。当一个节点故障后并不影响其他节点数据。虚拟节点可以让让故障节点的请求分散到不同的节点上(虽然取不到数据),防止某个节点故障后,只对一个节点带来具大的压力。
3.3 hash slot算法: redis cluster有固定个数(16384)hash slot。每个主节点内都会持有部分slot。当一个key过来时,对key进行CRC16计算,就可以获取到对应的slot,根据slot找到对应的节点。
这样做的好处就是将节点和数据进行了解耦,当一个节点挂掉不会影响其他节点的数据存取操作。当增加或者移除节点时,对slot进行再次分即可。还可以通过hash tag 将不同key的值落在相同节点上。
1.节点之间是采用的gossip协议进行通信
这种协议的特点就是指每个节点之间不断的交换信息。当节点信息发生变化,或者增加节点或减少节点时,会通过ping/pong发送通知,让所有节点知道并本地保存信息。
常用的gossip消息类型有:
1.1.meet : 某个节点会给新加入进来的节点发送meet消息,通知新加入的节点加入到集群中。
1.2.ping : 每一秒都会向其他节点发送ping消息(选5个节点),这种消息由两部分组成:请求头信息、请求休信息。请求头中的内容为节点本身的相关信息(节点的id,角色,slot,状态等)。请求体是其他节点的信息。
1.3 . pong : 当收到ping/meet信息里,进行响应的信息。证明通讯正常。pong信息里也包含节点自身的信息或其他节点信息。
1.4. fail : 当集群中的某一个节点主观认为另一个节点宕机时,会发送fail消息给其他节点,来确认改节点是否是客观宕机。
2.ping消息的节点选择
ping 消息的发送频率很高,如果每秒发送的节点数过多的话,势必会导致信息交换的成本过高的问题。
每个节点都有一个定时器,每100毫秒扫描本地的节点列表信息,找出最久没有通信的节点发送ping消息(1妙内选5个),如果发现节点最近一次接受pong消息的时间大于cluster-node-timeout/2 则立刻发送ping消息。防止信息不同步。redis.conf 可以设置cluster-node-timeout的时间,建议不要过大。
3.主备切换原理
3.1 故障判断:
当某个节点发送ping 消息给目标节点时后,目标节点在cluster-node-timeout内没返回pong,则认为目标节点为主观下线。
同时会发送fail 消息给其他节点,如果超过半数的主节点都认为目标节点下线了,那么就认客观下线。如果目标节点是主节点的话,标记为下线后还要进行切换操作,将选一个从节点提升为主节点。
3.2 节点选举:
检查每个slave node与master node断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor,那么就没有资格切换成master.
然后让主节点进行投票,每个主节点只能投一张票给从节点,当从节点收集到足够的选票(大于N/2+1)后,触发替换主节点操作,撤销原故障主节点的槽,委派给自己(被选上的slvae),并广播自己的委派消息,通知集群内所有节点。