当前位置: 首页 > article >正文

Redis7——基础篇(七)

 前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。

基础篇:

  1. Redis(一)
  2. Redis(二)
  3. Redis(三)
  4. Redis(四)
  5. Redis(五)
  6. Redis(六)

接上期内容:上期完成了Redis哨兵模式的学习。下面开始学习Redis集群(非常重点),话不多说,直接发车。


一、集群定义

(一)、什么是集群

集群是由多个相互关联的节点构成的系统架构,各节点之间通过协作机制协同运作,对外界呈现出统一的整体形态。在Redis集群体系中,每个节点均承担着部分数据的存储职责,并共同为客户端提供服务,以此达成数据的分布式存储与处理功能。


(二)、redis集群出现的背景

随着互联网应用的快速发展,数据量呈爆发式增长,单机的Redis在存储容量、读写性能和高可用性等方面逐渐难以满足需求。为了应对这些挑战,Redis 集群应运而生,它通过将数据分布在多个节点上,实现了水平扩展,大大提升了数据处理能力。


二、集群功能

  • 数据分片:将数据分散存储在多个节点上,突破单机存储容量限制。
  • 高可用性:通过节点间的复制和自动故障转移机制,确保集群在部分节点故障时仍然能正常工作。
  • 读写分离:从节点可以分担读请求,提供系统的读性能。
  • 水平扩展:可以方便地添加或删除节点,实现集群的动态伸缩。

三、集群算法

(一)、Redis集群分区是什么?

Redis集群分区是一种将数据分散存储到多个Redis节点的技术,目的是实现数据的分布式存储和处理,从而提升系统的可扩展性、性能和可用性。通过分区,Redis集群可以处理比单个 Redis 实例更大的数据集,并且可以并行处理更多的客户端请求。


(二)、Redis集群槽位是什么?

Redis集群槽位(Slot)是Redis集群中用于管理数据分布的一种逻辑概念。Redis集群共有16384 个槽位(编号从 0 到 16383),每个键在存储时会通过特定的哈希算法(CRC16)计算出对应的槽位编号,然后根据槽位的分配情况,将键值对存储到相应的节点上。


(三)、Redis集群分区-槽位映射方案

1、哈希取余分区

1.1、定义

根据数据的键值进行哈希计算,然后对节点数量取余数,根据余数将数据分配到相应的节点。这里所说的 “分区”,就是把数据按照这种哈希取余的规则,分散到不同的节点上存储,实现数据的分布式存储,每个节点就相当于一个数据分区。 

假设有3台机器构成一个集群,用户每次读写操作都是根据公式:Hash(key) % N台机器数,计算出哈希值,用来决定数据映射到那个节点上。


1.2、优劣势

优势:算法简单,易于实现,在节点数量固定时能较好地实现数据分布。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。

劣势:当节点数量发生变化(如增加或减少节点)时,大量数据需要重新计算哈希值并进行迁移,会导致数据的重新分布,影响系统性能。


1.3、小总结

哈希取余分区适用于节点数量相对稳定的场景,在节点动态变化频繁的场景下表现不佳。


2、一致性哈希算法分区

2.1、定义

将哈希值空间组织成一个虚拟的圆环,节点和数据都映射到这个圆环上。根据数据的哈希值,在圆环上顺时针查找,找到的第一个节点就是该数据的存储节点。在这个算法里,分区就是数据在虚拟圆环上对应到不同节点的存储区域,不同的节点负责存储圆环上特定区间的数据 ,从而实现数据分区。

实现一致性哈希算法分区三大步骤:

1、构建一致哈希环

一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。

它也是按照使用取模的方法,而一致性Hash算法是对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1, 0和2^32-1在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环。


2、Redis节点IP映射

将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:


3、key落键规则

当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。

如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。


2.2、优劣势

优势:①、容错性更高。假设Node C宕机,可以看到此时对象A、B、D不会受到影响。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。简单说,就是C挂了,受到影响的只是B、C之间的数据且这些数据会转移到D进行存储。

②、扩展性更好。假设需要增加一台节点NodeX,X的位置在D和C之间,那收到影响的也就是C到X之间的数据,重新把C到D的数据录入到X上即可,不会导致hash取余全部数据重新洗牌。


劣势:会产生数据倾斜问题。一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器:


2.3、小总结

一致性哈希算法虽然在节点动态变化场景下有优势,但在节点数量较少时会造成数据倾斜问题。


3、哈希槽分区

3.1、定义

Redis群将整个键值对空间划分为16384个哈希槽,每个节点负责一部分哈希槽。根据数据的键计算出哈希值,再映射到相应的哈希槽,从而确定数据存储在哪个节点。这里的 “分区” 是基于哈希槽实现的,每个哈希槽就是一个数据分区的最小单位 ,不同节点通过管理不同的哈希槽,实现对数据的分区存储。而 “槽位” 就是指这16384个哈希槽中的每一个,每个槽位都有唯一编号,用于标识和管理数据存储位置。

它的出现就是为了解决一致性哈希算法分区数据倾斜问题。解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配。


3.2、优劣势

优势:数据分布均匀,节点的增加和删除操作相对简单,通过哈希槽的迁移来实现数据的重新分布,对系统性能影响较小。

劣势:实现相对复杂,需要额外的机制来管理哈希槽和节点的映射关系。


3.3、小总结

哈希槽分区是Redis集群采用的主要分区方式,兼顾了数据分布的均匀性和集群的可扩展性。


(四)、经典面试题

Q:Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。但为什么哈希槽的数量是16384(2^14)个呢?CRC16算法产生的hash值有16bit,该算法可以产生2^16=65536个值,为啥用16384而不用65536呢

A:Redis之父的原话,why redis-cluster use 16384 slots? · Issue #2576 · redis/redis · GitHub

总结下来有三点:

①、心跳包太大了,浪费带宽。

在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb。

在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为16384时,这块的大小是: 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的压缩率也会很低。


四、集群实操

(一)、3主3从集群实操

1、3主3从集群搭建

1.1、前提说明

由于硬件关系,电脑同时启动6台虚拟机吃不消,所以,还是三台虚拟机,一台虚拟机上启动两个redis服务,效果一样滴。

①、架构图

192.168.112.129  ======》6379、6380在同一台机器上

192.168.112.129  ======》6381、6382在同一台机器上

192.168.112.129  ======》6383、6384在同一台机器上


②、前提准备

为了简洁明了,提前按照架构图创建好需要的文件和文件夹。

创建文件夹:

创建文件:

创建日志目录:


1.2、修改配置
bind 0.0.0.0
daemonize yes
protected-mode no
port 改为对应端口
logfile "/myredis/cluster/clusterLogs/cluster对应端口.log"
pidfile /myredis/cluster对应端口.pid
dir /myredis/cluster
dbfilename dump对应端口.rdb
aof-use-rdb-preamble yes
appendonly yes
appendfilename "appendonly对应端口.aof"
requirepass 登录密码
masterauth 登录密码

# 开启 Redis 集群模式
cluster-enabled yes
# 指定集群配置文件
cluster-config-file nodes-6381.conf
# 设置节点超时时间为 5 秒
cluster-node-timeout 5000

以6379为例,其他照着改就行了:


1.3、构建关系
①、启动实例
redis-server /myredis/cluster/clusterConfig/redisClusterxxx.conf

分别启动6379、6380、81、82、83、84:


②、构建集群

redis-cli -a 密码 --cluster create --cluster-replicas 1 
xxx.xxx.xxx:6379 xxx.xxx.xxx:6380 
xxx.xxx.xxx:6381 xxx.xxx.xxx:6382 
xxx.xxx.xxx:6383 xxx.xxx.xxx:6384

 参数说明:

  • --cluster create:表明要创建一个新的Redis 集群。
  • --cluster-replicas:用于指定每个主节点对应的从节点数量。
  • 1:表示为每个主节点分配 1 个从节点。

三台虚拟机都记得临时关闭防火墙


③、查看集群并检验集群状态

以6379作为切入点,查看集群:

常用命令:

info replication 查看自己节点信息


cluster info 查看集群信息


cluster nodes 查看集群节点关系


1.4、测试集群读写
①、随便设置key

Q:为啥设置k、k4报错,设置k2、k3正常?

A:不同的键名经过哈希计算后会被映射到不同的哈希槽中,而 Redis 集群里每个主节点(Master)负责一部分哈希槽。所以,当客户端连接到某个节点并尝试设置键时,如果该节点并非负责这个键对应的哈希槽,就可能会设置失败,这就导致了部分键设置成功,部分键设置失败的情况。对于redis-cli命令行工具,你可以在连接时添加-c参数开启集群模式,这样客户端会自动处理重定向,将命令转发到负责该键的正确节点上。


②、测试其他实例

其他实例也能获取成功,说明集群搭建成功,完美收官👍。


2、集群中主从故障迁移实操

如果在Redis集群中,某台Master宕机,从机是否会上位?先记住目前的节点信息:

2.1、模拟集群中的某台Master宕机

手动关闭6379:

在6381上查看集群节点信息:

slave会上位变成新的Master。


2.2、恢复架构
①、Q&A

Q1:假设当6379故障恢复后,它会以什么身份回归呢?

A1:以slave身份回归。

启动6379,恢复前:

恢复后:


Q2、虽然6379回归了,服务也正常,但是架构图跟以前不一样了啊?

A2:可以使用CLUSTER FAILOVER命令还原节点从属关系。

江山是没有那么容易易主滴。


2.3、小总结

通过上述实操,得出以下结论:

①、在Redis集群中,如果Master宕机,那么它对应的slave会迅速上位,也就是说在Redis集群中默认集成了哨兵模式。

②、Redis集群为CP模式,因此集群不保证数据一致性100%,一定会有数据丢失情况,官网也有说明。


(二)、集群扩容/容缩实操

1、集群扩容

1.1、需求说明

由于业务量的剧增,原本的3主3从的redis集群已经不足以支持现有的业务需求,决定新增redis服务来保证业务高可用。

架构图:


1.2、扩容实操
①、新启实例

由于硬件问题,所以将6385、6386放在6383那台服务器上。

此时6385、86都是Master。


②、加入集群

将6385做为集群中的新Maste加入到集群中。

redis-cli -a 密码 --cluster add-node 
xxx.xxx.xxx.xxx:xxxx xx2.xx2.xx2:xxx2

 参数说明:

  • add-node:表明要向 Redis 集群中添加一个新节点。
  • xxx.xxx.xxx.xxx:xxxx:代表新加入的节点IP和端口号。
  • xx2.xx2.xx2.xx2:xxx2:代表集群任意已经存在的IP和端口号

以6379为切入点:

6385加入集群成功。


③、第一次检查集群
redis-cli -a 密码 --cluster check xxx.xxx.xxx.xxx:xxxx

new Master6385确实成功加入集群,但是未分配槽号


④、为new Master分配槽号
redis-cli -a 密码 --cluster reshard xxx.xxx.xxx.xxx:xxxx

当在redis-cli执行次命令后,redis-cli会提示你输入以下信息:

  • 要迁移的哈希槽数量:输入想要从源节点迁移到目标节点的哈希槽数量。例如,如果想迁移 100 个哈希槽,就输入100。
  • 目标节点 ID:指定接收迁移哈希槽的目标节点的 ID(new Master ID)。
  • 源节点信息:指定要从哪些节点迁移哈希槽。可以选择具体的节点 ID,也可以输入all表示从所有节点均匀地迁移哈希槽。

待定槽位分配完毕。


⑤、第二次检查集群

槽位分配完成。


⑥、为new Master分配slave
redis-cli -a 密码 --cluster add-node 
xxx.xxx.xxx.xxx:xxxx xx2.xx2.xx2.xx2:xxx2 
--cluster-slave --cluster-master-id id

 参数说明:

  • --cluster add-node:向 Redis 集群中添加一个新节点。
  • xxx.xxx.xxx.xxx:xxxx:新节点的地址。
  • xx2.xx2.xx2.xx2:xxx2:集群中已存在节点的地址。
  • --cluster-slave:指定新添加的节点作为从节点(slave)加入集群
  • --cluster-master-id:指定新从节点要复制的主节点的 ID


⑦、第三次检查集群

自此redis集群由以前的3主3从变成了现在的4主4从,完美收官👍。


2、集群容缩

2.1、需求说明

本项目运行稳定,业务需求量增速放慢,经过评估,以前的3主3从足以支撑现有的业务需求,打算撤掉部分资源去支持其他项目。

架构图:

不一定非得撤去6385、86,也可以撤掉其他的。


2.2、缩容实操
①、第一次查看集群

确定要删除的主节点和从节点信息。


②、删除从节点
redis-cli -a 密码 --cluster del-node xxx.xxx.xxx.xxx:xxxx id

从节点删除成功。


③、还原槽位

将6385的槽位全部清空,交给6379。

后续还有一个输入项选择,输入yes即可,等待槽位清空完成。


④、第二次查看集群

6385已经由Master变成了6379的slave。(最开始6385就是由6379引荐入集群的


⑤、删除主节点
redis-cli -a 密码 --cluster del-node xxx.xxx.xxx.xxx:xxxx id

 删除6385:

6385删除成功。


⑥、第三次查看集群

自此,以前的4主4从变为了3主3从,redis集群的容缩完美收官👍。


五、集群常用操作命令

(一)、通配符

Q:如何解决在同一个slot槽位下的键值无法使用mset、mget等多键操作。

A:可以通过{}来定义同一个组的概念,使key中{}内相同内容的键值对放到一个slot槽位去,对照下图类似k1k2k3都映射为x(也可以是其他字符),自然槽位一样。


(二)、查看槽位状态

CLUSTER COUNTKEYSINSLOT 0-16383

 返回存的个数,0代表没存,其他则代表存了几个key


(三)、判断key应该存在那个槽上

CLUSTER KEYSLOT key


六、浅谈CRC16 

Q:Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,从文章在开头说到文末,但是一直没说CRC16是个什么东西?

A:不是我不说,而是我能力不足,java都还没搞明白,怎么敢去搞C的东西啊。。下图为CRC16的部分源码,有兴趣自己去研究吧。(网上cp的(●'◡'●)


七、总结 

Redis集群通过巧妙的集群算法和高效的管理机制,实现了数据的分布式存储和处理,为大规模数据处理和高并发访问提供了可靠的解决方案。在实际应用中,我们需要根据业务需求和场景选择合适的集群算法和配置参数,充分发挥 Redis 集群的优势。同时,掌握集群的搭建、操作和维护技能,能够确保集群的稳定运行和高效工作。


ps:努力到底,让持续学习成为贯穿一生的坚守。学习笔记持续更新中。。。。


http://www.kler.cn/a/560165.html

相关文章:

  • JDK安装步骤
  • 机器人学习模拟框架 robosuite 支持强化学习和模仿学习 (1) 快速入门
  • 使用 LROPoller 处理 Azure 文档分析时的常见问题及解决方案
  • 猿创征文 【高级篇】Java 进阶之JVM实战
  • MATLAB中fft函数用法
  • 数据结构与算法-图论-最短路-单源最短路的建图方式
  • 从vue底层原理上解释ref和reactive的区别
  • 【NLP 24、实践 ⑤ 计算Bert模型中的参数数量】
  • 2024年国赛高教杯数学建模D题反潜航空深弹命中概率问题解题全过程文档及程序
  • 网络安全产品
  • 数据安全_笔记系列02:国密算法(商用密码算法)详解
  • 测试工程师玩转DeepSeek之Prompt
  • 为什么java从json中获取值有数据类型,而从xml中获取值没有数据类型?
  • vue3学习4-pinia+组件通信
  • python与C系列语言的差异总结(2)
  • Apache Doris:一款高性能的实时数据仓库
  • 分班问题幼儿园分班
  • 基于 SpringBoot 的 “电影交流平台小程序” 系统的设计与实现
  • 学习笔记04——JMM内存模型
  • zookeeper的可视化界面