文章目录
- 1. 概述
- 2. Redis 安装及配置
- 3. key 常用命令及10 大数据类型
- 4. Redis 持久化
- 4.1 RDB (Redis Database)
- 4.2 AOF(Append Only File)
- 4.3 RDB-AOF混合持久化
- 4.4 纯缓存模式
- 5. Redis 事务
- 6. Redis管道
- 7. Redis 主从复制(replica)
- 8. Redis 哨兵(sentinel)
- 9. Redis 集群(cluster)
- 9.1 集群算法-分片-槽位 slot
- 9.2 为什么 Redis 集群的最大槽数是16384个?
- 9.3 集群环境配置
- 9.4 集群的使用
- 9.5 主从扩容
- 9.6 主从缩容
- 10. SpringBoot集成Redis
1. 概述
Redis :Remote Dictionary Server(远程字典服务)是完全开源的,使用ANSIC语言编写遵守BSD协议,是一个高性能的Key-Value数据库提供了丰富的数据结构,例如String、Hash、List、Set、SortedSet等等。数据是存在内存中的,同时Redis支持事务、持久化、LUA脚本、发布/订阅、缓存淘汰、流技术等多种功能特性提供了主从模式、Redis Sentinel和Redis Cluster集群架构方案
版本号命名规则:版本号第二位如果是偶数,才为稳定版本 如2.6、2.8、3.0、3.2
2. Redis 安装及配置
安装前需确保具备 gcc 编译环境,gcc -v
,如找不到命令,则可通过 yum -y install gcc-c++
安装 gcc 环境
- 官网下载:https://redis.io/download/
- 解压:
/opt
目录解压tar -zxvf redis-7.2.3.tar.gz
- 编译安装:进入
/opt/redis-7.2.3
目录,执行make && make install
- 默认安装目录查看:
/usr/local/bin
,该路径类似于 windows 系统中的C:\Program Files
该路径下查看有redis-benchmark
:性能测试工具,服务器运行后运行该命令可以查看性能情况redis-check-aof
:用于修复有问题的 aof 文件redis-check-rdb
:用于修复有问题的 rdb 文件redis-cli
:客户端,操作路口redis-sentinel
:redis 集群使用redis-server
:redis 服务器启动命令
- 修改配置文件:
/opt/redis-7.2.3/redis.conf
建议先备份,本人复制了一份到/root/myopt/redis.conf
修改以下四个配置daemonize
:改为yes
,让 redis 以后台程序运行protected-mode
:改为no
,如果设置为yes,那么只允许我们在本机的回环连接,其他机器无法连接,生产建议yes
bind 127.0.0.1 -::1
:测试可注释掉该项,否则只能指定 ip 连接 redis。生产建议配置好requirepass 密码
:配置密码,在配置文件约 1045 行添加该配置
- 修改配置文件:
/etc/sysctl.conf
启用内存过度分配,增加配置vm.overcommit_memory=1
,并执行立即生效命令sysctl vm.overcommit_memory=1
- 启动服务:
redis-server /root/myopt/redis.conf
- 连接服务:
redis-cli -a 密码
,会警告不安全,可忽略(在客户端用auth 密码
登陆将不会有警告),测试连接输入ping
,收到PONG
则表示成功
关闭 redis :单实例关闭 redis-cli -a 密码 shutdown
;多实例关闭 redis-cli -a 密码 -p 6379 shutdown
卸载 redis:停止 redis 服务后,删除 /usr/local/bin
目录下与 redis 相关的文件 rm -rf /usr/local/bin/redis-*
3. key 常用命令及10 大数据类型
命令参考网址:
- 官网英文版:https://redis.io/commands/ ,最全
- 中文参考推荐:https://www.w3cschool.cn/redis/
可以使用 help command
命令来查看命令帮助,如 help keys
或者使用 help @数据类型
名来来查看对应数据类型相关的函数
key 及 db 常用命令
命令 | 描述 |
---|---|
keys * | 查看当前库所有 key,也可将 * 改成 a* 表示查看 a 开头的 key |
exists key | 判断某个 key 是否存在 |
type key | 查看 key 的类型 |
del key | 删除指定 key 数据 |
unlink key | 异步删除 key,删除大key需要用此命令 |
ttl key | 查看过期时间,单位:秒。-1 永不过期,-2 已过期 |
expire key | 设置 key 过期时间,默认单位:秒 |
select dbindex【0~15】 | 切换数据库,默认 0 |
move key dbindex【0~15】 | 将对应 key 移动到指定数据库 |
dbsize | 查看当前数据库 key 的数量 |
flushdb | 清空当前库 |
flushall | 清空所有库 |
不同数据类型对应不同增删改查命令,建议直接看英文官网(最全),通过类型过滤即可,这里主要剖析不同数据类型特点
- 字符串(String) :最常使用,最大 512 MB,常用命令:先获取再设置(
getset
),数值增减(incr
),截取(getrange
),不存在才设置(setnx
)等- 应用场景:用于缓存,自增用于点赞等,不存在才设置用于实现分布式锁
- 哈希(Hash):键值对,适合存储对象,每个 hash 可存储
2^31 -1 (约40亿)
个键值对- 应用场景:早期购物车实现,缓存对象
- 列表(List):字符串列表,最多含
2^31 -1
个元素,底层结构为双端链表- 应用场景:订阅消息
- 集合(Set):无序且成员唯一字符串集合,最多含
2^31 -1
个元素,底层结构为哈希表- 应用场景:抽奖小程序,只推送未看过的视频
- 有序集合(Sorted set):特征与集合一样,不同是元素会关联 double 类型的分数。通过分数来进行排序。分数可重复
- 应用场景:根据商品销量对商品排序显示
- 位图(Bitmap):位字符串,最大
2^32
位,节省空间,且位运算效率高- 应用场景:签到,日活统计
- 基数统计(HyperLogLog):基数统计,统计一个集合中不重复元素的个数
- 应用场景:去重统计UV(独立访客,一般为IP)
- 地理位置(Geospatial indices,GEO):附近酒店、宾馆推送
- 流(Stream):Redis版的MQ消息中间件+阻塞队列,不建议使用,同时本篇文章中也将不再讨论 Redis 的发布订阅功能,建议使用专门的MQ消息中间件
- 位域(Bitfields):了解即可,将一个字符串看作是一个由二进制位组成的数组,并能对变长位宽和任意没有字节对齐的指定整数位域进行寻址和修改
- 如:
hello
用位域存储时每个字母是用 8位组成的字节 ASCII 存储的,用位域可直接操作对应 ASCII 编码,对编码进行修改
- 如:
4. Redis 持久化
持久化即将数据持久化到硬盘上,redis 有 rdb 和 aop 两种持久化方式。如完全为了性能不做自动持久化,也可配置纯缓存模式。持久化相关配置在配置文件中 SNAPSHOTTING
模块,可根据该关键字检索。
4.1 RDB (Redis Database)
该持久化方案默认开启,在指定的时间间隔,执行数据集的时间点快照,采集时进行全量快照。最终保存的格式是 dump.rdb
文件。
- 备份触发频率:默认
save 3600 1 300 100 60 10000
,表示 3600s(1小时)内至少有1次变更触发;300s(5分钟)内至少有100次变更触发;以及 60s (1分钟)内至少有 10000 此变更触发 - 劣势:
- 可能会丢失最近一次快照之后的数据
- 内存数据的全量同步时,数据量太大会影响服务器性能
- RDB 依赖于主进程的 fork ,在更大数据集中,可能会导致服务请求的瞬间延迟。fork 的时候内存中的数据被克隆了一份,大致 2 倍的膨胀性
- 修复工具及命令:
redis-check-rdb rdb文件
- 触发备份的5种方式:
- 配置文件中配置的自动备份频率
- 手动
save
/bgsave
命令,生产禁止使用save
备份,会阻塞主进程 - 执行
flushdb
/flushall
命令,产生的是空备份文件,无意义 - 执行
shutdown
且没有设置开启 AOF 持久化 - 主从复制时,主节点自动触发
- 禁用 RDB 快照:
redis-cli config set save ""
,配置文件中也是设置save ""
- 备份目录及文件名默认配置:备份目录:
dir ./
;备份文件名:dbfilename dump.rdb
总结:
- RDB 在保存文件时父进程唯一要做的就是 fork 出一个子进程,由子进程做 IO 操作,故可以最大化 redis 性能
- 与 AOP 相比,在恢复大的数据集的时候,RDB方式会更快一些
- 存在数据丢失风险
- fork 大数据集时,fork 过程非常耗时,保存大数据集时可能会导致 redis 在毫秒级不能响应客户端请求
4.2 AOF(Append Only File)
默认不开启,该备份方案是以日志的形式来记录每个写操作,恢复重启时根据日志内容将写操作从前到后执行一次以完成数据恢复
AOF 持久化流程:
1 | Client作为命令的来源,会有多个源头以及源源不断的请求命令。 |
---|---|
2 | 在这些命令到达Redis Server 以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。 |
3 | AOF缓冲会根据AOF缓冲区同步文件的三种写回策略将命令写入磁盘上的AOF文件。 |
4 | 随着写入AOF内容的增加为避免文件膨胀,会根据规则进行命令的合并(又称AOF重写),从而起到AOF文件压缩的目的。 |
5 | 当Redis Server 服务器重启的时候会从AOF文件载入数据。 |
- 配置文件:开启 AOF:
appendonly yes
;配置文件目录及名称dir
+appenddirname
配置写回策略:appendfsync
- Redis7会生成,BASE(只有一个),INCR(可能多个),HISTORY(该类型的AOF会被Redis自动删除),manifest(清单) 共4类文件
- 3种缓存写回策略:默认
everysec
always
:同步写回,每个写操作执行完立刻同步到磁盘everysec
:每秒写回no
:由操作系统自行决定何时从缓存写到磁盘
- 修复工具及命令:
redis-check-aof --fix aof文件
- AOF重写机制:AOF 在触发重写机制时会根据内存中数据重写 AOF 文件,生成新的 AOF 文件,只保留可恢复数据的最小指令集。两种触发机制:
- 自动触发:同时满足
auto-aof-rewrite-percentage 100
是否增长一倍和auto-aof-rewrite-min-size 64 mb
是否达到 64 MB大小 - 手动触发:客户端执行
bgrewriteaof
- 自动触发:同时满足
总结:
- AOF 是一个只进行追加的日志文件
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写
- AOF 文件有序地保存了写入操作,且 AOF 文件的内容非常容易让人读懂,方便分析
- 对于相同数据集来说,AOF 文件的体积通常大于 RDB 文件
- 根据使用的 fsync 策略,AOF 的速度可能会慢于 RDB
4.3 RDB-AOF混合持久化
RDB 和 AOF 方式是可以共存的,按是否开启混合模式有两种情况,如下:
- 开启参数:混合模式开启参数
aof-use-rdb-preamble yes
默认是开启的,不开启则将优先使用 AOF。同时必须开启 aof:appendonly yes
RDB + AOF 混合方式:这种方式会先使用 RDB 进行快照存储,然后使用 AOF 持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的 RDB 记录。这样的话,重启服务的时候会从 RDB 和 AOF 两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。在持久化方案中也推荐使用该方案。
4.4 纯缓存模式
为了追求极致性能采取的模式,同时关闭 RDB 和 AOF。
- 禁用 rdb 自动触发:配置
save ""
,禁用情况下仍然可以使用命令save
和bgsave
生成 rdb 文件 - 禁用 aof 自动触发:配置
appendonly no
,禁用情况下仍然可使用命令bgrewriteaof
生成 aof 文件
5. Redis 事务
使用事务,可以一次执行多个命令,本质是一组命令的集合,一个事务中的所有命令都会序列化,按顺序串行化执行,不会被其他命令加塞。
Redis事务特点:
- 单独的隔离操作,Redis是单线程架构,事务执行时不会再去执行其他客户端请求
- 没有隔离级别的概念,事务提交前任何指令都不会被实际执行
- 不保证事务的原子性,不保证所有命令同时成功或者同时失败
- 排它性,一个事务的命令依次执行,而不会被其它命令插入
命令 | 描述 |
---|---|
MULTI | 标记一个事务块的开始 |
DISCARD | 取消事务,放弃执行事务块内的所有命令 |
EXEC | 执行所有事务块内的命令 |
WATCH key | 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断,乐观锁定 |
UNWATCH | 取消 WATCH 命令对所有 key 的监视 |
在事务中,如果执行的语句不符合语法规则,则事务会被放弃;如果执行的语句符合语法规则,则执行会继续执行,异常也不会影响事务中其它命令的执行。
当使用 watch 监控了一个 key 时,别的客户端再修改该值,则 watch 监控处开启的事务中的语句将都不会执行,且事务执行时会返回 (nil)
,exec
后,所有监控锁都会被取消掉。
6. Redis管道
Pipeline 是批处理命令变种优化措施,类似于 Redis 的原生批处理命令( mget
和 mset
),主要用于解决频繁命令往返造成的性能瓶颈。
使用:首先编写 Redis 批处理文档 cmd.txt
,如下:
set k100 v100
set k200 v200
hset k300 name haha
hset k300 age 20
hset k300 gender male
使用管道参数执行,则 cmd.txt
的命令均会在 redis 中执行:
cat cmd.txt | redis-cli -a 密码 --pipe
注意:
- 管道执行命令不具备原子性,只是会依次执行指令,执行中发生异常会继续执行后续指令
- 组装的命令不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务端也被迫回复一个队列答复,占用很多内存
7. Redis 主从复制(replica)
主从复制,就是 master 以写为主,slave 以读为主,当 master 数据变化的时候,自动将新的数据异步同步到其它 slave 数据库。
作用:读写分离,容灾恢复,数据备份,水平扩容支撑高并发
配置小结:
- 配从不配主
- 权限细节:如果 master 配置了
requirepass
参数,那么 slave 就要配置masterauth
来设置连接主库的密码 - 4个基本操作命令或配置:
info replication
:查看节点的主从关系和配置信息relicaof 主库IP 主库端口
:主从复制,配置文件,在从库服务器上配置主库slaveof 主库IP 主库端口
:改换门庭,运行期间,执行该命令,建立从库关系,如果已经是从库,则会停止和原数据的同步关系slaveof no one
:自立为王
个人利用虚拟机进行主从复制配置步骤,配置前需确保主从机之间网络互通,且主机防火墙已放行对应端口:
- 开启
daemonize yes
- 注释
bind 127.0.0.1
- 关闭保护模式
protected-mode no
- 指定端口
port 6379
,默认就是 6379 - rdb 目录:
dir ./
默认值,可修改。还有文件名:dbfilename dump.rdb
- pid 文件名字,
pidfile /var/run/redis_6379.pid
- log 文件名字,
logfile "/root/myopt/redis7/6379redis.log"
- 主库配置密码:
requirepass 密码
- aof 配置【可选】:
appendonly yes
开启 aof ,文件名:appendfilename "appendonly.aof"
- 从机配置主机的 IP 及通行密码:
replicaof 主库IP 主库端口
,masterauth 主机密码
主机不需要配置slaveof 主库IP 端口
:使用该命令也可临时配置,重启后关系会断开
薪火相传:slave 也可以作为其他 slave 的 master,减轻主 master 的压力
复制原理及工作流程:
- slave 启动,同步初清:slave 启动成功连接到 master 会发送一个 sync 命令,首次连接会进行一次完全同步(全量复制),slave 自身数据会被覆盖清除
- 首次连接,全量复制:master 节点收到 sync 命令,会触发 rdb,同时继续收集修改数据集命令缓存起来,待持久化完成,将 rdb 文件和缓存命令一起发送
- 心跳持续,保持通信:
repl-ping-replica-period 10
- 进入平稳,增量复制:master 继续将所有收集到的修改命令,自动传给 slave,完成同步
- 从机下线,重连续传:master会检查backlog里面的offset,master和slave都会保存一个复制的offset还有一个masterId,offset是保存在backlog中的。master只会把已经复制的offset后面的数据复制给Slave,类似断点续传
缺点:后面的 Redis 哨兵及集群将会针对这两个痛点进行一定优化
- 复制延时,信号衰减:所有写操作都在 master 上操作,然后同步更新到 slave,存在延迟,从机越多,问题越严重
- master 挂了不会自动重选 master ,必须人工干预
8. Redis 哨兵(sentinel)
俗称无人值守运维,可以解决主从复制中 master 挂了必须人工干预的痛点。哨兵监控 master 主机是否故障,如果故障了重新选举 master 继续对外服务。
特点:
- 主从监控:监控主从 redis 库运行是否正常
- 消息通知:哨兵可以将故障转移的结果发送给客户端
- 故障转移:如果 master 异常,则会进行主从切换,将其中一个 slave 作为新的 master
- 配置中心:客户端通过连接哨兵来获得当前 redis 服务的主节点地址
哨兵配置:从安装时解压的解压目录中,复制 sentinel.conf
文件,按以下顺序配置
bind 0.0.0.0
:服务监听目录,用于客户端连接,默认无该项配置需自行添加(本人添加到配置文件第二行),但默认是本机地址protected-mode no
:默认即关闭,关闭保护模式,允许其他 redis 访问port 26379
:配置端口,默认26379
daemonize yes
:开启后台运行,默认no
pidfile /var/run/redis-sentinel26379.pid
:pid 文件路径,默认/var/run/redis-sentinel.pid
logfile "/root/myopt/redis7/sentinel26379.log"
:配置日志目录,默认""
dir /root/myopt/redis7
:配置工作目录,默认/tmp
sentinel monitor mymaster 192.168.115.129 6379 2
:设置要监控的 master 服务器,最后一个参数是quorum
,表示最少哨兵认可的客观下线票数。默认为sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster 主机密码
:设置主机连接密码,默认无该项配置,可在# sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
该注释行下添加
其他配置:可自行视情况调整
配置 | 描述 |
---|---|
sentinel down-after-milliseconds <master-name> <milliseconds> | 指定多少毫秒之后,主节点没有应答哨兵,此时哨兵主观上认为主节点下线 |
sentinel parallel-syncs <master-name> <nums> | 表示允许并行同步的slave个数 |
sentinel failover-timeout <master-name> <milliseconds> | 故障转移的超时时间,故障转移时,如果超过设置的毫秒,表示故障转移失败 |
sentinel notification-script <master-name> <script-path> | 配置当某一事件发生时所需要执行的脚本 |
sentinel client-reconfig-script <master-name> <script-path> | 客户端重新配置主节点参数脚本 |
提供一份测试中可直接使用的 sentinel.conf
参考配置:
bind 0.0.0.0
daemonize yes
protected-mode no
port 26379
logfile "/root/myopt/redis7/sentinel26379.log"
pidfile /var/run/redis-sentinel26379.pid
dir /root/myopt/redis7/
sentinel monitor mymaster 192.168.115.129 6379 2
sentinel auth-pass mymaster 主机密码
做完以上哨兵配置后,哨兵启动命令:redis-sentinel sentinel26379.conf --sentinel
,哨兵启动后可以在 master 用 info sentinel
查看哨兵信息
哨兵运行流程:当一个主从配置的 master 失效后,sentinel 可以选举出一个新的 master 接替原 master 工作,其他从机配置自动指向新 master 并同步数据。
一般不建议 sentinel 采取1~2台,防止某一台 sentinel 无法连接到 master 导致误切换
Server closed the connection
或Broken pipe
主机失效后,从机处可能的报错,意思是对端的管道已经断开,再次执行可能就会好
- SDown(Subjectively Down) 主观下线:指单个 sentinel 实例对服务器做出的下线判断,
sentinel down-after-milliseconds <masterName> <timeout>
可配置认定失效时间,默认 30 秒 - ODown(Objectively Down) 客观下线:意思是至少有
quorum
个 sentinel 认为这个 master 有故障才会对这个master进行下线以及故障转移 - 选举兵王:当主节点被判断客观下线后,各个哨兵节点会进行协商选举兵王,由兵王进行 failover(故障迁移)
- 选举算法:Raft 算法,基本思路先到先得,即在一轮选举中,哨兵A向B发送成为领导者的申请,如果B没有同意过其他哨兵,则会同意A成为领导者
- 由兵王推动故障切换流程并选出新 master:
- 新王登基:根据规则选中某个 slave 称为新 master,节点健康的情况下按以下规则优先级从上到下选举 master
- 配置文件中
slave-priority
或者replica-priority
最高的从节点(数字越小优先级越高) - 复制偏移位置 offset 最大的从节点(相当于处理的命令最多从节点)
- 最小 Run ID 的从节点(字典顺序,ASCII码)
- 配置文件中
- 群臣俯首:未被选中的 slave 的配置文件会动态变化,master 指向新选举的 master
- Sentinel leader 对选举出的新 master 执行
slaveof no one
操作,将其提升为 master 节点 - Sentinel leader 向其它 slave 发送命令,让剩余的 slave 成为新的 master 节点的 slave
- Sentinel leader 对选举出的新 master 执行
- 旧主拜服:原 master 再次上线后成为新 master 的从节点
- Sentinel leader 会让原来的 master 降级为 slave 并恢复正常工作
- 新王登基:根据规则选中某个 slave 称为新 master,节点健康的情况下按以下规则优先级从上到下选举 master
上述 slave 切换 master 时都会执行一个同步操作,先将自身的数据清除,再同步新 master 的数据。
使用建议:
- 哨兵数量应为多个且为奇数,哨兵本身应是集群,保证高可用
- 各个哨兵配置应该一致
哨兵使用的最大优缺点:
- 优点:当 master 出现故障,可以自动切换 master,无需人工干预,解决了主从复制必须人工干预的痛点
- 缺点:仍无法解决数据丢失及 master 不可用问题,当 master 挂了后仍然存在一定时间内 master 无法使用的痛点
后面的集群,将着手解决 master 失效问题,保证高可用。
9. Redis 集群(cluster)
Redis是一个提供在多个Redis节点间共享数据的程序集,Redis集群可以支持多个 master,每个 master 又可以挂载多个 slave,故可支持读写分离,数据的高可用,以及海量数据的读写存储操作。
- 由于 Cluster 自带 sentinel 的故障转移机制,内置了高可用的支持,无需再使用哨兵功能
- 客户端与 Redis 的节点连接无需连接集群所有的节点,只需要任意连接集群中一个可用节点即可
- 槽位 slot 负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系,即集群中每个主节点负责一部分槽位
特别注意:Redis 集群不保证强一致性,在特定条件下,Redis 集群可能会丢掉一些被系统收到的写入命令
9.1 集群算法-分片-槽位 slot
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384(2^14) 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定槽位。集群的每个节点负责一部分槽位。比如集群有3个节点,那么如下:
分片:集群中的每个Redis实例都被认为是整个数据的一个分片。使用确定性哈希函数,这意味着给定的key将多次始终映射到同一个分片
- 优势:这种结构最大的优势是方便扩缩容和数据分派查找。当要添加节点时,将所有旧节点的部分槽位分配到新节点上;当要删除节点时,将待删除节点的槽位分配给不删除节点,分配后再移除待删节点。这样无论添加和修改都不会造成集群不可用的状态。
- slot槽位映射业界一般有3种解决方案:Redis采用的是按哈希槽分区的方式
- 哈希取模分区:
hash(key) % 3
,增删节点会导致取模公式变化,会导致hash取模数据全部重新洗牌 - 一致性哈希算法分区:该方案增删节点都可以,但是在节点少的时候容易因为节点分布不均匀而造成数据倾斜问题
- 构建一致性哈希环,路径 [0, 2^32-1] 首尾相连,
- 通过 hash(节点ip) 算出节点在环上的位置,节点逆时针区域到另一个节点的路径归对应节点管理
- hash(key) 计算落键规则,落键位置顺时针找到的第一个节点将存储该键值对
- 哈希槽分区:
HashSlot = CRC16(key) mod 16384
,按槽分配,使得节点可均匀持有相同的槽位数,这即满足方便增删节点,又解决了数据倾斜问题
- 哈希取模分区:
9.2 为什么 Redis 集群的最大槽数是16384个?
首先,CRC16产生的 hash 值是 16 bit 即 2^16=65535 个值,有更大的65535为什么不用,而选择2^14=16384?
- 如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。
在消息头中最占空间的是 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的压缩率就很低
9.3 集群环境配置
首先,模板配置文件即最初解压目录中的 redis.conf
,配置模块为 REDIS CLUSTER
,根据该内容搜索即可直接到配置文件对应模块,重点要求配置的有
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
这里提供一份测试用的完整的配置文件
bind 0.0.0.0
daemonize yes
protected-mode no
port 6379
logfile "/root/myopt/redis7/cluster/cluster6379.log"
pidfile /root/myopt/redis7/cluster/cluster6379.pid
dir /root/myopt/redis7/cluster
dbfilename dump6379.rdb
appendonly yes
appendfilename "appendonly6379.aof"
requirepass redis
masterauth redis
# 集群配置
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 5000
- 启动命令:
redis-server /root/myopt/redis7/cluster/redisCluster6379.conf
- 构建集群关系命令:
redis-cli -a redis --cluster create --cluster-replicas 1 192.168.115.129:6379 192.168.115.129:6380 192.168.115.130:6379 192.168.115.130:6380 192.168.115.131:6379 192.168.115.131:6380
- 报错:
Could not connect to Redis at 192.168.115.130:6379: No route to host
可尝试关闭防火墙(systemctl stop firewalld
)再执行
- 报错:
- 链接一个节点,并检验集群状态:
redis-cli -a redis -p 6379
- 查看节点及集群情况:
info replication
,cluster info
,cluster nodes
- 查看节点及集群情况:
当主机宕机时,从机便会上位成为主机(新主登基),且原主机恢复后将会成为新主机的从机(旧主拜服)。
9.4 集群的使用
Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放在哪个槽,集群中的每个节点负责一部分的hash槽。
- 集群读写:集群的读写都是按槽位的范围区间来分配的,所有当只连接其中一个节点时将无法访问或设置全部键值对,而登陆是增加
-c
参数,则是以连接集群的方式连接,当操作不是本机管理的键值对就会自动转发路由进行操作,这样就可以对全部键值对进行管理,示例命令:redis-cli -a redis -c
- 查看 key 所属槽位:
cluster keysolt key
- 查看 key 所属槽位:
- 集群不保证数据的强一致性,特定条件下可能会丢掉一些被系统受到的写入命令
- 节点从属关系调整:新主登基,旧主拜服后如何还原从属关系:登陆旧主机器执行手动故障转移命令
cluster failover
- 不同槽位批量设置:不在同一槽位的键值对无法使用批量命令(如 mset / mget )设置,可通过
{}
来定义同一组的概念,同组内容将被放在同一槽位中- 使用示例:
mset k1{x} 11 k2{x} 22 k3{x} 33
和mget k1{x} k2{x} k3{x}
- 使用示例:
- 集群完整服务提供设置:
cluster-require-full-coverage
默认yes
,即需要集群完整方可对外提供服务,如要求不完整集群也可提供服务可配置为no
- 常用命令:
cluster countkeysinslot 槽位数字编号
:查看槽位占用情况。1表示被占用,0表示未占用cluster keyslot key
:查看键应占槽位号redis-cli -a 密码 --raw
:--raw
看 redis 中存储的中文将不再乱码
9.5 主从扩容
- 新增节点到集群命令:
redis-cli -a 密码 --cluster add-node 待加入节点IP:端口 集群中节点IP:端口
,后者相当于入群申请的介绍人 - 首次检查:
redis-cli -a 密码 --cluster check 新加入节点IP:端口
,新加入节点暂未分配槽位 - 槽位分配:
redis-cli -a 密码 --cluster reshard 新加入节点IP:端口
,需填写新节点将管理槽位数,ID以及可供分配的槽位(一般填all
即可) - 再次检查:
redis-cli -a 密码 --cluster check 新加入节点IP:端口
,新加入节点将被分配不连续的多段槽位 - 添加从节点:
redis-cli -a 密码 --cluster add-node 新slave的ip:端口 集群中主机IP:端口 --cluster-slave --cluster-master-id 主机节点ID
- 三次检查:
redis-cli -a 密码 --cluster check 主机IP:端口
,确认对应主机 slave 数增加,从节点成功加入
9.6 主从缩容
- 获取从节点ID:
redis-cli -a 密码 --cluster check 从节点IP:端口
- 删除从节点:
redis-cli -a 密码 --cluster del-node 从节点IP:端口 从节点ID
- 清空主节点槽位,指定接收主节点:
redis-cli -a 密码 --cluster reshard 待删主节点IP:端口
- 需要指定需要移除的槽位数,以及接收槽位的主机ID,
Source node
填待删除主机IP,后填Done
- 需要指定需要移除的槽位数,以及接收槽位的主机ID,
- 检查槽位分配情况:
redis-cli -a 密码 --cluster check 待删主节点IP:端口
,如待删节点槽位未清0,则仍需继续执行第3步 - 删除主节点:
redis-cli -a 密码 --cluster del-node 待删主节点IP:端口 待删节点ID
- 最后检查:
redis-cli -a 密码 --cluster check 某个主机IP:端口
,检查对应节点是否已被删除
10. SpringBoot集成Redis
这里使用的是 SpringBoot3,SpringBoot2中配置稍有不同,但这里不介绍,请自行了解。
- Jedis:Jedis Client 是Redis 官网推荐的一个面向 Java 端的库文件
- Lettuce:是一个 Redis 的 Java 驱动包,相等于 Jedis 的升级版,底层使用的是 Netty ,可以保证有多个线程需连接 Redis 服务器时只创建一个 Letture 连接
- RedisTemplate:集成了 Lettuce,是上面的进一步封装,推荐使用
Redis单机版,RedisTemplate配置及使用步骤:
-
在SpringBoot项目中导入依赖及添加配置
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
spring:data:redis:host: 192.168.115.129password: redis
-
配置 RedisTemplate ,配置后可以解决一系列序列化问题
@Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate; }
-
测试
@SpringBootTest(classes = SpringBootApplicationMain.class) public class MainTest {@Autowired private RedisTemplate redisTemplate;@Testpublic void test1() {System.out.println(redisTemplate.opsForValue().get("a"));redisTemplate.opsForValue().set("c", "非常好");System.out.println(redisTemplate.opsForValue().get("c"));} }
Redis集群版,相比单机版只需修改配置文件:
spring:data:redis:lettuce:cluster:refresh:# 支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭adaptive: true# 定时刷新period: 2000cluster:nodes: 192.168.115.129:6379,192.168.115.129:6380,192.168.115.131:6379,192.168.115.131:6380,192.168.115.132:6379,192.168.115.132:6380password: redis