分区与集群 https://blog.csdn.net/ko0491/article/details/109218004 proxy分区 https://blog.csdn.net/ko0491/article/details/109218776
Redis3.0之后,Redis官方提供了完整的集群解决方案。 方案采用去中心化的方式,包括:sharding(分区)、replication(复制)、failover(故障转移)。 称为RedisCluster。 Redis5.0前采用redis-trib进行集群的创建和管理,需要ruby支持 Redis5.0可以直接使用Redis-cli进行集群的创建和管理
RedisCluster由多个Redis节点组构成,是一个P2P无中心节点的集群架构,依靠Gossip协议传播的集群
Gossip协议是一个通信协议,一种传播消息的方式。 起源于:病毒传播 Gossip协议基本思想就是: 一个节点周期性(每秒)随机选择一些节点,并把信息传递给这些节点。 这些收到信息的节点接下来会做同样的事情,即把这些信息传递给其他一些随机选择的节点。 信息会周期性的传递给N个目标节点。这个N被称为fanout(扇出) gossip协议包含多种消息,包括meet、ping、pong、fail、publish等等
通过gossip协议,cluster可以提供集群间状态同步更新、选举自助failover等重要的集群功能
### slot redis-cluster把所有的物理节点映射到[0-16383]个slot上,基本上采用平均分配和连续分配的方式。 比如上图中有5个主节点,这样在RedisCluster创建时,slot槽可按下表分配: cluster 负责维护节点和slot槽的对应关系 value------>slot-------->节点 当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。 比如: set name zhaoyun hash(“name”)采用crc16算法,得到值:1324203551%16384=15903 根据上表15903在13088-16383之间,所以name被存储在Redis5节点。 slot槽必须在节点上连续分配,如果出现不连续的情况,则RedisCluster不能工作,详见容错。
高性能 Redis Cluster 的性能与单节点部署是同级别的。 多主节点、负载均衡、读写分离
高可用 Redis Cluster 支持标准的 主从复制配置来保障高可用和高可靠。
failover Redis Cluster 也实现了一个类似 Raft 的共识方式,来保障整个集群的可用性。
易扩展 向 Redis Cluster 中添加新节点,或者移除节点,都是透明的,不需要停机。 水平、垂直方向都非常容易扩展。 数据分区,海量数据,数据存储
原生 部署 Redis Cluster 不需要其他的代理或者工具,而且 Redis Cluster 和单机 Redis 几乎完全兼 容。
RedisCluster最少需要三台主服务器,三台从服务器。 端口号分别为:7001~7006
mkdir redis-cluster/7001 make install PREFIX=/var/redis-cluster/7001 第一步:创建7001实例,并编辑redis.conf文件,修改port为7001。 注意:创建实例,即拷贝单机版安装时,生成的bin目录,为7001目录第二步:修改redis.conf配置文件,打开cluster-enable yes
第三步:复制7001,创建7002~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 (赋写和执行的权限)
第五步:创建Redis集群(创建时Redis里不要有数据) # cluster-replicas : 1 1从机 前三个为主 [root@localhost bin]# ./redis-cli --cluster create 192.168.127.128:7001 192.168.127.128:7002 192.168.127.128:7003 192.168.127.128:7004 192.168.127.128:7005 192.168.127.128:7006 --cluster-replicas 1 >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 192.168.127.128:7005 to 192.168.127.128:7001 Adding replica 192.168.127.128:7006 to 192.168.127.128:7002 Adding replica 192.168.127.128:7004 to 192.168.127.128:7003 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: 02fdca827762904854293590323bb398e6bee971 192.168.127.128:7001 slots:[0-5460] (5461 slots) master M: 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 192.168.127.128:7002 slots:[5461-10922] (5462 slots) master M: 95598dd50a91a72812ab5d441876bf2ee40ceef4 192.168.127.128:7003 slots:[10923-16383] (5461 slots) master S: 633af51cfdadb907e4d930f3f10082a77b256efb 192.168.127.128:7004 replicates 02fdca827762904854293590323bb398e6bee971 S: 2191b40176f95a2a969bdcaccdd236aa01a3099a 192.168.127.128:7005 replicates 2dddc9d3925d129edd4c6bd5eab3bbad531277ec S: 1d35bec18fcc23f2c555a25563b1e6f2ffa3b0e9 192.168.127.128:7006 replicates 95598dd50a91a72812ab5d441876bf2ee40ceef4 Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join ..... >>> Performing Cluster Check (using node 192.168.127.128:7001) M: 02fdca827762904854293590323bb398e6bee971 192.168.127.128:7001 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: 95598dd50a91a72812ab5d441876bf2ee40ceef4 192.168.127.128:7003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: 2191b40176f95a2a969bdcaccdd236aa01a3099a 192.168.127.128:7005 slots: (0 slots) slave replicates 2dddc9d3925d129edd4c6bd5eab3bbad531277ec S: 633af51cfdadb907e4d930f3f10082a77b256efb 192.168.127.128:7004 slots: (0 slots) slave replicates 02fdca827762904854293590323bb398e6bee971 S: 1d35bec18fcc23f2c555a25563b1e6f2ffa3b0e9 192.168.127.128:7006 slots: (0 slots) slave replicates 95598dd50a91a72812ab5d441876bf2ee40ceef4 M: 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 192.168.127.128:7002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.命令客户端连接集群 命令
./redis-cli -h 127.0.0.1 -p 7001 -c注意:-c 表示是以redis集群方式进行连接
[root@localhost redis-cluster]# cd 7001 [root@localhost 7001]# ./redis-cli -h 127.0.0.1 -p 7001 -c 127.0.0.1:7001> set name1 aaa -> Redirected to slot [12933] located at 127.0.0.1:7003 OK 127.0.0.1:7003>查看集群的命令 查看集群状态
127.0.0.1:7003> cluster info cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:3 cluster_stats_messages_sent:926 cluster_stats_messages_received:926查看集群中的节点
127.0.0.1:7003> cluster nodes d277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 myself,master - 0 1570457306000 3 connected 10923-16383 af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 master - 0 1570457307597 1 connected 0-5460 e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave 068b678923ad0858002e906040b0fef6fff8dda4 0 1570457308605 5 connected 068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 0 1570457309614 2 connected 5461-10922 51c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slave af559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570457307000 4 connected 78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slave d277cd2984639747a17ca79428602480b28ef070 0 1570457309000 6 connected 127.0.0.1:7003>不同节点分组服务于相互无交集的分片(sharding),Redis Cluster 不存在单独的proxy或配置服务器,所以需要将客户端路由到目标的分片
Redis Cluster的客户端相比单机Redis 需要具备路由语义的识别能力,且具备一定的路由缓存能力
1.每个节点通过通信都会共享Redis Cluster中槽和集群中对应节点的关系 2.客户端向Redis Cluster的任意节点发送命令,接收命令的节点会根据CRC16规则进行hash运算与16384取余,计算自己的槽和对应节点 3.如果保存数据的槽被分配给当前节点,则去槽中执行命令,并把命令执行结果返回给客户端 4.如果保存数据的槽不在当前节点的管理范围内,则向客户端返回moved重定向异常 5.客户端接收到节点返回的结果,如果是moved异常,则从moved异常中获取目标节点的信息 6.客户端向目标节点发送命令,获取命令执行结果
[root@localhost bin]# ./redis-cli -h 127.0.0.1 -p 7001 -c 127.0.0.1:7001> set name:001 zhaoyun OK 127.0.0.1:7001> get name:001 "zhaoyun" [root@localhost bin]# ./redis-cli -h 127.0.0.1 -p 7002 -c 127.0.0.1:7002> get name:001 -> Redirected to slot [4354] located at 127.0.0.1:7001 "zhaoyun" 127.0.0.1:7001> cluster keyslot name:001 (integer) 4354在对集群进行扩容和缩容时,需要对槽及槽中数据进行迁移 当客户端向某个节点发送命令,节点向客户端返回moved异常,告诉客户端数据对应的槽的节点信息 如果此时正在进行集群扩展或者缩空操作,当客户端向正确的节点发送命令时,槽及槽中数据已经被迁 移到别的节点了,就会返回ask,这就是ask重定向机制 1.客户端向目标节点发送命令,目标节点中的槽已经迁移支别的节点上了,此时目标节点会返回ask转 向给客户端 2.客户端向新的节点发送Asking命令给新的节点,然后再次向新节点发送命令 3.新节点执行命令,把命令执行结果返回给客户端
moved和ask的区别 1、moved:槽已确认转移 2、ask:槽还在转移过程中
JedisCluster JedisCluster是Jedis根据RedisCluster的特性提供的集群智能客户端 JedisCluster为每个节点创建连接池,并跟节点建立映射关系缓存(Cluster slots) JedisCluster将每个主节点负责的槽位一一与主节点连接池建立映射缓存 JedisCluster启动时,已经知道key,slot和node之间的关系,可以找到目标节点 JedisCluster对目标节点发送命令,目标节点直接响应给JedisCluster 如果JedisCluster与目标节点连接出错,则JedisCluster会知道连接的节点是一个错误的节点 此时节点返回moved异常给JedisCluster JedisCluster会重新初始化slot与node节点的缓存关系,然后向新的目标节点发送命令,目标命令执行 命令并向JedisCluster响应 如果命令发送次数超过5次,则抛出异常"Too many cluster redirection!"
JedisPoolConfig config = new JedisPoolConfig(); Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>(); jedisClusterNode.add(new HostAndPort("192.168.127.128", 7001)); jedisClusterNode.add(new HostAndPort("192.168.127.128", 7002)); jedisClusterNode.add(new HostAndPort("192.168.127.128", 7003)); jedisClusterNode.add(new HostAndPort("192.168.127.128", 7004)); jedisClusterNode.add(new HostAndPort("192.168.127.128", 7005)); jedisClusterNode.add(new HostAndPort("192.168.127.128", 7006)); JedisCluster jcd = new JedisCluster(jedisClusterNode, config); jcd.set("name:001","zhangfei"); String value = jcd.get("name:001");添加主节点 先创建7007节点 (无数据)
mkdir redis-cluster/7007 make install PREFIX=/var/redis-cluster/7007hash槽重新分配(数据迁移) 添加完主节点需要对主节点进行hash槽分配,这样该主节才可以存储数据。
cluster nodes
redis集群有16384个槽,集群中的每个结点分配自已槽,通过查看集群结点可以看到槽占用情况
127.0.0.1:7001> cluster nodes d277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 master - 0 1570457568602 3 connected 10923-16383 50b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007@17007 master - 0 1570457567000 0 connected e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave 068b678923ad0858002e906040b0fef6fff8dda4 0 1570457569609 5 connected 068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 0 1570457566000 2 connected 5461-10922 51c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slave af559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570457567000 4 connected af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 myself,master - 0 1570457567000 1 connected 0-5460 78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slave d277cd2984639747a17ca79428602480b28ef070 0 1570457567593 6 connected输入:3000,表示要给目标节点分配3000个槽
What is the receiving node ID? 输入:50b073163bc4058e89d285dc5dfc42a0d1a222f2
50b073163bc4058e89d285dc5dfc42a0d1a222f2
输入:all
输入yes
查看结果
127.0.0.1:7001> cluster nodes 95598dd50a91a72812ab5d441876bf2ee40ceef4 192.168.127.128:7003@17003 master - 0 1595301163000 3 connected 11922-16383 6ff20bf463c954e977b213f0e36f3efc02bd53d6 192.168.127.128:7007@17007 master - 0 1595301164568 7 connected 0-998 5461-6461 10923-11921 2191b40176f95a2a969bdcaccdd236aa01a3099a 192.168.127.128:7005@17005 slave 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 0 1595301163000 5 connected 633af51cfdadb907e4d930f3f10082a77b256efb 192.168.127.128:7004@17004 slave 02fdca827762904854293590323bb398e6bee971 0 1595301164000 4 connected 1d35bec18fcc23f2c555a25563b1e6f2ffa3b0e9 192.168.127.128:7006@17006 slave 95598dd50a91a72812ab5d441876bf2ee40ceef4 0 1595301161521 6 connected 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 192.168.127.128:7002@17002 master - 0 1595301162000 2 connected 6462-10922 02fdca827762904854293590323bb398e6bee971 192.168.127.128:7001@17001 myself,master - 0 1595301160000 1 connected 999-5460
例如:
./redis-cli --cluster add-node 192.168.127.128:7008 192.168.127.128:7007 -- cluster-slave --cluster-master-id 6ff20bf463c954e977b213f0e36f3efc02bd53d650b073163bc4058e89d285dc5dfc42a0d1a222f2是7007结点的id,可通过cluster nodes查看
[root@localhost bin]# ./redis-cli --cluster add-node 192.168.127.128:7008 192.168.127.128:7007 --cluster-slave --cluster-master-id 6ff20bf463c954e977b213f0e36f3efc02bd53d6
Adding node 192.168.127.128:7008 to cluster 192.168.127.128:7007 Performing Cluster Check (using node 192.168.127.128:7007) M: 6ff20bf463c954e977b213f0e36f3efc02bd53d6 192.168.127.128:7007 slots:[0-998],[5461-6461],[10923-11921] (2999 slots) master S: 1d35bec18fcc23f2c555a25563b1e6f2ffa3b0e9 192.168.127.128:7006 slots: (0 slots) slave replicates 95598dd50a91a72812ab5d441876bf2ee40ceef4 S: 633af51cfdadb907e4d930f3f10082a77b256efb 192.168.127.128:7004 slots: (0 slots) slave replicates 02fdca827762904854293590323bb398e6bee971 M: 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 192.168.127.128:7002 slots:[6462-10922] (4461 slots) master 1 additional replica(s) M: 02fdca827762904854293590323bb398e6bee971 192.168.127.128:7001 slots:[999-5460] (4462 slots) master 1 additional replica(s) S: 2191b40176f95a2a969bdcaccdd236aa01a3099a 192.168.127.128:7005 slots: (0 slots) slave replicates 2dddc9d3925d129edd4c6bd5eab3bbad531277ec M: 95598dd50a91a72812ab5d441876bf2ee40ceef4 192.168.127.128:7003 slots:[11922-16383] (4462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration.
Check for open slots… Check slots coverage… [OK] All 16384 slots covered.
Send CLUSTER MEET to node 192.168.127.128:7008 to make it join the cluster. Waiting for the cluster to join
Configure node as replica of 192.168.127.128:7007. [OK] New node added correctly.
注意:如果原来该结点在集群中的配置信息已经生成到cluster-config-file指定的配置文件中(如果 cluster-config-file没有指定则默认为nodes.conf),这时可能会报错
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
解决方法是删除生成的配置文件nodes.conf,删除后再执行./redis-cli --cluster add-node 指令
[root@localhost 7008]# ./redis-cli -h 127.0.0.1 -p 7001 -c 127.0.0.1:7001> cluster nodes 95598dd50a91a72812ab5d441876bf2ee40ceef4 192.168.127.128:7003@17003 master - 0 1595301378000 3 connected 11922-16383 6be94480315ab0dd2276a7f70c82c578535d6666 192.168.127.128:7008@17008 slave 6ff20bf463c954e977b213f0e36f3efc02bd53d6 0 1595301378701 7 connected 6ff20bf463c954e977b213f0e36f3efc02bd53d6 192.168.127.128:7007@17007 master - 0 1595301379715 7 connected 0-998 5461-6461 10923-11921 2191b40176f95a2a969bdcaccdd236aa01a3099a 192.168.127.128:7005@17005 slave 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 0 1595301375666 5 connected 633af51cfdadb907e4d930f3f10082a77b256efb 192.168.127.128:7004@17004 slave 02fdca827762904854293590323bb398e6bee971 0 1595301379000 4 connected 1d35bec18fcc23f2c555a25563b1e6f2ffa3b0e9 192.168.127.128:7006@17006 slave 95598dd50a91a72812ab5d441876bf2ee40ceef4 0 1595301380731 6 connected 2dddc9d3925d129edd4c6bd5eab3bbad531277ec 192.168.127.128:7002@17002 master - 0 1595301376000 2 connected 6462-10922 02fdca827762904854293590323bb398e6bee971 192.168.127.128:7001@17001 myself,master - 0 1595301376000 1 connected 999-5460
命令:
./redis-cli --cluster del-node 192.168.127.128:7008 6be94480315ab0dd2276a7f70c82c578535d6666删除已经占有hash槽的结点会失败,报错如下 [ERR] Node 192.168.127.128:7008 is not empty! Reshard data away and try again.
需要将该结点占用的hash槽分配出去。
集群中的每个节点都会定期地(每秒)向集群中的其他节点发送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槽分配不连续)
当slave 收到过半的master 同意时,会成为新的master。此时会以最新的Epoch 通过PONG 消息广播自己成为master,让Cluster 的其他节点尽快的更新拓扑结构(node.conf)
自动切换 就是上面讲的从节点选举
人工故障切换是预期的操作,而非发生了真正的故障,目的是以一种安全的方式(数据无丢失)将当前master节点和其中一个slave节点(执行cluster-failover的节点)交换角色
1、向从节点发送cluster failover 命令(slaveof no one) 2、从节点告知其主节点要进行手动切换(CLUSTERMSG_TYPE_MFSTART) 3、主节点会阻塞所有客户端命令的执行(10s) 4、从节点从主节点的ping包中获得主节点的复制偏移量 5、从节点复制达到偏移量,发起选举、统计选票、赢得选举、升级为主节点并更新配置 6、切换完成后,原主节点向所有客户端发送moved指令重定向到新的主节点 以上是在主节点在线情况下。 如果主节点下线了,则采用cluster failover force或cluster failover takeover 进行强制切换
我们知道在一主一从的情况下,如果主从同时挂了,那整个集群就挂了。 为了避免这种情况我们可以做一主多从,但这样成本就增加了。 Redis提供了一种方法叫副本漂移,这种方法既能提高集群的可靠性又不用增加太多的从机
集群检测到新的Master1是单点的(无从机) 集群从拥有最多的从机的节点组(Master3)中,选择节点名称字母顺序最小的从机(Slaver31)漂移 到单点的主从节点组(Master1)。
具体流程如下(以上图为例):
1、将Slaver31的从机记录从Master3中删除 2、将Slaver31的的主机改为Master1 3、在Master1中添加Slaver31为从节点 4、将Slaver31的复制源改为Master1 5、通过ping包将信息同步到集群的其他节点
