一、Redis概述
1、Redis组建集群共有三种方式
第一种:Redis主从模式,搭建该集群有点就是非常简单并且每个数据保存在多个Redis中,这样保障Redis中的数据安全,缺点:当集群中的主服务器(Master)宕机后从服务器(Slave)不会自动接管主服务器的工作,需要人工干预
第二种:Redis哨兵模式,Redis哨兵主要采用单独开一个进程进行监控Redis集群运行状态,在Redis编译安装完成后,源文件可以看到一个sentinel.conf文件这个就是哨兵的配置文件,Redis哨兵也类似于Redis主从,在集群中选举一个主服务器(Master),所有写入的数据由主服务器接收,然后同步到集群中的从服务器(Slave)上,但是哨兵比Redis主从更加智能的,在哨兵集群中,当主服务器(Master)出现故障,集群会自动重新选举一台主服务器,这样不需要人工干预,系统运行更加稳定
第三种:Redis cluster,无论是Redis主从或者Redis哨兵,他们都有一个共同的问题,就是所有请求都是由一台服务器进行响应,既:主服务器(Master),如果请求/并发量太大,这台服务器将会成为瓶颈。而Redis 3.0以后提供了一个Redis cluster模式,它使用哈希槽分片,将所有数据分布在不同的服务器上
2、为什么要实现Redis Cluster
1、主从复制不能实现高可用
2、随着公司发展,用户数量增多,并发越来越多,业务需要更高的QPS,而主从复制中单机的QPS可能无法满足业务需求
3、数据量的考虑,现有服务器内存不能满足业务数据的需要时,单纯向服务器添加内存不能达到要求,此时需要考虑分布式需求,把数据分布到不同服务器上
4、网络流量需求:业务的流量已经超过服务器的网卡的上限值,可以考虑使用分布式来进行分流
5、离线计算,需要中间环节缓冲等别的需求
3、Redis数据分区
数据分布通常有 哈希分区 和 范围分区 两种方式(本文主要讲哈希分区)
哈希分区:离散程度好,数据分布与业务无关,无法顺序访问 Redis Cluster,Cassandra,Dynamo
顺序分区: 离散程度易倾斜,数据分布与业务相关,可以顺序访问 BigTable,HBase,Hypertable 由于Redis Cluster 采用哈希分区规则
Redis Cluster 采用虚拟哈希槽分区,所有的键根据哈希函数映射到 0 ~ 16383 整数槽内,计算公式:slot = CRC16(key) & 16383。每一个节点负责维护一部分槽以及槽所映射的键值数据
Redis 虚拟槽分区的特点:
1、解耦数据和节点之间的关系,简化了节点扩容和收缩难度
2、节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据
3、支持节点、槽和键之间的映射查询,用于数据路由,在线集群伸缩等场景
如图:节点1的槽范围 0 ~ 3276 ;节点2的槽范围 3277 ~ 6553;节点3的槽范围 6554 ~ 9830;节点4的槽范围 9831 ~ 13107 ;节点5的槽范围 13108 ~ 16383。
4、 Redis集群选举原理
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程
过程:
1、slave发现自己的master变为FAIL
2、将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST 信息
3、其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
4、尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
5、slave收到超过半数master的ack后变成新Master(这里解释了集群为什么至少需要三个主节点,如果只有两个,当其中一个挂了,只剩一个主节点是不能选举成功的)
6、slave广播Pong消息通知其他集群节点
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票
延迟计算公式:DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举
5、key跳转重定向
说明:客户端向已迁移(或错误的节点)发送键指令 ,该节点发现指令的key所在的槽位的值并不归自己管理,这时会给客户端回复一个特殊的ask转向携带目标操作的节点地址,告诉客户端去访问这个节点获取数据,客户端收到指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有的key都会使用新的槽位映射表。