242_Redis_集群_cluster架构
【摘要】 cluster集群架构
slot概念
slot迁移
cluster应用
Redis cluster
去中心化, 集群有多个节点(主从Redis)组成,每个节点存储数据或多或少, 节点之间通过特殊的二进制协议交互集群信息
在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof的功能,同时当主节点down,实现类似于sentinel的自动failover的功能
可能下线PFail & 确定下线Fail
Redis去中心化, 一个节点失联,不代表所有节点都认为它失联了, 集群需要一次协商, Redis采用Gossip协议来广播自己状态
- 一个节点发现A节点失联(PFail) 发送广播给其它节点
- 如果收到节点失联的节点数量(PFail count) 已经达到了集群大多数,标记该节点为确定下线(Fail),向整个集群广播 并进行主备切换
1 redis cluster配置修改
include /home/bigdata/redis.conf
port 6379
pidfile "/var/run/redis_6379.pid"
dbfilename "dump6379.rdb"
dir "/home/bigdata/redis_cluster"
logfile "/home/bigdata/redis_cluster/redis_err_6379.log"
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000 # 当某个节点持续时间失联,认定其故障,需要主备切换
#cluster-slave-validity-factor 10 #容错紧急程度
#假设cluster-node-timeout=5,cluster-slave-validity-factor=10,则如果从节点跟主节点失联超过50秒,此从节点不能成为主节点
cluster-migration-barrier <count>:主节点需要的最小从节点数,只有达到这个数,主节点失败时,它从节点才会进行迁移
cluster-require-full-coverage <yes/no>
#在部分key所在的节点不可用时,如果此参数设置为”yes”(默认值), 则整个集群停止接受操作;
#如果此参数设置为”no”,则集群依然为可达节点上的key提供读操作
2 启动&将节点加入集群管理
# --replicas 1 采用最简单的方式配置集群,一个节点node 包括主从
redis-cli --cluster create --cluster-replicas 1 192.168.11.101:6379 192.168.11.101:6380 192.168.11.101:6381 192.168.11.101:6389 192.168.11.101:6390 192.168.11.101:6391
redis-cli -p 7000 cluster nodes | grep master # 集群主节点状态
redis-cli -p 7000 cluster nodes | grep slave # 集群从节点状态
2.1 普通方式登录
可能直接进入读主机,存储数据时,如果发现该key所在槽位不归自己管理, 会出现MOVED重定向操作 同时报错
redis-cli –p 6379
2.2 集群策略方式登录
-c 采用集群策略连接,设置数据会自动切换到相应的写主机
redis-cli -c -p 6379
cluster nodes命令查看集群信息
3 slots
Redis集群包含16384个插槽(hash slot),数据库中的每个键都属于16384个插槽的其中一个, 集群中的每个节点负责处理一部分插槽
集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key)语句用于计算键 key 的CRC16 校验和
例 集群可以有主节点,其中:
- 节点 A 负责处理 0 号至 5460 号插槽。
- 节点 B 负责处理 5461 号至 10922 号插槽。
- 节点 C 负责处理 10923 号至 16383 号插槽
3.1迁移大致流程
Slots 迁移的单位是槽, 当slot正在迁移时, 这个槽处于中间过渡状态, migrating –> importing 可以使用工具 (redis-trib)
- 从源节点获取内容 迁移启动时候会将源节点和目标节点设置好中间过渡状态, 然后获取源节点槽位key列表, 再逐个进行迁移
- 存到目标节点 当前key dump序列化, 传到目标端restore,返回给源端 ok
- 从源节点删除内容 当源端收到ok后,删除该key
备注
目标端restore 到源端 删除key 期间, 源节点主线程处于阻塞状态,一直到key 删除, 如果迁移过程中网络异常,恢复后会提示用户继续迁移
由于过程中有阻塞, 每个key都很小, migrate指令会指向很快, 如果key很大,阻塞时间会很久, 导致源节点和目标节点卡顿.
3.2 迁移过程中的数据访问
- 1 目标端和 源端的槽位可能都存在部分key数据
- 2 客户端先访问源端, 如果key 存在,直接返回, 如果不在 两种情况 1目标端里 2 不存在,
- 3 源端无法判断这两种情况, 反给客户端 –ASK targetNodeAddr的重定向指令
- 4 客户端收到后,先去目标端执行不带任何参数的 ASKING指令
- 5 重定向循环:不带参数 是因为迁移完成前 这个slot还不属于目标端, 如果直接发槽位命令,目标端会拒绝,反一个-MOVED 源节点
- 6 AKSING 指令的目的是 告诉目标端不能置之不理,要当做自己的槽位来处理
- 7 迁移影响效率,同样指令正常情况下1个TTL , 迁移状态下 3个TTL
3.3 槽位迁移感知
如果槽位迁移过程中或者迁移完毕,客户端如何感知; 重试次数2次或者多次,Java/Python客户端 有重试参数设置
- 1 客户端保存了槽位和节点的映射关系表, 要及时更新,方可把指令正确发送到节点上
- 2 两个特殊错误error指令 MOVED & AKSING
- 3 MOVED 用来纠正槽位:如果客户端发送命令给错误节点, 节点返回MOVED+节点, 客户端刷新自己的槽位表 然后重试指令
- 4 ASKING 用来临时纠正槽位: 迁移过程中源端反 asking error携带上目标节点地址, 客户端不会刷新自己的槽位表, 后面还会去访问源端
3.4 集群变更感知
如果服务器节点变更,客户端会立即得到通知,实时刷新节点表, 两种情况
- 1 目标节点down, 客户端抛出一个 ConnectionError, 紧接着随机挑一个节点来重试,被重试节点通过MOVED 指令告知目标槽位被分配到新节点地址
- 2 手动运维改变集群信息(节点迁移,移除), 客户端请求旧节点会收到ClusterDown错误,客户端会关闭所有连接, 清空槽位表,报错,待下一条指令请求,重新尝试初始化节点信息
4 在集群中录入值
- 在redis-cli每次录入、查询键值,redis都会计算出该key应该送往的插槽,
- 如果不是该客户端对应服务器的插槽,redis会报错,并告知应前往的redis实例地址和端口
- redis-cli客户端提供了 –c 参数实现自动重定向。
- redis-cli -c –p 6379 登入后,再录入、查询键值对可以自动重定向
4.1 增
不在一个slot下的键值,不能使用mget,mset等多键操作
可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去
4.2 查
CLUSTER GETKEYSINSLOT <slot><count> 返回 count 个 slot 槽中的键
5 添加 & 删除节点
#安装集群插件
EPEL源安装ruby支持
yum install ruby rubygems -y
使用国内源
gem sources -l
gem sources -a http://mirrors.aliyun.com/rubygems/
gem sources --remove https://rubygems.org/
gem sources -l
gem install redis -v 3.3.3
增加主节点
redis-cli --cluster add-node 192.168.11.101:6382 192.168.11.101:6379
转移slot(重新分片)
redis-cli --cluster reshard 10.0.0.54:7000
添加一个从节点
redis-cli --cluster add-node --cluster-slave --cluster-master-id 4e4452fedxxxxxxxxxxx
192.168.11.101:6392 192.168.11.101:6379
# redis-trib工具方式
redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000
redis-trib.rb reshard 127.0.0.1:7000
redis-trib.rb reshard 127.0.0.1:7000 49257f251824dd815bc7f31e1118b670365e861a 127.0.0.1:7006
删除节点先slot移动走
redis-trib.rb reshard 192.168.11.101:6379 xxxxxxxxxxxxxxxxx 192.168.11.101:6382
0-1364 5461-6826 10923-12287
1365 1366 1365
删除一个节点
删除master节点之前首先要使用reshard移除master的全部slot,然后再删除当前节点
redis-trib.rb del-node 192.168.11.101:6382 xxxxxxxxx
redis-trib.rb del-node 192.168.11.101:6392 xxxxxxxxx
6 故障恢复
如果主节点下线?从节点能否自动升为主节点?注意:15秒超时
主节点恢复后,主节点回来变成从机
如果所有某一段插槽的主从节点都宕掉,默认不能对外提供服务,涉及数据完整性, 如果想继续提供服务调整 redis.conf中的参数 cluster-require-full-coverage
如果某一段插槽的主从都挂掉,而cluster-require-full-coverage 为yes ,需要集群完整性,才能对外提供服务
如果某一段插槽的主从都挂掉,而cluster-require-full-coverage 为no ,那么,该node 插槽数据全都不能使用,也无法存储。其它node可以对外提供服务
7 集群应用
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class JedisClusterDemo {
public static void main(String[] args) throws IOException {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(20);
config.setMaxIdle(10);
config.setMinIdle(5);
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort("192.168.18.131", 8001));
jedisClusterNode.add(new HostAndPort("192.168.18.131", 8004));
jedisClusterNode.add(new HostAndPort("192.168.18.132", 8002));
jedisClusterNode.add(new HostAndPort("192.168.18.132", 8005));
jedisClusterNode.add(new HostAndPort("192.168.18.133", 8003));
jedisClusterNode.add(new HostAndPort("192.168.18.133", 8006));
JedisCluster jedisCluster = null;
try {
//connectionTimeout:指的是连接一个url的连接等待时间
//soTimeout:指的是连接上一个url,获取response的返回等待时间 password = 123456
//JedisCluster j = new JedisCluster(jedisClusterNode, connectionTimeout, soTimeout, maxAttempts, password, poolConfig);
jedisCluster = new JedisCluster(jedisClusterNode, 6000, 5000, 10, "123456", config);
System.out.println(jedisCluster.set("clusterArtisan", "artisanValue"));
System.out.println(jedisCluster.get("clusterArtisan"));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedisCluster != null)
jedisCluster.close();
}
}
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)