您当前的位置:首页 > 电脑百科 > 数据库 > Redis

Redis集群原理与容器化部署

时间:2022-09-15 09:55:51  来源:网易号  作者:互联共商

1、集群原理简介1.1、什么是集群?什么是分区?

集群简单的说就是将同一个服务部署在不同的机器上,从而提高服务的横向扩展能力。

分区就是将数据分布在多个实例(服务器)上,让每一个实例都只存储一部分数据,从而达到增大总的存储数据量的效果。

1.2、为什么要实用集群?

为什么要实用集群呢?主从+哨兵模式不是已经很好了吗,已经高可用了吗?

但是主从+哨兵虽然解决了高可用问题,但是没有解决数据分区存储问题。因为我们存储的数据量大小取决于主服务器的存储容量。那么集群模式将数据分区存储就是为了实现数据存储量可以横向扩展。

1.3、数据分区的优点与缺点?

优点

 

  • 1、性能提升
    • 单机redis的网络I/O能力和计算能力是有限的,将请求分发到多台机器,充分利用多台机器的计算能力和带宽,有助于redis总体的服务能力。
  • 2、存储能力横向扩展
    • 即使Redis的存储能力已经能满足大部分需求,但是随着key的数量不断增加,单台机器受限于机器本身的存储容量,将数据分散到多台机器存储使得Redis服务可以横向扩展。

 

缺点

 

  • 1、管理更加复杂
    • Redis数据分散到多台机器,管理起来自然会更加的复杂。还涉及到数据迁移等工作,增大了操作难度。
  • 2、分散后的数据节点宕机使得集群缺少部分数据(可以使用主从解决)
1.4、分区方式

 

一般按照分区键(ID)进行分区,分区方式一般有范围分区和Hash分区方式。

1.4.1、范围分区

根据ID数字额范围分区,比如:1-10000,100001-20000...90001-100000。每个范围分到不同得Redis实例中。

优点

实现简单,方便迁移和扩展

缺点

数据分布不均匀,可以少数节点占据了大多数的数据。性能损失比较严重。

非数字型的key,比如UUID就无法使用,当然,可以使用雪花算法代替ID的生成。雪花算法是数值且能够排序。

1.4.2、Hash分区

利用简单的hash算法就可以,比如根据key求hash值,对Redis实例的总数执行取模操作,从而计算落在哪个Redis实例上。

优点

支持所有key类型, key分布均匀, 性能比较好

缺点

迁移复杂,需要重新计算,扩展较差(但是可以利用一致性hash环拓展)。 而Hash算法在客户端链接服务端时,被广泛使用(比如:JedisPool)。

1.5、客户端分区

对于给定一个key, 客户端可以直接选择正确的节点进行读写。许多客户端都实现了客户端分区(比如:RedisPool),当然,也可以自己编码是现实。


 

客户端有很多种计算key的落地到那个Redis实例的算法,这个时最普通的hash算法。

1.5.1、普通hash算法

计算公式:hash(key)%N;hash:可以采用hash算法,比如CRC32、CRC16等;N:是Redis主机个数。

优点

数据分布均匀,实现简单

缺点

节点数量固定,扩展的话需要重新计算hash。

查询必须采用分片的key来查询,一旦key变化了,数据就查询不出来了,所以不要轻易改变key的分区。

1.5.1、一致性hash算法1.5.1.1、算法简介

普通hash是对主机数量取模,而一致性hash是对2^32(4 294 967 296)取模(一个足够大的hash表)。

我们把2^32想象成一个圆,就像钟表一样,钟表的圆可以理解成由60个点组成的圆,而此处我们把这个圆想象成由2^32个点组成的圆,示意图如下:


 

圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1 。我们把这个由2的32次方个点组成的圆环称为hash环。

假设我们有3台缓存服务器(A/B/C),使用它们各自的IP地址进行哈希计算,使用哈希后的结果对2^32取模,可以使用如下公式:

hash("服务器的IP地址") % 2^32

通过上述公式算出的结果一定是一个0到2^32-1之间的一个整数,我们就用算出的这个整数,分别代表服务器(A/B/C).

既然这个整数肯定处于0到2^32-1之间,那么,上图中的hash环上必定有一个点与这个整数对应,也就是服务器A/B/C就可以映射到这个环上,如下图:


 

假设,我们需要使用Redis缓存数据,那么我们使用如下公式可以将数据映射到上图中的hash环上

hash(key) % 2^32

现在服务器与数据都被映射到了hash环上,上图中的数据将会被缓存到服务器A上。

因为数据的开始位置,沿顺时针方向遇到的第一个服务器就是A服务器,所以,上图中的数据将会被缓存到服务器A上。


 

1.5.1.2、一致性hash算法有缺点

优点

添加或移除节点时,数据只需要做部分的迁移,比如上图中把C服务器移除,则数据4迁移到服务器A中,而其他的数据保持不变。

缺点

数据分布不均匀,可能出现所有的key都被hash到同一个节点上了,折中现象叫做hash环偏移。

理论上我们可以增加服务器数量来减少便宜,但是这样成本太高了。所以通过增加虚拟节点来处理。

1.5.1.3、一致性hash虚拟节点

"虚拟节点"是"实际节点"(实际的物理服务器)在hash环上的复制品,一个实际节点可以对应多个虚拟节点。

从上图可以看出,A、B、C三台服务器分别虚拟出了一个虚拟节点,当然,如果你需要,也可以虚拟出更多的虚拟节点。

引入虚拟节点的概念后,缓存的分布就均衡多了,上图中,1和3号数据被缓存在服务器A中,4和5号数据被缓存在服务器B中,2和6号数据被缓存在服务器C中.

如果你还不放心,可以虚拟出更多的虚拟节点,以便减小hash环偏斜所带来的影响,虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的概率就越大。


 

一般来说,一致性hash算法+虚拟节点就是一个很好的方案了。

1.5.1.4、一致性hash算法实现

一致性hash算法(无虚拟节点)

public class HashDemo { public static void mAIn(String[] args) { //step1 初始化:把服务器节点IP的哈希值对应到哈希环上 // 定义服务器ip String[] servers = new String[]{"192.168.222.101", "192.168.222.102", "192.168.222.103"}; // 创建一个排序的hashMap,key存储hash值,value存储服务器IP地址,并按照Hash值排序 SortedMap hashServerMap = new TreeMap<>(); for (String redisServer : servers) { // 求出每⼀个ip的hash值,对应到hash环上,存储hash值与ip的对应关系 int serverHash = Math.abs(redisServer.hashCode()); // 存储hash值与ip的对应关系 hashServerMap.put(serverHash, redisServer); } //step2 针对客户端IP求出hash值 // 定义客户端传递过来的RedisKey String[] redisKeys = new String[]{"user:001:name", "user:001:age", "user:001:sex"}; for (String redisKey : redisKeys) { // 计算redisKey的hash值 int redisKeyHash = Math.abs(redisKey.hashCode()); //step3 针对客户端,找到能够处理当前RedisKey的服务器(哈希环上顺时针最近) // 根据redisKey的哈希值去找出哪⼀个服务器节点能够处理 // tailMap返回此映射的键大于或等于fromKey的部分,也就是比redisKey的hash值大的排序列表,取第一个就是最近的服务器节点 SortedMap filteredSortedMap = hashServerMap.tailMap(redisKeyHash); // 获取key落到那台服务器,filteredSortrdMap为空,直接取服务器列表hashServerMap第一个,不为空,则取出最近一个filteredSortrdMap Integer hashKey = filteredSortedMap.isEmpty() ? hashServerMap.firstKey() : filteredSortedMap.firstKey(); System.out.println("==========>>>>RedisKey:" + redisKey + " 被路由到服务器:" + hashServerMap.get(hashKey)); } } }

运行结果

==========>>>>RedisKey:user:001:name 被路由到服务器:192.168.222.101 ==========>>>>RedisKey:user:001:age 被路由到服务器:192.168.222.101 ==========>>>>RedisKey:user:001:sex 被路由到服务器:192.168.222.101

可以看出,Redis的key被路由到同一个节点了,我们使用增加虚拟节点来避免折中情况。

一致性hash算法(有虚拟节点)

public class HashDemo2 { public static void main(String[] args) { //step1 初始化:把服务器节点IP的哈希值对应到哈希环上 // 定义服务器ip String[] servers = new String[]{"192.167.222.101", "192.168.222.103", "191.169.222.123"}; // 创建一个排序的hashMap,key存储hash值,value存储服务器IP地址,并按照Hash值排序 SortedMap hashServerMap = new TreeMap<>(); // 定义针对每个真实服务器虚拟出来⼏个节点 int virtualCount = 3; for (String redisServer : servers) { // 求出每⼀个ip的hash值,对应到hash环上,存储hash值与ip的对应关系 int serverHash = Math.abs(redisServer.hashCode()); // 存储hash值与ip的对应关系 hashServerMap.put(serverHash, redisServer); // 处理虚拟节点 for(int i = 0; i < virtualCount; i++) { int virtualHash = Math.abs((redisServer + "#" + i).hashCode()); hashServerMap.put(virtualHash,"----由虚拟节点"+ i + "映射过来的请求:"+ redisServer); } } //step2 针对客户端IP求出hash值 // 定义客户端传递过来的RedisKey String[] redisKeys = new String[]{ "user:001:name", "order:001:name", "product:001:name", "user:002:name", "order:002:name", "product:002:name", }; for (String redisKey : redisKeys) { // 计算redisKey的hash值 int redisKeyHash = Math.abs(redisKey.hashCode()); //step3 针对客户端,找到能够处理当前RedisKey的服务器(哈希环上顺时针最近) // 根据redisKey的哈希值去找出哪⼀个服务器节点能够处理 // tailMap返回此映射的键大于或等于fromKey的部分,也就是比redisKey的hash值大的排序列表,取第一个就是最近的服务器节点 SortedMap filteredSortedMap = hashServerMap.tailMap(redisKeyHash); // 获取key落到那台服务器,filteredSortrdMap为空,直接取服务器列表hashServerMap第一个,不为空,则取出最近一个filteredSortrdMap Integer hashKey = filteredSortedMap.isEmpty() ? hashServerMap.firstKey() : filteredSortedMap.firstKey(); System.out.println("==========>>>>RedisKey:" + redisKey + " 被路由到服务器:" + hashServerMap.get(hashKey)); } } }

运行结果

==========>>>>RedisKey:user:001:name 被路由到服务器:192.167.222.101 ==========>>>>RedisKey:order:001:name 被路由到服务器:191.169.222.123 ==========>>>>RedisKey:product:001:name 被路由到服务器:191.169.222.123 ==========>>>>RedisKey:user:002:name 被路由到服务器:----由虚拟节点2映射过来的请求:191.169.222.123 ==========>>>>RedisKey:order:002:name 被路由到服务器:191.169.222.123 ==========>>>>RedisKey:product:002:name 被路由到服务器:191.169.222.123

可以看出,虚拟节点确实生效了。

2、Redis集群

Redis3.0之后,Redis官方提供了完整的集群解决方案,称为Rediscluster。

Redis集群方案采用去中心化的方式,包括:sharding(分区)、replication(复制)、failover(故障转移)。

Redis5.0前采用redis-trib进行集群的创建和管理,需要ruby支持。Redis5.0可以直接使用Redis-cli进行集群的创建和管理。

2.1、Redis集群部署架构


 

Redis的部署架构时没有中心的,每个节点都是主节点,是一个P2P(点对点)的去中心化集群架构,依靠gossip协议用于集群间传播。

2.2、Gossip协议

Gossip协议是一个通信协议,一种传播消息的方式,它起源于病毒传播。

Gossip协议基本思想

一个节点周期性(每秒)随机选择一些节点,并把信息传递给这些节点。

这些收到信息的节点接下来会做同样的事情,即把这些信息传递给其他一些随机选择的节点。

信息会周期性的传递给N个目标节点。这个N被称为fanout(扇出)。

gossip协议包含多种消息,包括meet、ping、pong、fail、publish等等。

 

  • 1、meet:sender向receiver发出,请求receiver加入sender的集群(加入集群时的协议)
  • 2、ping:节点检测其他节点是否在线
  • 3、pong:receiver收到meet或ping后的回复信息;在failover后,新的Master也会广播pong
  • 4、fail:节点A判断节点B下线后,A节点广播B的fail信息,其他收到节点会将B节点标记为下线
  • 5、节点A收到publish命令,执行该命令,并向集群广播publish命令,收到publish命令的节点都会执行相同的publish命令

 

通过gossip协议,cluster可以提供集群间状态同步更新、自动选举,故障转移(failover)等重要的集群功能.

2.3、Redis的hash槽

redis-cluster把所有的物理节点映射到[0-16383]个slot上,基本上采用平均分配连续分配的方式。

比如部署架构图中有5个主节点,这样在RedisCluster创建时,slot槽可按如下分配:

Redis1 0-3270, Redis2 3271-6542, Redis3 6543-9814, Redis4 9815-13087, Redis5 13088-16383

cluster负责维护节点和slot槽的对应关系 value------>slot-------->节点

当需要在Redis集群中放置一个key-value时,redis先对key使用crc16算法算出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同的节点。

2.5、RedisCluster的优点

  • 1、高性能:Redis的性能和单机版时同级别的,但是存在多个主节点,可以做负载均衡,读写分离等。
  • 2、高可用:Redis分片集群的同时,对每个节点都可以采用主从复制保障每个节点的高可用。
  • 3、故障转移,Redis也实现了一个类似Raft的方式,保证整个集群的可用性。failover故障自动转移。
  • 4、易扩展:向Redis增加,移除节点是透明的,无需停机。水平和垂直方向都非常容易扩展。
  • 5、Redis官方实现:部署RedisCluster不需要其他代理或者工具,使用Redis-Cli即可。是Redis官方开发的,与单机版几乎完全兼容。
2.6、Redis集群搭建(传统)

 

生产环境中的Redis服务器最少三台主服务器,三台从服务器。这里由于条件有限,在同一台机器上处理,也就是实现伪分布式集群。

下载Redis

下载地址:https://download.redis.io/releases/redis-5.0.0.tar.gz

安在Redis单机版

请查看<> 中,地址为:https://www.toutiao.com/article/7140648630402204168

准备工作

# 创建redis集群文件夹 mkdir -p /opt/redis/redis_cluster # 复制一份编译好的Redis命令 cp -r /opt/redis/baseredis /opt/redis/redis_cluster/redis1 # 复制配置文件 cp /opt/redis/redis-5.0.0/redis.conf /opt/redis/redis_cluster/redis1/redis.conf # 复制六份,分别修改配置文件 cp -r redis1 redis2 ; cp -r redis1 redis3 ; cp -r redis1 redis4 ; cp -r redis1 redis5 ; cp -r redis1 redis6

redis.conf配置文件修改

##################################.NETWORK ##################################### # 注释掉bind 127.0.0.1,不然ip地址只能使用127.0.0.1访问 # bind 127.0.0.1 # 端口号(需要修改) port 7001 tcp-backlog 511 timeout 0 tcp-keepalive 300 ################################# GENERAL ##################################### # 开启后台启动(修改为yes) daemonize yes supervised no # 进程ID(修改为对应端口号的pid) pidfile /var/run/redis_7001.pid loglevel notice logfile "" databases 16 always-show-logo yes ################################ SNAPSHOTTING ################################ save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbchecksum yes dbfilename dump.rdb dir ./ ################################# REPLICATION ################################# # 主从复制 # replicaof # 连接主服务器认证密码(修改为集群的密码,每台机器都一样) masterauth abcAbc123. replica-serve-stale-data yes replica-read-only yes repl-diskless-sync no repl-disable-tcp-nodelay no # By default the priority is 100. replica-priority 100 ################################## SECURITY ################################### # 认证密码(修改为集群的密码,每台机器都一样) requirepass abcAbc123. ############################# LAZY FREEING #################################### lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no ############################## AppEND ONLY MODE ############################### # 是否开启AOF(修改为yes, 开启aof) appendonly yes # 开启aof后的文件名 appendfilename "appendonly.aof" # appendfsync always appendfsync everysec # appendfsync no no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble yes ################################ LUA SCRIPTING ############################### # Set it to 0 or a negative value for unlimited execution without warnings. lua-time-limit 5000 ################################ REDIS CLUSTER ############################### # 是否开启集群(修改为yes,开启集群功能) cluster-enabled yes # 集群节点的配置文件(修改为对应端口号的集群端口号对用节点) cluster-config-file nodes-7001.conf # 节点间通信超时时间 cluster-node-timeout 15000 ################################## SLOW LOG ################################### slowlog-max-len 128 ################################ LATENCY MONITOR ############################## latency-monitor-threshold 0 ############################# EVENT NOTIFICATION ############################## notify-keyspace-events "" ############################### ADVANCED CONFIG ############################### hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 stream-node-max-bytes 4096 stream-node-max-entries 100 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 dynamic-hz yes aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes

同样的配置复制6份,修改为端口号相关的东西,比如端口号,进程ID文件,集群节点名称等。可以使用以上配置批量替换

vi编辑器中执行

# 将7001替换成7002 /g表示全部替换 :%s/7001/7002/g

启动Redis

cd /opt/redis/redis_cluster/redis1/ && ./bin/redis-server redis.conf cd /opt/redis/redis_cluster/redis2/ && ./bin/redis-server redis.conf cd /opt/redis/redis_cluster/redis3/ && ./bin/redis-server redis.conf cd /opt/redis/redis_cluster/redis4/ && ./bin/redis-server redis.conf cd /opt/redis/redis_cluster/redis5/ && ./bin/redis-server redis.conf cd /opt/redis/redis_cluster/redis6/ && ./bin/redis-server redis.conf

查看redis启动情况

[root@VM-0-5-centos redis6]# ps -ef |grep redis root 1485 1 0 22:22 ? 00:00:00 ./bin/redis-server *:7001 [cluster] root 1604 1 0 22:22 ? 00:00:00 ./bin/redis-server *:7002 [cluster] root 1606 1 0 22:22 ? 00:00:00 ./bin/redis-server *:7003 [cluster] root 1611 1 0 22:22 ? 00:00:00 ./bin/redis-server *:7004 [cluster] root 1617 1 0 22:22 ? 00:00:00 ./bin/redis-server *:7005 [cluster] root 1630 1 0 22:22 ? 00:00:00 ./bin/redis-server *:7006 [cluster]

开启防火墙

firewall-cmd --zone=public --add-port=7001/tcp --permanent firewall-cmd --zone=public --add-port=7002/tcp --permanent firewall-cmd --zone=public --add-port=7003/tcp --permanent firewall-cmd --zone=public --add-port=7004/tcp --permanent firewall-cmd --zone=public --add-port=7005/tcp --permanent firewall-cmd --zone=public --add-port=7006/tcp --permanent firewall-cmd --zone=public --add-port=17001/tcp --permanent firewall-cmd --zone=public --add-port=17002/tcp --permanent firewall-cmd --zone=public --add-port=17003/tcp --permanent firewall-cmd --zone=public --add-port=17004/tcp --permanent firewall-cmd --zone=public --add-port=17005/tcp --permanent firewall-cmd --zone=public --add-port=17006/tcp --permanent systemctl restart firewalld.service

放行云服务器的防火墙端口(7001-7006,17001-17006)于本机公网IP


 

开启集群(公网IP,指定密码)

/opt/redis/redis_cluster/redis1/bin/redis-cli --cluster create 162.14.74.11:7001 162.14.74.11:7002 162.14.74.11:7003 162.14.74.11:7004 162.14.74.11:7005 162.14.74.11:7006 --cluster-replicas 1 -a abcAbc123.

  • 1、 --cluster-replicas表示副本数量为1,六台Redis实例,复本为1,也就是三主三从。
  • 2、 -a表示指定密码

 

加入集群结果

[root@VM-0-5-centos redis6]# /opt/redis/redis_cluster/redis1/bin/redis-cli --cluster create > 162.14.74.11:7001 > 162.14.74.11:7002 > 162.14.74.11:7003 > 162.14.74.11:7004 > 162.14.74.11:7005 > 162.14.74.11:7006 > --cluster-replicas 1 -a abcAbc123. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 162.14.74.11:7004 to 162.14.74.11:7001 Adding replica 162.14.74.11:7005 to 162.14.74.11:7002 Adding replica 162.14.74.11:7006 to 162.14.74.11:7003 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: 95bb2b273537ec44879178d80fec968a4a02d151 162.14.74.11:7001 slots:[0-5460] (5461 slots) master M: 840c4b75f4603e1e1baa3189154adc9c2dc9abc7 162.14.74.11:7002 slots:[5461-10922] (5462 slots) master M: 478f97fc6bc954daadc1aeed49bd90b5b8f921a9 162.14.74.11:7003 slots:[10923-16383] (5461 slots) master S: b7cefab8fbce66cf7784b52a18c1d07fbc485e8d 162.14.74.11:7004 replicates 95bb2b273537ec44879178d80fec968a4a02d151 S: 9d6cc857350689586336dfd6d82f0fbb41dd8450 162.14.74.11:7005 replicates 840c4b75f4603e1e1baa3189154adc9c2dc9abc7 S: 830c13e63211ef4c4dc2668581895f78b45ff06c 162.14.74.11:7006 replicates 478f97fc6bc954daadc1aeed49bd90b5b8f921a9 Can I set the above configuration? (type 'yes' to accept): yes # 这里输入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 162.14.74.11:7001) M: 95bb2b273537ec44879178d80fec968a4a02d151 162.14.74.11:7001 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: 830c13e63211ef4c4dc2668581895f78b45ff06c 162.14.74.11:7006 slots: (0 slots) slave replicates 478f97fc6bc954daadc1aeed49bd90b5b8f921a9 M: 478f97fc6bc954daadc1aeed49bd90b5b8f921a9 162.14.74.11:7003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) M: 840c4b75f4603e1e1baa3189154adc9c2dc9abc7 162.14.74.11:7002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: b7cefab8fbce66cf7784b52a18c1d07fbc485e8d 162.14.74.11:7004 slots: (0 slots) slave replicates 95bb2b273537ec44879178d80fec968a4a02d151 S: 9d6cc857350689586336dfd6d82f0fbb41dd8450 162.14.74.11:7005 slots: (0 slots) slave replicates 840c4b75f4603e1e1baa3189154adc9c2dc9abc7 [OK] All nodes agree about slots configuration. # 加入集群成功 >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.

连接Redis进行测试

# 使用集群方式连接Redis /opt/redis/redis_cluster/redis1/bin/redis-cli -h 162.14.74.11 -p 7001 -c # 使用密码认证 162.14.74.11:7001> auth abcAbc123. OK # 使用cluster nodes查询集群节点 162.14.74.11:7001> cluster nodes 830c13e63211ef4c4dc2668581895f78b45ff06c 162.14.74.11:7006@17006 slave 478f97fc6bc954daadc1aeed49bd90b5b8f921a9 0 1662994023610 6 connected 95bb2b273537ec44879178d80fec968a4a02d151 10.0.0.5:7001@17001 myself,master - 0 1662994021000 1 connected 0-5460 478f97fc6bc954daadc1aeed49bd90b5b8f921a9 162.14.74.11:7003@17003 master - 0 1662994022610 3 connected 10923-16383 840c4b75f4603e1e1baa3189154adc9c2dc9abc7 162.14.74.11:7002@17002 master - 0 1662994024612 2 connected 5461-10922 b7cefab8fbce66cf7784b52a18c1d07fbc485e8d 162.14.74.11:7004@17004 slave 95bb2b273537ec44879178d80fec968a4a02d151 0 1662994022000 4 connected 9d6cc857350689586336dfd6d82f0fbb41dd8450 162.14.74.11:7005@17005 slave 840c4b75f4603e1e1baa3189154adc9c2dc9abc7 0 1662994023000 5 connectedRedis集群搭建(Docker方式)

使用Docker集群也是一样的道理。我们使用host模式(直接使用本机IP),实现集群。

准备工作

# 创建docker方式redis集群文件夹 mkdir -p /opt/redis/docker_redis_cluster # 拷贝准备好的文件到该目录 # 如果没有安装tree 先安装 yum install tree -y

使用tree查看目录结构, 只需要创建配置文件目录进行挂载修改,data和logs会自动挂载。

. ├── docker-compose.yml ├── redis1 │ └── conf │ └── redis.conf ├── redis2 │ └── conf │ └── redis.conf ├── redis3 │ └── conf │ └── redis.conf ├── redis4 │ └── conf │ └── redis.conf ├── redis5 │ └── conf │ └── redis.conf └── redis6 └── conf └── redis.conf

再使用ls -al查询隐藏文件

[root@VM-0-5-centos docker_redis_cluster]# ls -al total 40 drwxr-xr-x 8 root root 4096 Sep 14 21:29 . drwxr-xr-x 8 root root 4096 Sep 12 22:49 .. -rw-r--r-- 1 root root 2953 Sep 14 21:29 docker-compose.yml -rw-r--r-- 1 root root 24 Sep 13 21:23 .env drwxr-xr-x 3 root root 4096 Sep 14 21:31 redis1 drwxr-xr-x 3 root root 4096 Sep 14 21:31 redis2 drwxr-xr-x 3 root root 4096 Sep 14 21:31 redis3 drwxr-xr-x 3 root root 4096 Sep 14 21:31 redis4 drwxr-xr-x 3 root root 4096 Sep 14 21:31 redis5 drwxr-xr-x 3 root root 4096 Sep 14 21:31 redis6

可以看到我们准备了docker-compose.yml, .env, redis.conf三种文件。只需要修改.env的变量,就可以通过docker-compose实现一键集群了。

.env

# 服务器的IP地址 公网IP 注意开启防火墙端口 和 公网的安全组 SERVICE_IP=162.14.74.11 # 根目录 BASE_DIR=/opt/redis/docker_redis_cluster

编写docker-compose.yml

version: '2' services: redis_cluster: image: redis hostname: redis_cluster container_name: redis_cluster command: 'redis-cli --cluster create ${SERVER_IP}:7001 ${SERVER_IP}:7002 ${SERVER_IP}:7003 ${SERVER_IP}:7004 ${SERVER_IP}:7005 ${SERVER_IP}:7006 --cluster-yes --cluster-replicas 1 -a abcAbc123.' depends_on: - redis1 - redis2 - redis3 - redis4 - redis5 - redis6 privileged: true environment: TZ: Asia/Shanghai network_mode: host redis1: # 镜像名 image: redis # 重启策略 失败后总是重启 restart: always # 主机名 hostname: redis1 # 容器名 container_name: redis1 # 是否有权限 true privileged: true # 网络模式 host表示与宿主机使用相同的IP,docker中的IP发生变化 network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis1/data:/data - ${BASE_DIR}/redis1/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis1/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ] redis2: image: redis restart: always hostname: redis2 container_name: redis2 privileged: true network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis2/data:/data - ${BASE_DIR}/redis2/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis2/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ] redis3: image: redis restart: always hostname: redis3 container_name: redis3 privileged: true network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis3/data:/data - ${BASE_DIR}/redis3/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis3/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ] redis4: image: redis restart: always hostname: redis4 container_name: redis4 privileged: true network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis4/data:/data - ${BASE_DIR}/redis4/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis4/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ] redis5: image: redis restart: always hostname: redis5 container_name: redis5 privileged: true network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis5/data:/data - ${BASE_DIR}/redis5/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis5/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ] redis6: image: redis restart: always hostname: redis6 container_name: redis6 privileged: true network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis6/data:/data - ${BASE_DIR}/redis6/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis6/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ]

redis.conf配置文件

protected-mode yes port 7001 tcp-backlog 511 timeout 0 tcp-keepalive 300 daemonize no supervised no pidfile /var/run/redis_7001.pid loglevel verbose databases 16 always-show-logo yes save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir ./ masterauth abcAbc123. replica-serve-stale-data yes replica-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no replica-priority 100 requirepass abcAbc123. lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no appendonly yes appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble yes lua-time-limit 5000 cluster-enabled yes cluster-config-file nodes-7001.conf cluster-node-timeout 15000 cluster-replica-validity-factor 10 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 stream-node-max-bytes 4096 stream-node-max-entries 100 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 dynamic-hz yes aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes

上面时原始的redis.conf去除了注释后,并修改了部分属性,修改部分如下:

# 端口号 port 7001 # 进程ID保存文件 pidfile /var/run/redis_7001.pid # 向主服务器认证的密码 masterauth abcAbc123. # 服务器自己的密码 与向主服务器认证密码保持一致 requirepass abcAbc123. # 开启appendaof模式 appendonly yes # 开启集群 cluster-enabled yes # 集群节点配置文件名称 cluster-config-file nodes-7001.conf

启动集群

cd /opt/redis/docker_redis_cluster && docker-compose up -d

测试集群

# 进入容器 docker exec -it redis1 /bin/bash # 使用集群方式连接Redis redis-cli -h 162.14.74.11 -p 7001 -c # 使用密码认证 162.14.74.11:7001> auth abcAbc123. OK # 使用cluster nodes查询集群节点 162.14.74.11:7001> cluster nodes ef24f98f9d811539ed3aa7ebd58b42c02ae11c1a 162.14.74.11:7005@17005 slave d77367d7830b4503980a14e379cb06a271906787 0 1663164275000 1 connected 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 162.14.74.11:7002@17002 master - 0 1663164276864 2 connected 5461-10922 d77367d7830b4503980a14e379cb06a271906787 10.0.0.5:7001@17001 myself,master - 0 1663164274000 1 connected 0-5460 448b264edf1f697128395d8b6a656129024e2b55 162.14.74.11:7006@17006 slave 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 0 1663164275861 2 connected 841ea8438a496f02c3866fa71fc9d4271b94e946 162.14.74.11:7004@17004 slave 851c1b20f0616b60f172837e7e4bce792397d8ac 0 1663164275000 3 connected 851c1b20f0616b60f172837e7e4bce792397d8ac 162.14.74.11:7003@17003 master - 0 1663164273856 3 connected 10923-16383

使用Docker方式实现集群,其实跟手动实现集群是一样的,只是使用docker-compose一键实现了该操作而已。

2.3、Redis客户端分片与重定向

不同节点分组服务于相互无交集的分片(sharding),Redis Cluster不存在单独的proxy或配置服务器,所以需要将客户端路由到目标的分片。

Redis Cluster的客户端相比单机Redis需要具备路由语义的识别能力,且具备一定的路由缓存能力。

2.3.1、moved重定向

我们直到,Redis集群数据时存储在各个分片上的,如果我们连接某一个几点,但是数据没有在该节点上,将会被重定向到其他节点获取数据。流程图如下:

流程图


 

流程说明

 

  • 1、每个节点都共享RedisCluster中槽和集群中对应节点的关系(元数据共享)
  • 2、客户端向RedisCluster的任意节点发送命令,接收命令的节点会根据CRC16规则进行hash运算与16384取余,计算自己的槽和对应节点(计算所在槽和节点)
  • 3、如果保存数据的槽被分配给当前节点,则去槽中执行命令,并把命令执行结果返回给客户端(数据就在本节点,执行就返回)
  • 4、如果保存数据的槽不在当前节点的管理范围内,则向客户端返回moved重定向异常(不在,返回moved重定向标识)
  • 5、客户端接收到节点返回的结果,如果是moved异常,则从moved异常中获取目标节点的信息(客户端收到moved重定向)
  • 6、客户端向目标节点发送命令,获取命令执行结果(连接目标节点执行命令返回)

 

命令实现

# 在7001上面设置获取key root@redis1:/data# redis-cli -h 162.14.74.11 -p 7001 -c 162.14.74.11:7001> get name # 会经过认证 (error) NOAUTH Authentication required. 162.14.74.11:7001> auth abcAbc123. OK # 获取 162.14.74.11:7001> get name # 获取时发现在7002上,重定向到7002, 但是开启了认证 所有没有获取到 -> Redirected to slot [5798] located at 162.14.74.11:7002 (error) NOAUTH Authentication required. # 进行认证 162.14.74.11:7002> auth abcAbc123. OK # 重新获取则成功 162.14.74.11:7002> get name "zhangsan"2.3.2、ask重定向

在对集群进行扩容和缩容时,需要对槽及槽中数据进行迁移

当客户端向某个节点发送命令,节点向客户端返回moved异常,告诉客户端数据对应的槽的节点信息

如果此时正在进行集群扩展或者缩空操作,当客户端向正确的节点发送命令时,槽及槽中数据已经被迁移到别的节点了,就会返回ask,这就是ask重定向机制。

流程图


 

流程说明

 

  • 1、客户端向目标节点发送命令,目标节点中的槽已经迁移支别的节点上了,此时目标节点会返回ask重定向给客户端。
  • 2、客户端向新的节点发送Asking命令给新的节点,然后再次向新节点发送命令
  • 3、新节点执行命令,把命令执行结果返回给客户端
2.3.3、moved重定向和ask重定向的区别
  • 1、moved重定向,槽已完成了迁移工作
  • 2、ask重定向:槽正在迁移的过程中
2.4、Redis的扩容和缩容和数据迁移2.4.1、Redis扩容

 

Redis时可以实现动态扩缩容的,Redis扩容就是向Redis中添加节点

防火墙开通端口

firewall-cmd --zone=public --add-port=7007/tcp --permanent firewall-cmd --zone=public --add-port=17007/tcp --permanent systemctl restart firewalld.service

处理这个,还需要开启云服务器的安全组规则。能够telnet通才可以。

[root@VM-0-5-centos docker_redis_cluster]# telnet 162.14.74.11 7007 Trying 162.14.74.11... Connected to 162.14.74.11. Escape character is '^]'.

编写增加节点的docker-compose.yml

version: '2' services: redis7: image: redis restart: always hostname: redis7 container_name: redis7 privileged: true network_mode: host environment: TZ: Asia/Shanghai volumes: - ${BASE_DIR}/redis7/data:/data - ${BASE_DIR}/redis7/conf/redis.conf:/etc/redis/redis.conf - ${BASE_DIR}/redis7/logs:/logs command: [ "redis-server","/etc/redis/redis.conf" ]

执行文件

docker-compose -f addNode.yml up -d

加入集群

在任意一台机器执行如下命令

# 注意 如果设置了密码 加入节点时使用-a指定密码 redis-cli --cluster add-node 162.14.74.11:7007 162.14.74.11:7001 -a abcAbc123.

执行结果

Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Adding node 162.14.74.11:7007 to cluster 162.14.74.11:7001 >>> Performing Cluster Check (using node 162.14.74.11:7001) M: d77367d7830b4503980a14e379cb06a271906787 162.14.74.11:7001 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: ef24f98f9d811539ed3aa7ebd58b42c02ae11c1a 162.14.74.11:7005 slots: (0 slots) slave replicates d77367d7830b4503980a14e379cb06a271906787 M: 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 162.14.74.11:7002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: 448b264edf1f697128395d8b6a656129024e2b55 162.14.74.11:7006 slots: (0 slots) slave replicates 5a92ba294e35f1d61e8091216c59c2fa44adfb9d S: 841ea8438a496f02c3866fa71fc9d4271b94e946 162.14.74.11:7004 slots: (0 slots) slave replicates 851c1b20f0616b60f172837e7e4bce792397d8ac M: 851c1b20f0616b60f172837e7e4bce792397d8ac 162.14.74.11:7003 slots:[10923-16383] (5461 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.

同理,使用cluster nodes查看节点信息

ef24f98f9d811539ed3aa7ebd58b42c02ae11c1a 162.14.74.11:7005@17005 slave d77367d7830b4503980a14e379cb06a271906787 0 1663166631000 1 connected 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 162.14.74.11:7002@17002 master - 0 1663166631175 2 connected 5461-10922 d77367d7830b4503980a14e379cb06a271906787 10.0.0.5:7001@17001 myself,master - 0 1663166628000 1 connected 0-5460 448b264edf1f697128395d8b6a656129024e2b55 162.14.74.11:7006@17006 slave 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 0 1663166630173 2 connected d5004e076572b8fab64c8cc4473c298396b78823 162.14.74.11:7007@17007 master - 0 1663166632178 0 connected 841ea8438a496f02c3866fa71fc9d4271b94e946 162.14.74.11:7004@17004 slave 851c1b20f0616b60f172837e7e4bce792397d8ac 0 1663166631000 3 connected 851c1b20f0616b60f172837e7e4bce792397d8ac 162.14.74.11:7003@17003 master - 0 1663166630000 3 connected 10923-16383

可以看到,节点已经加入成功了,但是发现不像其他节点有一个connected 0-5460。这是因为还没有分配hash操作,节点上没有数据。

2.4.1、Redis数据迁移+重新分配hash槽

添加完主节点需要对主节点进行hash槽分配,这样该主节才可以存储数据。

Redis数据迁移原理


 

 

  • 1、向节点B发送状态变更命令,将B的对应slot状态置为importing。
  • 2、向节点A发送状态变更命令,将A对应的slot状态置为migrating。
  • 3、向A发送migrate命令,告知A将要迁移的slot对应的key迁移到B。
  • 4、当所有key迁移完成后,cluster setslot重新设置槽位。
# 指定rehash重新分槽的命令 redis-cli --cluster reshard 162.14.74.11:7007 -a abcAbc123. # 输入hash槽数量,表示要分配hash槽给目标节点 How many slots do you want to move (from 1 to 16384)? 输入3000 # 输入接收槽的结点id 也就是7007节点的id 可以在前面的cluster nodes中获取 d5004e076572b8fab64c8cc4473c298396b78823 What is the receiving node ID? d5004e076572b8fab64c8cc4473c298396b78823 # 输入源结点id,这里输入all表示从其他所有节点中都分一点槽出来 Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs. Source node #1: all # 输入yes开始移动槽到目标结点id Do you want to proceed with the proposed reshard plan (yes/no)? yes # 这些就是迁移日志 还有很多 只复制了两行 Moving slot 195 from 162.14.74.11:7001 to 162.14.74.11:7007: Moving slot 196 from 162.14.74.11:7001 to 162.14.74.11:7007:

 

使用cluster nodes查看

162.14.74.11:7001> cluster nodes ef24f98f9d811539ed3aa7ebd58b42c02ae11c1a 162.14.74.11:7005@17005 slave d77367d7830b4503980a14e379cb06a271906787 0 1663167613059 7 connected 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 162.14.74.11:7002@17002 master - 0 1663167610000 2 connected 7687-10922 # 7001有两端槽 因为之前迁移错误 迁移到7001去了 d77367d7830b4503980a14e379cb06a271906787 10.0.0.5:7001@17001 myself,master - 0 1663167612000 7 connected 1550-6961 10923-12421 448b264edf1f697128395d8b6a656129024e2b55 162.14.74.11:7006@17006 slave 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 0 1663167611053 2 connected # 这里7007有i狼三段槽,从7001-7003都迁移了部分过来 d5004e076572b8fab64c8cc4473c298396b78823 162.14.74.11:7007@17007 master - 0 1663167611000 8 connected 0-1549 6962-7686 12422-13146 841ea8438a496f02c3866fa71fc9d4271b94e946 162.14.74.11:7004@17004 slave 851c1b20f0616b60f172837e7e4bce792397d8ac 0 1663167612055 3 connected 851c1b20f0616b60f172837e7e4bce792397d8ac 162.14.74.11:7003@17003 master - 0 1663167608044 3 connected 13147-163832.4.2、Redis添加从节点

添加7008从结点,将7008作为7007的从结点

放行防火墙和云服务器安全组

firewall-cmd --zone=public --add-port=7008/tcp --permanent firewall-cmd --zone=public --add-port=17008/tcp --permanent systemctl restart firewalld.service

安全组略,需要修改腾讯云上的端口规则。

添加从节点

# redis-cli --cluster add-node 新节点的ip和端口 旧节点ip和端口 --cluster-slave --cluster-master-id 主节点id -a 密码 redis-cli --cluster add-node 162.14.74.11:7008 162.14.74.11:7007 --cluster-slave --cluster-master-id d5004e076572b8fab64c8cc4473c298396b78823 -a abcAbc123.

执行结果

root@redis1:/data# redis-cli --cluster add-node 162.14.74.11:7008 162.14.74.11:7007 --cluster-slave --cluster-master-id d5004e076572b8fab64c8cc4473c298396b78823 -a abcAbc123. Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. >>> Adding node 162.14.74.11:7008 to cluster 162.14.74.11:7007 >>> Performing Cluster Check (using node 162.14.74.11:7007) M: d5004e076572b8fab64c8cc4473c298396b78823 162.14.74.11:7007 slots:[0-1549],[6962-7686],[12422-13146] (3000 slots) master S: ef24f98f9d811539ed3aa7ebd58b42c02ae11c1a 162.14.74.11:7005 slots: (0 slots) slave replicates d77367d7830b4503980a14e379cb06a271906787 S: 841ea8438a496f02c3866fa71fc9d4271b94e946 162.14.74.11:7004 slots: (0 slots) slave replicates 851c1b20f0616b60f172837e7e4bce792397d8ac M: 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 162.14.74.11:7002 slots:[7687-10922] (3236 slots) master 1 additional replica(s) M: 851c1b20f0616b60f172837e7e4bce792397d8ac 162.14.74.11:7003 slots:[13147-16383] (3237 slots) master 1 additional replica(s) S: 448b264edf1f697128395d8b6a656129024e2b55 162.14.74.11:7006 slots: (0 slots) slave replicates 5a92ba294e35f1d61e8091216c59c2fa44adfb9d M: d77367d7830b4503980a14e379cb06a271906787 162.14.74.11:7001 slots:[1550-6961],[10923-12421] (6911 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 162.14.74.11:7008 to make it join the cluster. Waiting for the cluster to join >>> Configure node as replica of 162.14.74.11:7007. [OK] New node added correctly.

使用cluster nodes查看

64b8c5798f880927b81ca09d8fc21ab2402767a5 162.14.74.11:7008@17008 slave d5004e076572b8fab64c8cc4473c298396b78823 0 1663168579000 8 connected ef24f98f9d811539ed3aa7ebd58b42c02ae11c1a 162.14.74.11:7005@17005 slave d77367d7830b4503980a14e379cb06a271906787 0 1663168577000 7 connected 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 162.14.74.11:7002@17002 master - 0 1663168579327 2 connected 7687-10922 d77367d7830b4503980a14e379cb06a271906787 10.0.0.5:7001@17001 myself,master - 0 1663168578000 7 connected 1550-6961 10923-12421 448b264edf1f697128395d8b6a656129024e2b55 162.14.74.11:7006@17006 slave 5a92ba294e35f1d61e8091216c59c2fa44adfb9d 0 1663168580330 2 connected d5004e076572b8fab64c8cc4473c298396b78823 162.14.74.11:7007@17007 master - 0 1663168579000 8 connected 0-1549 6962-7686 12422-13146 841ea8438a496f02c3866fa71fc9d4271b94e946 162.14.74.11:7004@17004 slave 851c1b20f0616b60f172837e7e4bce792397d8ac 0 1663168579000 3 connected 851c1b20f0616b60f172837e7e4bce792397d8ac 162.14.74.11:7003@17003 master - 0 1663168578000 3 connected 13147-163832.4.3、Redis缩容

原理与扩容一样

redis-cli --cluster del-node 162.14.74.11:7008 64b8c5798f880927b81ca09d8fc21ab2402767a5 -a abcAbc123.2.5、Redis故障转移(failover)

故障检测

集群中的每个节点都会定期地(每秒)向集群中的其他节点发送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)

主从切换

从节点通过选举自动切换。

人工处理手动切换

 

  • 1、向从节点发送cluster failover命令
  • 2、从节点告知其主节点要进行手动切换(CLUSTERMSG_TYPE_MFSTART)
  • 3、主节点会阻塞所有客户端命令的执行(10s)
  • 4、从节点从主节点的ping包中获得主节点的复制偏移量
  • 5、从节点复制达到偏移量,发起选举、统计选票、赢得选举、升级为主节点并更新配置
  • 6、切换完成后,原主节点向所有客户端发送moved指令重定向到新的主节点

 

如果主节点下线了,则采用cluster failover force或cluster failover takeover进行强制切换。

副本漂移

我们知道在一主一从的情况下,如果主从同时挂了,那整个集群就挂了。

为了避免这种情况我们可以做一主多从,但这样成本就增加了。

Redis提供了一种方法叫副本漂移,这种方法既能提高集群的可靠性又不用增加太多的从机。


 

Master1宕机,则Slaver11提升为新的Master1

集群检测到新的Master1是单点的(无从机)

集群从拥有最多的从机的节点组(Master3)中,选择节点名称字母顺序最小的从机(Slaver31)漂移到单点的主从节点组(Master1)。具体流程如下(以上图为例):

 

  • 1、将Slaver31的从机记录从Master3中删除
  • 2、将Slaver31的的主机改为Master1
  • 3、在Master1中添加Slaver31为从节点
  • 4、将Slaver31的复制源改为Master1
  • 5、通过ping包将信息同步到集群的其他节点
3、小结

 

虽然Redis集群操作很简单,但是其内的原理涉及到的知识点非常全面,了解其原理,可以更好的应对线上线下的问题。



Tags:Redis集群   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Redis集群架构模式概述,引领我们穿越在数据存储的未知之旅
Redis,不仅是数据存储,更是架构的艺术。从主从到哨兵、再到Cluster,每个模式都有着独特的优势。而代理模式,则是应对大规模场景的得力助手。这是一场探险,Redis引领我们穿越在数...【详细内容】
2023-12-08  Search: Redis集群  点击:(134)  评论:(0)  加入收藏
使用Docker Compose搭建高可用Redis集群
&emsp;&emsp;如今业务系统对于缓存Redis的依赖似乎是必不可少的,我们可以在各种各样的系统中看到Redis的身影。考虑到系统运行的稳定性,Redis的应用和MySQL数据库一样需要做到...【详细内容】
2023-11-13  Search: Redis集群  点击:(193)  评论:(0)  加入收藏
Redis集群的原理是什么?
Redis 集群是一种高可用性、高性能的 Redis 解决方案,可以在多个节点之间分配数据和负载,并在某些节点出现故障时保持数据的可用性。下面将介绍 Redis 集群的概念和原理。Redi...【详细内容】
2023-05-17  Search: Redis集群  点击:(291)  评论:(0)  加入收藏
Redis集群介绍及测试思路
作者:京东零售 李磊Redis集群介绍Redis集群一般有四种方式,分别为:主从复制、哨兵模式、Cluster以及各大厂的集群方案。在3.0版本之前只支持单实例模式,3.0之后支持了集群方式。...【详细内容】
2023-04-07  Search: Redis集群  点击:(114)  评论:(0)  加入收藏
Redis集群原理与容器化部署
1、集群原理简介1.1、什么是集群?什么是分区?集群简单的说就是将同一个服务部署在不同的机器上,从而提高服务的横向扩展能力。分区就是将数据分布在多个实例(服务器)上,让每一个实...【详细内容】
2022-09-15  Search: Redis集群  点击:(519)  评论:(0)  加入收藏
Redis集群的5种使用方式,及各自优缺点对比分析
本文主要针对 Redis 常见的几种使用方式及其优缺点展开分析。一、常见使用方式Redis 的几种常见使用方式包括: Redis 单副本 Redis 多副本(主从) Redis Sentinel(哨兵) Redis...【详细内容】
2021-03-19  Search: Redis集群  点击:(453)  评论:(0)  加入收藏
Redis集群做法的难点,百万并发客户端「实战」
Redis集群详解Redis有三种集群模式,分别是:* 主从模式 * Sentinel模式 * Cluster模式三种集群模式各有特点,关于Redis介绍可以参考这里:NoSQL(二)&mdash;&mdash;RedisRedis官网:ht...【详细内容】
2020-10-17  Search: Redis集群  点击:(314)  评论:(0)  加入收藏
redis集群搭建
./redis-trib.rb create --replicas 1 172.20.10.8:7001 172.20.10.8:7002 172.20.10.8:7003 172.20.10.8:7004 172.20.10.8:7005 172.20.10.8:70061.安装ruby环境redis集群...【详细内容】
2020-08-11  Search: Redis集群  点击:(284)  评论:(0)  加入收藏
三分钟快速搭建分布式高可用的Redis集群
这里的Redis集群指的是Redis Cluster,它是Redis在3.0版本正式推出的专用集群方案,有效地解决了Redis分布式方面的需求。当单机内存、并发、流量等遇到瓶颈的时候,可以采用这种...【详细内容】
2020-07-16  Search: Redis集群  点击:(395)  评论:(0)  加入收藏
面试问Redis集群,被虐的不行了
【51CTO.com原创稿件】 上一篇我们讲解了 Redis 哨兵的工作原理,哨兵主要针对单节点故障无法自动恢复的解决方案,集群主要针对单节点容量、并发问题、线性可扩展性的解决方案...【详细内容】
2020-06-17  Search: Redis集群  点击:(337)  评论:(0)  加入收藏
▌简易百科推荐
16个Redis常见使用场景总结
来源:blog.csdn.net/qq_39938758/article/details/105577370目录 缓存 数据共享分布式 分布式锁 全局ID 计数器 限流 位统计 购物车 用户消息时间线timeline 消息...【详细内容】
2024-04-11    书圈  Tags:Redis   点击:(4)  评论:(0)  加入收藏
Linux获取Redis 性能指标方法
一、监控指标&Oslash; 性能指标:Performance&Oslash; 内存指标: Memory&Oslash; 基本活动指标:Basic activity&Oslash; 持久性指标: Persistence&Oslash; 错误指标:Error二、监...【详细内容】
2024-04-11  上海天正信息科技有限    Tags:Redis   点击:(4)  评论:(0)  加入收藏
Redis与缓存一致性问题
缓存一致性问题是在使用缓存系统,如Redis时经常遇到的问题。当数据在原始数据源(如数据库)中发生变化时,如何确保缓存中的数据与数据源保持一致,是开发者需要关注的关键问题。一...【详细内容】
2024-04-11  后端Q    Tags:Redis   点击:(3)  评论:(0)  加入收藏
Redis 不再 “开源”,未来采用 SSPLv1 和 RSALv2 许可证
Redis 官方于21日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause...【详细内容】
2024-03-27  dbaplus社群    Tags:Redis   点击:(14)  评论:(0)  加入收藏
Redis“叛逃”开源,得罪了几乎所有人
内存数据库供应商Redis近日在开源界砸下了一块“巨石”。Redis即将转向双许可模式,并实施更为严格的许可条款。官方对此次变更的公告直截了当:从Redis 7.4版本开始,Redis将在Re...【详细内容】
2024-03-25    51CTO  Tags:Redis   点击:(10)  评论:(0)  加入收藏
如何使用 Redis 实现消息队列
Redis不仅是一个强大的内存数据存储系统,它还可以用作一个高效的消息队列。消息队列是应用程序间或应用程序内部进行异步通信的一种方式,它允许数据生产者将消息放入队列中,然...【详细内容】
2024-03-22  后端Q  微信公众号  Tags:Redis   点击:(18)  评论:(0)  加入收藏
Redis不再 “开源”
Redis 官方今日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause 开...【详细内容】
2024-03-21  OSC开源社区    Tags:Redis   点击:(11)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  编程技术汇    Tags:Redis   点击:(49)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  楼仔  微信公众号  Tags:Redis   点击:(40)  评论:(0)  加入收藏
工作中Redis有哪些好用的运维工具
工作中使用 Redis 时,如果大家公司没有专业运维,可能开发人员就会面临这些运维的工作,包括 Redis 的运行状态监控,数据迁移,主从集群、切片集群的部署和运维等等。本文我就从这三...【详细内容】
2024-02-06  waynaqua    Tags:Redis   点击:(56)  评论:(0)  加入收藏
站内最新
站内热门
站内头条