目录
Redis有三种集群模式,分别是:
-
主从模式
-
Sentinel模式
-
Cluster模式
Cluster模式介绍:
1.问题
容量不够,redis如何进行扩容?
并发写操作, redis如何分摊?
另外,主从模式,薪火相传模式,主机宕机,导致ip地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息。
之前通过代理主机来解决,但是redis3.0中提供了解决方案。就是无中心化集群配置。
2.什么是集群
sentinel模式基本可以满足一般生产的需求,具备高可用性。但是当数据量过大到一台服务器存放不下的情况时,主从模式或sentinel模式就不能满足需求了,这个时候需要对存储的数据进行分片,将数据存储到多个Redis实例中。cluster模式的出现就是为了解决单机Redis容量有限的问题,将Redis的数据根据一定的规则分配到多台机器。
Redis 集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。
Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能,所以如果配置两个副本三个分片的话,就需要六个Redis实例。因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容。
使用集群,只需要将redis配置文件中的cluster-enable配置打开即可。集群中至少需要三个主数据库才能正常运行,新增节点非常方便。
Redis Cluster是一种服务端Sharding技术,3.0版本开始正式提供。Redis Cluster并没有使用一致性hash,而是采用slot(槽)的概念,一共分成16384个槽。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。
哈希slot虚拟槽分区:
Redis 既没有用哈希取模,也没有用一致性哈希,而是用虚拟槽来实现的。
Redis 创建了 16384 个槽(slot),每个节点负责一定区间的 slot。
比如 Node1 负 责 0-5460,Node2 负责 5461-10922,Node3 负责 10923-16383。
方案说明:
redis cluster 解决了分片的问题,支持横向纵向的扩展,所以在高并发的情况是很稳定的
(1)自动将数据进行分片,每个master上放一部分数据
- 通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,默认分配了16384 个槽位
- 每份数据分片会存储在多个互为主从的多节点上
- 数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)
- 同一分片多个节点间的数据不保持一致性
- 读取数据时,当客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点
- 扩容时时需要需要把旧节点的数据迁移一部分到新节点
在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是 加1w 的端口号,比如 16379。
16379 端口号是用来进行节点间通信的,也就是 cluster bus 的东西,cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。cluster bus 用了另外一种二进制的协议,gossip 协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。
节点间的内部通信机制:
基本通信原理:
集群元数据的维护有两种方式:集中式、Gossip 协议。redis cluster 节点间采用 gossip 协议进行通信。
分布式寻址算法:
- hash 算法(大量缓存重建)
- 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡)
- redis cluster 的 hash slot 算法
优点:
- 无中心架构,支持动态扩容,对业务透明
- 具备Sentinel的监控和自动Failover(故障转移)能力
- 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- 高性能,客户端直连redis服务,免去了proxy代理的损耗
缺点:
- 运维也很复杂,数据迁移需要人工干预
- 只能使用0号数据库
- 不支持批量操作(pipeline管道操作)
- 分布式逻辑和存储模块耦合等
搭建集群:
1.删除持久化数据:将rdb,aof文件都删除掉。
cd /usr/local/bin
rm -rf dump*
rm -rf *.aof
2.接下来制作6个实例,6379,6380,6381,6389,6390,6391
先找一个基本的配置文件进行修改,如redis6379.conf,删除掉其他两个原先的配置文件,redis6379.conf修改内容如下3和4:
rm -rf redis6380.conf redis6381.conf
vim redis6379.conf
修改内容如下3和4:
3.配置基本信息(在redis.conf中修改):
开启daemonize yes
Pid文件名字
指定端口
Log文件名字
Dump.rdb名字
Appendonly 关掉或者换名字
4.redis cluster配置修改三处(在redis.conf中修改):
cluster-enabled yes #打开集群模式
cluster-config-file nodes-6379.conf #设定节点配置文件名
cluster-node-timeout 15000 #设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换。
1.cluster-enabled <yes/no> 开启redis cluster集群
2.这是指定一个文件,供cluster模式下的redis实例将集群状态保存在那里,
包括集群中其他机器的信息,比如节点的上线和下限,故障转移,不是我们
去维护的,给它指定一个文件,让redis自己去维护的:
cluster-config-file <filename>
3.节点存活超时时长,超过:一定时长,认为节点宕机,
master宕机的话就会触发主备切换,slave宕机就不会提供服务:
cluster-node-timeout <milliseconds>
最终样子:
5.修改好redis6379.conf文件,拷贝多个redis.conf文件:
cp redis6379.conf redis6380.conf
cp redis6379.conf redis6381.conf
cp redis6379.conf redis6389.conf
cp redis6379.conf redis6390.conf
cp redis6379.conf redis6391.conf
ll #查看文件
6.使用查找替换修改另外5个文件:修改的对应的端口号等
例如:修改redis6380.conf:
vim redis6380.conf
:%s/6379/6380 回车即可,这样就将6379替换成6380了
同样修改vim redis6381.conf 等
vim redis6389.conf
vim redis6390.conf
vim redis6391.conf
7.启动6个redis服务:
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf
redis-server redis6389.conf
redis-server redis6390.conf
redis-server redis6391.conf
ps -ef|grep redis
ll
8.将六个节点合成一个集群:
组合之前,请确保所有redis实例启动后,nodes-xxxx.conf文件都生成正常。
合体:进入到redis6.2.6的src目录下:
cd /opt/redis-6.2.1/src:(这里找到我们自己本机的redis的安装路径)
此处不要用127.0.0.1, 请用真实IP地址
–replicas 1 采用最简单的方式配置集群,一台主机,一台从机,正好三组。
cd /usr/src/redis-6.2.6/src
ls
以下都是要执行的命令: (通过ifconfig 查看自己本机ip )
redis-cli --cluster create --cluster-replicas 1 192.168.211.210:6379 192.168.211.210:6380 192.168.211.210:6381 192.168.211.210:6389 192.168.211.210:6390 192.168.211.210:6391
集群的方式登录:
9. -c 采用集群策略连接,设置数据会自动切换到相应的写主机:
通过 cluster nodes 命令查看集群信息:
在当前src目录下执行:
redis-cli -c -p 6379
cluster nodes
redis cluster 如何分配这六个节点:
一个集群至少要有三个主节点。
选项 --cluster-replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。
分配原则尽量保证每个主数据库运行在不同的IP地址,每个从库和主库不在一个IP地址上。
12.什么是slots:
Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。
1.Redis集群最大节点个数是多少–>16384个
2.Redis集群如何选择数据库–>Redis集群目前无法做数据库选择,默认在0数据库。
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个,
集群使用公式CRC16(key) % 16384来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:
- 节点 A 负责处理 0 号至 5460 号插槽。
- 节点 B 负责处理 5461 号至 10922 号插槽。
- 节点 C 负责处理 10923 号至 16383 号插槽。
举例说明插槽:
在集群中录入值:
在redis-cli每次录入、查询键值,redis都会计算出该key应该送往的插槽,如果不是该客户端对应服务器的插槽,redis会报错,并告知应前往的redis实例地址和端口。
redis-cli客户端提供了–c 参数实现自动重定向。
如 redis-cli -c –p 6379 登入后,再录入、查询键值对可以自动重定向。
不在一个slot下的键值,是不能使用mget,mset等多键操作。
一次性插入多个值:需要设置组名{}:
可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去:
查询集群中的值:
CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。
cluster keyslot k1 #当前key所在的插槽位置
cluster countkeysinslot 插槽位置 # 计算当前插槽位置的key数量
cluster getkeysinslot 插槽位置 要返回的key的数量 #列举指定插槽位置的指定数量的key
只能查看自己插槽中的值,看不到其他主机插槽中的值的;
redis集群故障恢复:
情况1:
当某一个主机挂掉后,其相应的从机成为新主机,而原先主机上线后会变成从机的:
情况2:看配置文件分两种情况:
配置信息 : cluster-require-full-coverage no
15.Redis 集群提供了以下好处:
- 实现扩容
- 分摊压力
- 无中心配置相对简单
16.Redis 集群的不足:
- 多键操作是不被支持的
- 多键的Redis事务是不被支持的。lua脚本不被支持
- 由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至redis cluster,需要整体迁移而不是逐步过渡,复杂度较大。
生产环境中的 redis 是怎么部署的?
redis cluster,10 台机器,5 台机器部署了 redis 主实例,另外 5 台机器部署了 redis 的从实例,每个主实例挂了一个从实例,5 个节点对外提供读写服务,每个节点的读写高峰qps可能可以达到每秒 5 万,5 台机器最多是 25 万读写请求/s。
机器是什么配置?32G 内存+ 8 核 CPU + 1T 磁盘,但是分配给 redis 进程的是10g内存,一般线上生产环境,redis 的内存尽量不要超过 10g,超过 10g 可能会有问题。
5 台机器对外提供读写,一共有 50g 内存。
因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis 从实例会自动变成主实例继续提供读写服务。
你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是 10kb。100 条数据是 1mb,10 万条数据是 1g。常驻内存的是 200 万条商品数据,占用内存是 20g,仅仅不到总内存的 50%。目前高峰期每秒就是 3500 左右的请求量。
其实大型的公司,会有基础架构的 team 负责缓存集群的运维。
问题:新增或下线了 Master 节点,数据怎么迁移(数据迁移)
redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot
redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot
hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去
移动hash slot的成本是非常低的.
客户端的api,可以对指定的数据,让他们走同一个hash slot,通过hash tag来实现
所以,redis cluster是通过hash slot去找数据,而不是通过redis去找数据,当有一个主节点挂了,redis cluster也会用最快得速度把该主节点上面得hash slot分配到其他主节点去,这样客户端通过hash slot来找数据得时候,依然能找到数据.
数据迁移:
因为 key 和 slot 的关系是永远不会变的,当新增了节点的时候,需要把原有的 slot
分配给新的节点负责,并且把相关的数据迁移过来。
添加新节点(新增一个 7297):
redis-cli --cluster add-node 127.0.0.1:7291 127.0.0.1:7297
新增的节点没有哈希槽,不能分布数据,在原来的任意一个节点上执行:
redis-cli --cluster reshard 127.0.0.1:7291
输入需要分配的哈希槽的数量(比如 500),和哈希槽的来源节点(可以输入 all 或
者 id)。
Cluster 模式的原理:
其实现原理就是一致性 Hash。Redis Cluster 中有一个 16384 长度的槽的概念,他们的编号为 0、1、2、3 …… 16382、16383。这个槽是一个虚拟的槽,并不是真正存在的。正常工作的时候,Redis Cluster 中的每个 Master 节点都会负责一部分的槽,当有某个 key 被映射到某个 Master 负责的槽,那么这个 Master 负责为这个 key 提供服务。
至于哪个 Master 节点负责哪个槽,这是可以由用户指定的,也可以在初始化的时候自动生成(redis-trib.rb脚本)。这里值得一提的是,在 Redis Cluster 中,只有 Master 才拥有槽的所有权,如果是某个 Master 的 slave,这个slave只负责槽的使用,但是没有所有权。
3、Cluster 的分片机制?
为了使得集群能够水平扩展,首要解决的问题就是如何将整个数据集按照一定的规则分配到多个节点上。对于客户端请求的 key,根据公式 HASH_SLOT=CRC16(key) mod 16384,计算出映射到哪个分片上。而对于 CRC16 算法产生的 hash 值会有 16bit,可以产生 2^16-=65536 个值。
Redis 集群提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以下线部分节点进行缩容。可以说,槽是 Redis 集群管理数据的基本单位,集群伸缩就是槽和数据在节点之间的移动。
4、Cluster 集群的扩容流程?
当一个 Redis 新节点运行并加入现有集群后,我们需要为其迁移槽和数据。首先要为新节点指定槽的迁移计划,确保迁移后每个节点负责相似数量的槽,从而保证这些节点的数据均匀。
1)首先启动一个 Redis 节点,记为 M4。
2)使用 cluster meet 命令,让新 Redis 节点加入到集群中。新节点刚开始都是主节点状态,由于没有负责的槽,所以不能接受任何读写操作,后续给他迁移槽和填充数据。
3)对 M4 节点发送 cluster setslot { slot } importing { sourceNodeId } 命令,让目标节点准备导入槽的数据。
4)对源节点,也就是 M1,M2,M3 节点发送 cluster setslot { slot } migrating { targetNodeId } 命令,让源节点准备迁出槽的数据。
5)源节点执行 cluster getkeysinslot { slot } { count } 命令,获取 count 个属于槽 { slot } 的键,然后执行步骤 6)的操作进行迁移键值数据。
6)在源节点上执行 migrate { targetNodeIp} " " 0 { timeout } keys { key… } 命令,把获取的键通过 pipeline 机制批量迁移到目标节点,批量迁移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。
7)重复执行步骤 5)和步骤 6)直到槽下所有的键值数据迁移到目标节点。
8)向集群内所有主节点发送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配给目标节点。为了保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽执行新节点。
5、Cluster 集群收缩流程?
收缩节点就是将 Redis 节点下线,整个流程需要如下操作流程。
1)首先需要确认下线节点是否有负责的槽,如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性。
2)当下线节点不再负责槽或者本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有的节点忘记改节点后可以正常关闭。
高级开发不得不懂的Redis Cluster数据分片机制:
https://www.cnblogs.com/lowmanisbusy/p/10993748.html