分区是将数据分布在多个Redis实例(Redis主机)上,以至于每个实例只包含一部分数据
- 性能的提升
单机Redis的网络I/O能力和计算资源是有限的,将请求分散到多台机器,充分利用多台机器的计算能力 可网络带宽,有助于提高Redis总体的服务能力。
- 存储能力的横向扩展
即使Redis的服务能力能够满足应用需求,但是随着存储数据的增加,单台机器受限于机器本身的存储 容量,将数据分散到多台机器上存储使得Redis服务可以横向扩展。
根据id数字的范围比如1--10000、100001--20000.....90001-100000,每个范围分到不同的Redis实例 中
- 好处:
实现简单,方便迁移和扩展
- 缺陷:
热点数据分布不均,性能损失
非数字型key,比如uuid无法使用(可采用雪花算法替代
利用简单的hash算法即可:
Redis实例=hash(key)%N key:要进行分区的键,比如user_id N:Redis实例个数(Redis主机)
- 好处:
支持任何类型的key
热点分布较均匀,性能较好
- 缺陷:
迁移复杂,需要重新计算,扩展较差(利用一致性hash环)
对于一个给定的key,客户端直接选择正确的节点来进行读写。许多Redis客户端都实现了客户端分区 (JedisPool),也可以自行编程实现。
(1)hash
- 优势 :实现简单,热点数据分布均匀
- 缺陷 :节点数固定,扩展的话需要重新计算
(2) 一致性hash
我们有3台缓存服务器,服务器A、服务器B、服务器C,那么,在生产环境中,这三台服务器肯定 有自己的IP地址,我们使用它们各自的IP地址进行哈希计算,使用哈希后的结果对2^32取模,
使用 如下公式: hash(服务器的IP地址) % 2^32
Redis3.0之后,Redis官方提供了完整的集群解决方案。 方案采用去中心化的方式,包括:sharding(分区)、replication(复制)、failover(故障转移)。 称为RedisCluster。
Redis5.0前采用redis-trib进行集群的创建和管理,需要ruby支持。
Redis5.0可以直接使用Redis-cli进行集群的创建和管理。
RedisCluster由多个Redis节点组构成,是一个P2P无中心节点的集群架构,依靠Gossip协议传播的集 群。
Gossip协议是一个通信协议,一种传播消息的方式。
起源于:病毒传播
Gossip协议基本思想就是:
一个节点周期性(每秒)随机选择一些节点,并把信息传递给这些节点。 这些收到信息的节点接下来会做同样的事情,即把这些信息传递给其他一些随机选择的节点
通过gossip协议,cluster可以提供集群间状态同步更新、选举自助failover等重要的集群功能
redis-cluster把所有的物理节点映射到[0-16383]个slot上,基本上采用平均分配和连续分配的方式。 比如上图中有5个主节点,这样在RedisCluster创建时,slot槽可按下表分配
比如:
set name zhaoyun hash("name")采用crc16算法,
得到值:1324203551%16384=15903
根据上表15903在13088-16383之间,所以name被存储在Redis5节点。
- 高性能
Redis Cluster 的性能与单节点部署是同级别的。
多主节点、负载均衡、读写分离
- 高可用
Redis Cluster 支持标准的 主从复制配置来保障高可用和高可靠
Redis Cluster 也实现了一个类似 Raft 的共识方式,来保障整个集群的可用性。
- 易扩展
向Redis Cluster 中添加新节点,或者移除节点,都是透明的,不需要停机。
水平、垂直方向都非常容易扩展。
数据分区,海量数据,数据存储
- 原生
部署 Redis Cluster 不需要其他的代理或者工具,而且 Redis Cluster 和单机 Redis 几乎完全兼 容。
RedisCluster最少需要三台主服务器,三台从服务器。 端口号分别为:7001~7006
mkdir redis-cluster/7001 make install PREFIX=/var/redis-cluster/7001 cp /var/redis-5.0.5/redis.conf /var/redis-cluster/7001/bin修改redis.conf配置文件,打开cluster-enable yes
第三步:复制7001,创建7002~7006实例,注意端口修改。
cp -r /var/redis-cluster/7001/* /var/redis-cluster/7002
cp -r /var/redis-cluster/7001/* /var/redis-cluster/7003
cp -r /var/redis-cluster/7001/* /var/redis-cluster/7004
cp -r /var/redis-cluster/7001/* /var/redis-cluster/7005
cp -r /var/redis-cluster/7001/* /var/redis-cluster/7006
第四步:创建start.sh,启动所有的实例
cd 7001/bin ./redis-server redis.conf cd .. cd .. cd 7002/bin ./redis-server redis.conf cd .. cd .. cd 7003/bin ./redis-server redis.conf cd .. cd .. cd 7004/bin ./redis-server redis.conf cd .. cd .. cd 7005/bin ./redis-server redis.conf cd .. cd .. cd 7006/bin ./redis-server redis.conf cd .. cd .. chmod u+x start.sh (赋写和执行的权限) ./start.sh(启动RedisCluster)第五步:创建Redis集群(创建时Redis里不要有数据)
./redis-cli --cluster create 192.168.72.128:7001 192.168.72.128:7002 192.168.72.128:7003 192.168.72.128:7004 192.168.72.128:7005 192.168.72.128:7006 --cluster-replicas 1
cd 7001
/redis-cli -h 127.0.0.1 -p 7001 -c
查看集群状态
cluster info
查看集群中的节点:
cluster nodes
mkdir redis-cluster/7007 make install PREFIX=/var/redis-cluster/7007 ./redis-cli --cluster add-node 192.168.72.128:7007 192.168.72.128:7001 #查看集群结点发现7007已添加到集群中 cluster nodes 添加完主节点需要对主节点进行hash槽分配,这样该主节才可以存储数据。 查看集群中槽占用情况 cluster nodes 给刚添加的7007结点分配槽 ./redis-cli --cluster reshard 192.168.72.128:7007 输入要分配的槽数量 How many slots do you want to move (from 1 to 16384)? 3000 输入接收槽的结点id What is the receiving node ID? 这里准备给7007分配槽,通过cluster nodes查看7007结点id为: 50b073163bc4058e89d285dc5dfc42a0d1a222f2 输入源结点iD 输入:all 输入yes开始移动槽到目标结点id yes 查看结果 cluster nodes 添加从节点 添加7008从结点,将7008作为7007的从结点 (50b073163bc4058e89d285dc5dfc42a0d1a222f2是7007结点的id) ./redis-cli --cluster add-node 192.168.72.128:7008 192.168.72.128:7007 -- cluster-slave --cluster-master-id 6ff20bf463c954e977b213f0e36f3efc02bd53d6 查看集群中的结点,刚添加的7008为7007的从节点: ./redis-cli -h 127.0.0.1 -p 7001 -c cluster nodes
./redis-cli --cluster del-node 192.168.127.128:7008 6be94480315ab0dd2276a7f70c82c578535d6666
集群中的每个节点都会定期地(每秒)向集群中的其他节点发送PING消息 如果在一定时间内(cluster-node-timeout),发送ping的节点A没有收到某节点B的pong回应,则A将B 标识为pfail。 A在后续发送ping时,会带上B的pfail信息, 通知给其他节点。 如果B被标记为pfail的个数大于集群主节点个数的一半(N/2 + 1)时,B会被标记为fail,A向整个集群 广播,该节点已经下线。 其他节点收到广播,标记B为fail。
raft,每个从节点,都根据自己对master复制数据的offset,来设置一个选举时间,offset越大(复制数 据越多)的从节点,选举时间越靠前,优先进行选举。 slave 通过向其他master发送FAILVOER_AUTH_REQUEST 消息发起竞选, master 收到后回复FAILOVER_AUTH_ACK 消息告知是否同意。 slave 发送FAILOVER_AUTH_REQUEST 前会将currentEpoch 自增,并将最新的Epoch 带入到 FAILOVER_AUTH_REQUEST 消息中,如果自己未投过票,则回复同意,否则回复拒绝。
所有的Master开始slave选举投票,给要进行选举的slave进行投票,如果大部分master node(N/2 + 1)都投票给了某个从节点,那么选举通过,那个从节点可以切换成master。 RedisCluster失效的判定: 1、集群中半数以上的主节点都宕机(无法投票) 2、宕机的主节点的从节点也宕机了(slot槽分配不连续)
所有的Master开始slave选举投票,给要进行选举的slave进行投票,如果大部分master node(N/2 + 1)都投票给了某个从节点,那么选举通过,那个从节点可以切换成master。 RedisCluster失效的判定: 1、集群中半数以上的主节点都宕机(无法投票) 2、宕机的主节点的从节点也宕机了(slot槽分配不连续)
我们知道在一主一从的情况下,如果主从同时挂了,那整个集群就挂了。 为了避免这种情况我们可以做一主多从,但这样成本就增加了。 Redis提供了一种方法叫副本漂移,这种方法既能提高集群的可靠性又不用增加太多的从机。
Master1宕机,则Slaver11提升为新的Master1 集群检测到新的Master1是单点的(无从机) 集群从拥有最多的从机的节点组(Master3)中,选择节点名称字母顺序最小的从机(Slaver31)漂移 到单点的主从节点组(Master1)。