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

从零开始学习Redis(四):分布式缓存(Redis集群)

之前做的redis缓存(点评项目)都是单节点部署,但单点redis存在一些问题

单点redis的问题:

数据丢失问题:Redis是内存存储,服务重启可能会丢失数据

并发能力问题:单节点Redis并发能力虽不错,但无法应对高并发场景

故障恢复问题:如果Redis宕机,则服务不可用,需要一种自动的故障恢复手段

存储能力问题:Redis基于内存,单节点能存储的数据难以满足海量需求

Redis集群可以对以上问题给出解决方案:

数据丢失问题:实现Redis数据持久化,将数据持久化到磁盘

并发能力问题:搭建主从集群,实现读写分离

故障恢复问题:利用Redis哨兵,实现健康检测和自动恢复

存储能力问题:搭建分片集群,利用插槽机制实现动态扩容

以上的解决方案也是要学习的Redis的四个点:Redis持久化,Redis主从,Redis哨兵,Redis分片集群。

Redis持久化(解决数据丢失问题)

RDB持久化

RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。

快照文件称为RDB文件,默认是保存在当前运行目录,默认开启

save:redis主进程执行RDB会阻塞所有命令,适合在服务停机之前使用

bgsave:开启子进程异步执行RDB,避免主进程受到影响

save ""  :禁用RDB

RDB方式bgsave的基本流程:

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据,完成fork后子进程读取内存数据写入RDB文件,用新RDB文件替换旧的RDB文件

fork采用的是copy-on-write技术:

· 当主进程执行读操作时,访问共享内存;

· 当主进程执行写操作时,则会拷贝一份数据,执行写操作。

RDB执行时机:

save:默认服务停止时

bgsave:根据conf文件里的配置,例如save 60 1000代表60秒内至少执行1000次修改则触发RDB

RDB缺点:

RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险

fork子进程,压缩,写出RDB文件都比较耗时

AOF持久化(解决数据安全问题)

AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。

AOF默认关闭,要修改conf配置文件来开启

conf配置AOF命令记录频率:

  • appendfsync always:每执行一次写命令,立即记录到AOF,性能最差
  • appendfsync everysec:写命令执行完先放入AOF缓冲区,每隔一秒将缓冲区数据写到AOF,是默认方案,性能适中,最多丢失一秒数据
  • appendfsync no:写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘,性能最好但安全性最差

cat  appendonly.aof:查看AOF文件

因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。

Redis会在触发阈值时自动去重写AOF文件,阈值在conf文件中配置:

RDBAOF
持久化方式定时对整个内存做快照记录每一次执行的命令
数据完整性不完整,两次备份之间会丢失相对完整,取决于刷盘策略
文件大小会有压缩,文件体积小记录命令,文件体积很大
宕机恢复速度很快
数据恢复优先级低,因为数据完整性不如AOF高,因为数据完整性更高
系统资源占用高,大量CPU和内存消耗低,主要是磁盘IO资源
但AOF重写时会占用大量CPU和内存资源
使用场景可以容忍数分钟的数据丢失,追求更快的启动速度对数据安全性要求较高常见

Redis主从(解决并发能力问题)

搭建主从架构

单节点的Redis并发能力是有上限的,要进一步提高Redis的并发能力,就要搭建主从集群,实现读写分离。一个主节点master,多个从节点slave/replica

为什么使用主从集群?

因为Redis大多是读多写少的场景,读的压力较大,使用主节点执行写操作,多个从节点执行读操作,通过拆分读写请求大大提升了Redis读的并发能力。主节点把数据同步给每一个从节点保证读的结果相同

如何将B作为A的slave(从)节点?

在B节点执行命令:slaveof   A的IP   A的port

数据同步原理

主从第一次同步是全量同步

slave做数据同步,必须向master声明自己的replication id offset

Replication Id:简称replid,数据集的标记,id一致说明说同一数据集。每个master都有唯一的replid,slave会继承master节点的replid

offset:偏移量,随着记录在repl_baklog缓冲区的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。

全量同步流程:

  • slave节点请求增量同步,
  • master判断replid,发现不一致,拒绝增量同步,做全量同步
  • master将完整内存数据生成RDB,发送RDB到slave
  • slave清空本地数据,加载master的RDB
  • master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave

如果slave重启后同步,则执行增量同步

注:repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致尚未备份的数据被覆盖,则无法基于log做增量同步,只能再次全量同步。

优化Redis主从集群:

· 在master中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘I0。

· Redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘I0

· 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步

· 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力

全量同步和增量同步区别

全量同步:master将完整内存数据生成RDB,发送RDB到slave。后续命令则记录在repl_baklog,逐个发送给slave。

增量同步:slave提交自己的offset到master,master获取repl_baklog中从offset之后的命令给slave

什么时候执行全量同步?

slave节点第一次连接master节点时

· slave节点断开时间太久,repl_baklog中的offset已经被覆盖时

什么时候执行增量同步?

· slave节点断开又恢复,并且在repl_baklog中能找到offset时

slave节点宕机恢复后可找master节点同步数据,那master节点宕机怎么办

当master节点宕机的一瞬间,redis会选取一个slave成为新的master,当之前的master节点恢复后就将其变为slave节点,实现自动故障恢复,而这一动作是由Redis的哨兵机制来实现的。

Redis哨兵(解决故障恢复问题)

哨兵的作用和工作原理:

Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:

哨兵也是一个集群。

  • · 监控:Sentinel 会不断检查您的master和slave是否按预期工作
  • · 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
  • · 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端

1 那么哨兵如何监控检测服务状态呢?

Sentinel基于心跳机制检测服务状态,每隔一秒向集群的每个实例发送ping命令:

如果某Sentinel节点发现某实例未在规定时间内响应,则认为是主观下线

若超过指定数量(quorum)的Sentinel都认为该实例主观下线,则该实例客观下线。其实就是类似于投票,quorum值最好超过Sentinel实例数量的一半。

2 发现master故障后,Sentinel要在slave中选一个作为新的master,选择依据:

如果slave节点与master节点断开时间超过指定值(down-after-milliseconds*10)则会排除该slave节点,然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举。如果slave-priority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高。offset一样,slave节点的运行id越小优先级越高

3 选中了slave后,进行故障转移

sentinel给被选中的slave发送slaveof no one命令,让该节点成为master,sentinel给其他slave发送slaveof  新master的IP  新master的port,让这些slave成为新master的从节点,开始从新master同步数据,再将故障节点标记为slave,修改其配置,添加slaveof  新master的IP  新master的port,故障节点恢复后自动成为master的slave节点

RedisTemplate的哨兵模式

当redis的主从集群节点因自动故障转移而发生变化时,RedisTemplate底层利用lettuce实现了节点的感知和自动切换,及时更新连接信息。

1 在pom文件引入redis的starter依赖:

2 在配置文件中指定sentinel相关信息:


3 在启动类里配置主从读写分离

ReadFrom是配置Redis的读取策略,是一个枚举,包括:

  • MASTER:从主节点读取
  • MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
  • REPLICA:从slave(replica)节点读取
  • REPLICA_PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

Redis分片集群(解决海量存储和高并发写)

分片集群结构

主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:海量数据存储问题和高并发写的问题

使用分片集群可以解决上述问题,分片集群特征:

  • · 集群中有多个master,每个master保存不同数据
  • · 每个master都可以有多个slave节点
  • · master之间通过ping监测彼此健康状态
  • · 客户端请求可以访问集群任意节点,最终都会被转发到正确节点

散列插槽

Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到。

数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分两种情况:

  • · key中包含”0)",且“0”中至少包含1个字符,“0)”中的部分是有效部分
  • · key中不包含“0)”,整个key都是有效部分

例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

为什么要将数据与插槽绑定?

redis的节点可能被删除或宕机,若数据与节点绑定,数据就有丢失风险。但如果是将数据与插槽绑定,节点宕机时,我们可以将该节点的插槽转移到活着的节点,数据跟着插槽走,根据插槽就可以找到数据。

Redis如何判断某个key应该在哪个实例?

  1. · 将16384个插槽分配到不同的实例
  2. · 根据key的有效部分计算哈希值,对16384取余
  3. · 余数作为插槽,寻找插槽所在实例即可

如果要将同一类数据固定的保存在同一个Redis实例,我们可以让这一类数据使用相同的有效部分,例如key都以{typeld}为前缀

集群伸缩

集群(Redis Cluster)的伸缩是指通过添加节点(扩容)或移除节点(缩容)来动态调整集群的处理能力,核心是通过哈希槽(hash slot)的迁移实现数据在节点间的重新分布。

添加节点(扩容):

1. 准备新节点

新节点需配置为集群模式(cluster-enabled yes),并启动。

port 6380  # 新节点端口
cluster-enabled yes
cluster-config-file nodes-6380.conf  # 集群配置文件(自动生成)
cluster-node-timeout 15000启动新节点:redis-server redis.conf
2. 将新节点加入集群
redis-cli --cluster add-node 新节点地址 现有集群节点地址redis-cli --cluster add-node 127.0.0.1:6380 127.0.0.1:6379
3. 迁移哈希槽到新节点
语法:redis-cli --cluster reshard 集群任意节点地址redis-cli --cluster reshard 127.0.0.1:6379

执行后需交互配置:

  • 输入需迁移的槽位数量(例如迁移 1000 个槽);
  • 输入新节点的node-id(作为目标节点,接收槽位);
  • 输入源节点的node-id(指定从哪些节点迁移,输入all表示从所有主节点均衡迁移);
  • 输入yes确认迁移。

移除节点(缩容)

缩容的目标是将待移除节点的所有哈希槽迁移到其他节点,再将节点从集群中删除。

1. 迁移待移除节点的所有哈希槽
redis-cli --cluster reshard 127.0.0.1:6379

交互配置:

  • 输入待迁移的槽位数量(即待移除节点当前负责的所有槽位,可通过cluster slots查看);
  • 输入目标节点的node-id(接收槽位的其他主节点);
  • 输入待移除节点的node-id(作为源节点);
  • 输入yes确认迁移。

验证:通过cluster countkeysinslot 槽位号检查待移除节点的所有槽位是否已迁移完成(键数量为 0)。

2. 移除节点
# 语法:redis-cli --cluster del-node 集群任意节点地址 待移除节点的node-id
redis-cli --cluster del-node 127.0.0.1:6379 待移除节点的node-id

故障转移

我们已知当集群中有一个master宕机后,redis会自动提升一个slave为新的master,但有时候因为机器老旧而需要更换新的节点,我们就会使用手动故障转移,实现无感知的机器的升级,也叫数据迁移。

利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。

数据迁移步骤:

手动的Failover支持三种不同模式:

  • · 缺省:默认的流程,如图1~6歩(建议使用)
  • · force:省略了对offset的一致性校验
  • · takeover:直接执行第5步,忽略数据一致性、忽略master状态和其它master的意见

RedisTemplate访问分片集群

RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:

1. 引入redis的starter依赖(略)

2. 配置分片集群地址

3. 配置读写分离(略)

与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:

http://www.dtcms.com/a/554791.html

相关文章:

  • oj进制的回文数(存在些许疑惑
  • 为什么不推荐免费建站网站怎么申请微信认证
  • 2025.10.31写题
  • 兰州酒店网站建设招聘网58同城求职信息
  • 如何找招标信息
  • 北京盛赛车网站开发嘉定php网站开发培训
  • 爬虫数据去重:BloomFilter算法实现指南
  • 怎样自己做一个网站学校网站建设市场
  • 网站地图开发一站式做网站开发
  • JavaScript基础提升【三】
  • 百度网盘 做网站图床美区能和国区家庭共享吗
  • 基于3DGIS+BIM的智慧园区运维平台价值分享
  • atsec出席2025 PCI社区会议
  • 白云区建材网站建设推广wordpress换了ip
  • 旌阳区黄河开发建设网站建设工程施工司法解释
  • 外包网站设计哪家好怎样建立网站平台
  • 海南省工程建设定额网站网站建设的SOWT分析
  • 第1讲:彻底解决C++中资源泄露
  • CentOS 7上运行C程序
  • 网站建设有什么证.net程序员网站开发工程师
  • 安信可(Ai-Thinker)WiFi系列模块全解析:选型指南与应用洞察
  • 科技建站网站源码黄金网站app视频播放画质选择
  • 品牌网站设计图片企业软件管家
  • NetSuite 如何删除未生成的Memorized Transaction?
  • 秦皇岛优化网站排名邹城网站建设
  • 扁平化网站导航ui模板电子商务网站建设与管理理解
  • 有什么网站可以做毕业影像页面设计源代码
  • 金泽通 打造数字金融与商业融合新模式
  • 【算法专题训练】29、树的深度优先遍历
  • Rust + WebAssembly 实现多人在线共享白板:从设计到性能验证