将新增的6387节点(空槽号)作为master节点加入原集群
Redis—9—集群(cluster)
是什么
定义
由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis 的集群,其作用是提供在多个Redis节点间共享数据的程序集。
Redist集群是一个提供在多个Redis节点间共享数据的程序集。
Redis集群可以支持多个Master。
能干吗
-
Redis集群支持多个Master,每个Master又可以挂载多个Slave。
读写分离 支持数据的高可用 支持海量数据的读写存储操作
-
由于Cluster自带Sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能。
-
客户端与Redis的节点连接,不再需要连接集群中所有的节点,只需要任意连接集群中的一个可用节点即可。
-
槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系。
集群算法-分片-槽位slot
Redis集群的槽位slot
key通过CRC16来计算得到slot槽位进行存放
Redis集群的分片
分片是什么?
使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集群中的每个Redis实例都被认为是整个数据的一个分片。
如何找到给定key的分片?
为了找到给定key的分片,我们对key进行CRC16(key)算法处理并通过对总分片数量取模。然后使用确定性哈希函数,这意味着给定的key将多次始终映射到同一个分片,我们可以推断将来读取特点key的位置。
它俩的优势
最大优势,方便扩缩容和数据分派查找
这种结构很容易添加或者删除节点,比如如果我想新添加个节点D,我需要从节点ABC中的部分槽到D上,如果我想移除节点A,需要将A中的槽移到B或者C节点上,然后将没有任何槽的A节点从集群中移除即可,由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。
slot槽位映射,一般业界有3中解决方案
1,哈希取余分区
2,一致性哈希算法分区
是什么
为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不ok了。
能干吗
提出一致性Hash解决方案
目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。
三大步骤
算法构建一致性哈希环
服务器IP节点映射
key落到服务器的落键规则
优点:
缺点:一致性哈希算法的数据倾斜问题
一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器。
小总结
为了在节点数目发生改变时尽可能少的迁移数据将所有的存储节点排列在首尾相接的Hash环上,每个key在计算Hash后会顺时针找到临近的存储节点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。优点
加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。缺点
数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所有数据在进行存储时达不到均匀分布的效果。
3,哈希槽分区
是什么
HASH_SLOT = CRC16(key) mod 16384
-
为什么出现
为了解决一致性哈希算法的数据倾斜问题
哈希槽实质上就是一个数组,数组[0,2^14-1]形成hash slot空间。 2^14=16384
-
能干什么
-
解决均匀分配的问题,**在数据和节点之间又加入了一层,把这层成为哈希槽(slot),用于管理数据和节点之间的关系,**现在就相当于节点上方的是槽,槽里放的是数据。
槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。
-
多少个Hash槽
一个集群只能有16384个槽,编号0-16383.这些槽会分配给集群中的所有主节点,分配策略没有要求。 集群会记录节点和槽的对应关系,解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取模,余数是几key就落入相应的槽里。 Hash_SLOT = CRC16(key) mod 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。
经典面试题:为什么redis集群的最大槽数是16384个?
① 如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:65536÷8÷1024 = 8kb在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。当槽位为65536时,这块的大小是:16384÷8÷1024 = 2kb因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。② redis的集群主节点数量基本上不可能超过1000个。集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。③槽位越小,节点少的情况下,压缩比高,容易传输Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存到的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率slots/N 很高的话(N表示节点数),bitmap的压缩率就很低。如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。
Redis集群不保证强一致性,这意味着在特定的条件下,Redis集群可能会丢掉一些被系统收到的写入请求命令。(没有来得及同步就宕机)
集群环境案例步骤
1,3主3从redis集群配置
找3台真实虚拟机,各自创建 mkdir -p /myredis/cluster
新建6个独立的redis实例服务 6381 6382 在一号机器 master slave ip 192.168.137.132vim /myredis/cluster.redisCluster6381.confvim /myredis/cluster.redisCluster6382.conf6383 6384 在二号机器 master slave ip 192.168.137.135vim /myredis/cluster.redisCluster6383.confvim /myredis/cluster.redisCluster6384.conf6385 6386 在三号机器 master slave ip 192.168.137.136vim /myredis/cluster.redisCluster6385.confvim /myredis/cluster.redisCluster6386.conf启动6台redis主机实例redis-server /myredis/cluster/redisCluster6381.conf...redis-server /myredis/cluster/redisCluster6386.conf
通过redis-cli命令为6台机器构建集群关系
redis-cli -a 924721 --cluster create --cluster-replicas 1 192.168.137.132:6381 192.168.137.132:6382 192.168.137.135:6383 192.168.137.135:6384 192.168.137.136:6385 192.168.137.136:6386--cluster create 创建集群--cluster-replicas 1 表示为每个master创建一个slave节点链接进入6381作为切入点,查看并检验集群状态cluster nodes 查看集群节点
cluster info 查看某一个节点环境配置
新建6个独立的redis实例服务
通过redis-cli命令为6台机器构建集群关系
配置文件
bind 0.0.0.0 服务监听地址,用于客户端连接,默认本机地址
daemonize yes 是否以后台daemon方式运行
protected-mode no安全保护模式
port 6381 端口
logfile "/myredis/cluster/cluster6381.log" 日志文件路径
pidfile "/myredis/cluster/cluster6381.pid" pid文件路径
dir /myredis/cluster 工作目录
dbfilename dump6381.rdb 快照RDB持久化
appendonly yes 日志AOF持久化
appendfilename "appendonly6381.aof"
requirepass 924721
masterauth 924721==========================cluster-enabled yes 打开集群
cluster-config-file nodes-6381.conf 集群配置文件
cluster-node timeout 500 集群超时时间
真实情况master下边的slave不一定如图正好对应
2,3主3从redis集群读写
对比6381新增两个key,查看效果,发现有报错
为什么报错
如何解决
防止路由失效加参数-c并新增两个key
redis-cli -a 924721 -p 6381 -c
重新查看集群信息
查看某个key该属于对应的槽位值
cluster keyslot 键名称
3,主从容错切换迁移案例
主6381和从机切换,先停止主机6381,查看对应的真实从机上位
再次啥看集群信息,本次6381主6384从
发现6384主,6381从
随后,6381原来的主机回来了,不会上位。
集群不保证数据一致性100%ok,一定会有数据丢失情况。
Redis集群不保证强一致性
手动故障转移 or 节点从属调整该如何处理?
上面一换后6381、6384主从对调了,和原始设计图不一样了,该如何?
重新登录6381机器
常用命令 cluster failover
4,主从扩容案例
新建6387、6388两个服务实例配置文件+新建后启动
启动87、88两个新的节点实例,此时他们自己都是master
redis-server redisCluster6387.conf
redis-server redisCluster6388.conf
将新增的6387节点(空槽号)作为master节点加入原集群redis-cli -a 924721 --cluster add-node 192.168.137.136:6387(要加入的IP) 192.168.137.132:6381(目标集群IP)6387就是将要作为master新增节点6381就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群检查集群情况第一次redis-cli -a 924721 --cluster check 192.168.137.132:6381重新分派槽号(reshard)redis-cli -a 924721 --cluster reshard IP地址:端口号redis-cli -a 924721 --cluster reshard 192.168.137.132:6381How many slots do you want to move (from 1 to 16384)? 平均主义:16384/集群数What is the receiving node ID?(需要加入的mid)Source node #1:all(全部接收)检查集群情况第二次
为主节点6387分配从节点6388redis-cli -a 924721 --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点IDredis-cli -a 924721 --cluster add-node 192.168.137.136:6388 192.168.137.132:6381 --cluster-slave --cluster-master-id 4e5a07db4676c08902684f9d91c4f816f348fea8
检查集群情况第三次
将新增的6387节点(空槽号)作为master节点加入原集群
检查集群情况第一次
检查集群情况第二次
为什么6387是3个新的区间,以前的还是连续?
重新分配成本太高,所以前3家各自匀出来一部分,从6381、6376、6375三个旧节点分别匀出1364个坑位给新节点6387
为主节点6387分配从节点6388
检查集群情况第三次
5,主从缩容案例
目的:6387和6388下线
检查集群情况第一次,先获得从节点6388的节点ID
从集群中将4号从节点6388删除redis-cli -a 924721 --cluster del-node ip:从机端口 从机6388节点IDredis-cli -a 924721 --cluster del-node 192.168.137.136:6388 ed0100414fd152170e4d4701c025c6feb581be17将6387的槽号清空,重新分配,本例将清出来的槽号都给6381redis-cli -a 924721 --cluster reshard 192.168.137.132:6381检查集群情况第二次4096个槽位都指给6381,它变成了8192个槽位,相当于全部都给6381了,不然要输入3次,一锅端将6387删除redis-cli -a 924721 --cluster del-node 192.168.137.136:6387 4e5a07db4676c08902684f9d91c4f816f348fea8检查集群情况第三次,6387/6388被彻底去除
从集群中将4号从节点6388删除
将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
例子:
本机:
检查集群情况第二次
将6387删除
集群常用命令和CRC16算法分析
不在同一个slot槽位下的多键操作支持不好,通识占位符登场
Redis集群有16384个哈希槽,每个key通过CRC16校验之后对16384取模来决定放置哪个槽。集群的每个节点负责一部分hash槽
常用命令
占位符
CRC源码浅谈
常用命令
集群是否完整才能对外提供服务
cluster-require-full-coverage
cluster countkeysinslot 槽位数字编号
ckVyV6F-1719974834141)]
集群常用命令和CRC16算法分析
不在同一个slot槽位下的多键操作支持不好,通识占位符登场
Redis集群有16384个哈希槽,每个key通过CRC16校验之后对16384取模来决定放置哪个槽。集群的每个节点负责一部分hash槽
常用命令
占位符
[外链图片转存中…(img-KPO3qqb4-1719974834141)]
[外链图片转存中…(img-dG5dqv3z-1719974834142)]
CRC源码浅谈
[外链图片转存中…(img-UJNUmDEl-1719974834142)]
常用命令
集群是否完整才能对外提供服务
cluster-require-full-coverage
[外链图片转存中…(img-CaP4fIic-1719974834143)]
cluster countkeysinslot 槽位数字编号
cluster keyslot 键名称