Redis实现高可用持久化与性能管理

news2025/3/12 20:06:32

前言

在生产环境中,为了实现Redis的高可用性,可以采用持久化、主从复制、哨兵模式和 Cluster集群的方法确保数据的持久性和可靠性。这里首先介绍一下使用持久化实现服务器的高可用。主从复制、哨兵模式和集群介绍请参考:Redis主从复制、哨兵模式和集群-CSDN博客

目录

一、Redis 高可用方法

1. 持久化

2. 主从复制

3. 哨兵

4. Cluster 集群

二、Redis 持久化

1. 概述

2. 实现方式

3. RDB 持久化

3.1 触发条件

3.2 执行流程

3.3 启动时加载 

4. AOF 持久化

4.1 开启 AOF

4.2 执行流程

4.2.1 命令追加(append)

4.2.2 文件写入(write)和文件同步(sync)

4.2.3 文件重写(rewrite) 

4.3 文件重写触发 

4.4 重写流程

4.5 启动时加载 

5. RDB 和 AOF 的优缺点 

6. RDB 和 AOF 优先级

三、内存性能管理 

1.内存使用与碎片

1.1 查看 Redis 内存使用

1.2 内存碎片率与 Redis 资源性能

1.3 内存使用率

2. 内存回收key

3. Redis 缓存的穿透、击穿与雪崩

3.1 穿透

3.2 击穿

3.3 雪崩


一、Redis 高可用方法

1. 持久化

最简单的高可用方法,主要作用是数据备份,即定期将数据保存到硬盘。

2. 主从复制

是高可用 Redis 的基础,哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。缺陷:故障恢复无法自动化;写操作无法负载均衡;存储能力受到单机的限制。

3. 哨兵

主从复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。

4. Cluster 集群

通过集群,Redis解决了写操作无法负载均衡,以及存储能力受到单机限制的问题,实现了较为完善的高可用方案。

二、Redis 持久化

1. 概述

Redis 是内存数据库,数据都是存储在内存中,为了避免服务器断电等原因导致Redis进程异常退出后数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。

2. 实现方式

① RDB 持久化:将 Reids在内存中的数据库记录定时保存到磁盘上,类似于快照。

② AOF 持久化:将 Reids 的操作日志以追加的方式写入文件,类似于MySQL的binlog。实时性更好,进程意外退出时丢失的数据更少。

3. RDB 持久化

RDB 持久化是指在达到触发条件后将内存中当前进程中的数据用二进制压缩存储,生成dump.rdb 文件;当Redis重新启动时,可以读取快照文件恢复数据。

3.1 触发条件

(1)手动触发

① save 命令:会阻塞 Redis 服务器进程,直到 RDB 文件创建完。

② bgsave 命令:会创建一个子进程,由子进程来负责创建 RDB 文件,父进程(即 Redis 主进程)则继续处理请求,注意仍需待子进程处理完毕通知父进程才可以继续处理下一个请求。

(2)自动触发

配置文件中通过3个“save m n”满足任意一个时,都会引起 bgsave 的调用

[root@localhost ~]# vim /etc/redis/6379.conf 
格式:
save m n           # 指定m秒内发生n次变化,会触发bgsave;这里的save是bgsave的格式写法
 219 save 900 1    # 指定900秒内发生1次变化,会触发bgsave
 220 save 300 10
 221 save 60 10000

相关配置:

 254 dbfilename dump.rdb      # 指定RDB文件名
 264 dir /var/lib/redis/6379  # 指定RDB文件和AOF文件所在目录
 242 rdbcompression yes       # 是否开启RDB文件压缩

其他触发机制:

① 在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行 bgsave 命令,并将 rdb 文件发送给从节点。

② 手动关闭 redis,如执行:shutdown、/etc/initd.d/redis.6379 stop/restart 命令时,会自动执行 rdb 持久化。注意 kill 通知不会触发。

3.2 执行流程

① 当 rdb 持久化被触发后,正常命令、操作等信息会被 redis 父进程接收

② 父进程接收到"快照"和"持久化"指令,会判断是否存在子进程,如果存在,则执行数据处理返回信息;如果不存在,则 fork 创建子进程 

③ fork 创建子进程过程中会阻塞父进程,此时父进程是不能接受任何的请求操作 

④ 子进程创建完毕后会返回信息给父进程,此时父进程将不再阻塞可以接收其他命令,不过需要等待子进程返回上一条完毕信息给父进程,才可以处理下一条命令信息。即可以接收,但需要排队处理

⑤ 子进程的作用就是用来生成 *.rdb文件(覆盖原文件,或者压缩替换原来的文件)

⑥ 当 rdb 文件生成完毕后信号通知父进程,父进程会接收其他命令、更新统计信息

3.3 启动时加载 

  • 当服务器启动时自动执行 rdb 文件的载入工作
  • AOF 的优先级更高,因此当 AOF 开启时,Redis 会优先载入 AOF 文件来恢复数据
  • 服务器载入 rdb 文件期间处于阻塞状态,直到载入完成为止
  • Redis 载入rdb 文件时,会对 rdb 文件进行校验,如果文件损坏,则记录日志,启动失败

4. AOF 持久化

将Redis执行的每次写、删除命令记录到单独的日志文件中,查询操作不会记录; 当Redis重启时再次执行AOF文件中的命令来恢复数据。相当于增量备份,与RDB相比AOF的实时性更好。

4.1 开启 AOF

在配置文件中默认开启RDB,AOF 需要手动开启。

[root@localhost ~]# vim /etc/redis/6379.conf 
 700 appendonly yes                   # 开启AOF,默认no
 704 appendfilename "appendonly.aof"  # 指定AOF文件名称
 796 aof-load-truncated yes           
# 是否忽略最后一条可能存在问题的指令
# 需要注意的是:当最后一条存在问题,忽略这条指令;当最后一条没有问题,保留这条指令

4.2 执行流程

4.2.1 命令追加(append)

将Redis的写命令追加到缓冲区 aof_buf,而不是直接写入文件,避免频繁写入,导致硬盘 IO 成为Redis 负载的瓶颈。在 AOF 文件中,除了用于指定数据库的 select 命令是由 Redis 添加,其他均来自客户端。

4.2.2 文件写入(write)和文件同步(sync)

根据不同的同步策略将 aof_buf 中的内容同步到硬盘;当用户调用 write 函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。Redis提供了多种AOF缓存区的同步文件策略:

  • appendfsync always:一直触发 AOF 的持久化,应用有强制一致性要求的场景
  • appendfsync no:不进行持久化
  • appendfsync everysecond:每秒钟触发一次持久化,建议使用,类似于负载均衡的场景 

4.2.3 文件重写(rewrite) 

定期重写 AOF 文件,达到压缩的目的、减小 AOF 文件的体积。需要注意的是,AOF 重写是把 Redis 进程内的数据转化为写命令,同步到新的 AOF 文件;不会对旧的 AOF 文件进行任何读取、写入操作。重写一般针对以下情况:

  • 过期的数据不再写入文件
  • 无效的命令不再写入文件
  • 多条命令可以整合的

4.3 文件重写触发 

(1)手动触发

直接调用 bgrewriteaof 命令,该命令的执行与 bgsave 有些类似:都是 fork 子进程进行具体的工作,且都只有在 fork 时阻塞。

(2)自动触发

修改 /etc/redis/6379.conf 相关配置,只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个选项同时满足时,才会自动触发AOF重写,即bgrewriteaof操作。

[root@localhost ~]# vim /etc/redis/6379.conf 
 771 auto-aof-rewrite-percentage 100  # 当前AOF文件大小(即aof_current_size)是上次日志重写时AOF文件大小(aof_base_size)两倍时,发生BGREWRITEAOF操作
 772 auto-aof-rewrite-min-size 64mb   # 当前AOF文件执行BGREWRITEAOF命令的最小值,避免刚开始启动Reids时由于文件尺寸较小导致频繁的BGREWRITEAOF

4.4 重写流程

① 父进程会先判断有没有其他的子进程在运行,如果有 bgrewriteaof 的直接返回,如果是 bgsave 等他执行完再执行

② 如果没有其他的子进程,父进程就会 fork 子进程,此时父进程是阻塞的,子进程会创建好后信息通知父进程,此时父进程可以继续接收其他命令

③ redis 会先将写入的命令暂存在缓冲区里,根据 sync 策略同步的硬盘里

④ 父进程在 fork 子进程后响应的命令会同时记录到 aof_rewrite_buf 当中

⑤ fork 后的数据也会被写入到旧的 aof 文件中

⑥ 子进程根据合并规则重写生成新的 aof 文件

⑦ 子进程完成新的 aof 文件生成后向父进程发送信号,父进程更新统计数据

⑧ fork 后的数据也会被写入到新的 aof 文件

⑨ 新的aof文件 替换旧的 aof 文件

4.5 启动时加载 

  • 当AOF开启时,Redis 启动时会优先载入 AOF 文件来恢复数据;只有当 AOF 关闭时,才会载入RDB 文件恢复数据
  • 当AOF开启,但AOF文件不存在时,即使RDB文件存在也不会加载
  • Redis载入AOF文件时,会对AOF文件进行校验,如果文件损坏,则日志中会打印错误,Redis启动失败
  • 如果是 AOF 文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且 aof-load-truncated 参数开启,则日志中会输出警告,Redis 忽略掉 AOF 文件的尾部,启动成功

5. RDB 和 AOF 的优缺点 

① RDB 持久化

优点:

  • RDB 文件紧凑,体积小,网络传输快,适合全量复制,会压缩数据
  • 恢复速度比 AOF 快很多
  • 备份整个结果,主从复制优先使用 rdb,同步性能高

缺点:

  • 数据快照的持久化方式决定了必然做不到实时持久化
  • RDB 文件需要满足特定格式,兼容性差 
  • bgsave 在进行 fork 操作时 Redis 主进程会阻塞
  • 子进程向硬盘写数据也会带来 IO 压力

②  AOF 持久化

优点:

  • 支持秒级持久化、兼容性好
  • 有重写功能,可以压缩释放空间

缺点:

  • 文件大、恢复速度慢、对性能影响大
  • 对于 AOF 持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO 压力更大,甚至可能造成 AOF 追加阻塞问题
  • AOF文件的重写会有fork时的阻塞和子进程的IO压力问题

6. RDB 和 AOF 优先级

① AOF 优先级高于 RDB,如果两种持久化方式都开启,Redis 会优先使用 AOF 来恢复数据,因为 AOF 记录了每次写操作,可以保证数据的完整性

② RDB 是一种快照持久化方式,它会定期将内存中的数据集快照写入磁盘,但是这种方式可能会丢失最后一次快照后的所有数据

③ 虽然 AOF 优先级高于 RDB,但是在某些情况下,可能需要同时使用这两种方式,以提高数据的安全性和可靠性

④ 如果两种持久化方式都关闭,Redis 会在内存中保存数据,但是一旦服务器重启,数据就会丢失

三、内存性能管理 

Redis 需要在保持高性能的同时有效管理内存,因为内存是 Redis 的关键资源。通过合理配置Redis 的数据持久化机制,可以平衡性能与数据安全之间的关系,确保系统的稳定性和可靠性。

1.内存使用与碎片

1.1 查看 Redis 内存使用

127.0.0.1:6379> info memory
# Memory
used_memory:7564808             # 表示 Redis 实例当前使用的内存量为 7564808 字节,约为 7.21 兆字节
used_memory_rss:11739136          
used_memory_rss_human:11.20M    # 表示 Redis 进程占用的实际物理内存(包括共享库、堆栈等)为 11739136 字节,约为 11.20 兆字节
used_memory_peak_perc:94.27%    # 表示 Redis 实例使用的内存峰值为 8024592 字节,约为 7.65 兆字节,占已分配内存的 94.27%。
used_memory_dataset:1737080     # 表示 Redis 数据集占用的内存量为 1737080 字节
mem_fragmentation_ratio:1.56    # 是内存碎片率,表示 Redis 内存碎片化的程度。在这种情况下,内存碎片率为 1.56

1.2 内存碎片率与 Redis 资源性能

Redis内存碎片指的是未被充分利用的内存空间,通常由于内存分配和释放的不规则或频繁操作而产生。内存按块平均分配,比如一块32字节,若此时写入redis的每条命令均为24字节,那么空出来无法使用的8字节就是碎片。

在Redis中,内存碎片率可以通过 mem_fragmentation_ratio 指标来评估,即操作系统分配的内存值 used_memory_rss 除以 Redis 使用的内存总量值 used_memory 计算得出。即MFR=used_memory_rss/used_memory。

注意:当内存使用量(used_memory)很小的时候,这个值参考价值不大。所以,建议used_memory至少1G以上才考虑对内存碎片率进行监控。

mem_fragmentation_ratio:

  • 内存碎片率稍大于1是合理的,这个值表示内存碎片率比较低,也说明 Redis 没有发生内存交换
  • 内存碎片率超过1.5,说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。需要在redis-cli工具上输入shutdown save 命令,让 Redis 数据库执行保存操作并关闭 Redis 服务,再重启服务器
  • 内存碎片率低于1的,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。需要增加可用物理内存或减少 Redis 内存占用

1.3 内存使用率

redis 实例的内存使用率超过可用最大内存,操作系统将开始进行内存与 swap 空间交换。

避免内存交换发生的方法:

  • 针对缓存数据大小选择安装 Redis 实例
  • 尽可能的使用Hash数据结构存储
  • 设置key的过期时间

2. 内存回收key

内存清理策略,保证合理分配redis有限的内存资源。当达到设置的最大阀值时,需选择一种key的回收策略,默认情况下回收策略是禁止删除。配置文件中修改 maxmemory-policy 属性值:

vim /etc/redis/6379.conf
 598 # maxmemory-policy noeviction  
# 示当内存达到上限时,Redis 不会驱逐任何数据,而是会拒绝写入操作并向客户端返回一个错误
volatile-lru     # 使用LRU算法从已设置过期时间的数据集合中淘汰数据(移除最近最少使用的key,针对设置了TTL的key)
volatile-ttl     # 从已设置过期时间的数据集合中挑选即将过期的数据淘汰(移除最近过期的key)
volatile-random  # 从已设置过期时间的数据集合中随机挑选数据淘汰(在设置了TTL的key里随机移除)
allkeys-lru      # 使用LRU算法从所有数据集合中淘汰数据(移除最少使用的key,针对所有的key)
allkeys-random   # 从数据集合中任意选择数据淘汰(随机移除key)
noenviction      # 禁止淘汰数据(不删除直到写满时报错)
保存文件并重启 Redis 服务以使更改生效

3. Redis 缓存的穿透、击穿与雪崩

3.1 穿透

指的是针对不存在于缓存中的数据进行大量请求,导致这些请求直接访问数据库。这可能是因为恶意请求或者查询不存在的键导致的。

在 maxmemory-policy 方面,可以设置为 noeviction,禁止淘汰数据,确保即使缓存未命中也不会导致数据库被大量无效请求冲击。

3.2 击穿

发生在某个热点数据过期后,此时有大量并发请求同时访问该热点数据,导致大量请求直接访问数据库。

在 maxmemory-policy 方面,可以使用 lur(最近最少使用)或者 ttl(设置过期时间)策略来尽可能保留热点数据,减少缓存击穿的概率。

3.3 雪崩

指的是缓存中大量的数据同时失效,导致大量请求直接访问数据库,造成数据库负载剧增。为了避免缓存雪崩,可以给缓存数据设置不同的过期时间,使其分散失效时间点;另外,使用热点数据预热,保证缓存中的数据不会同时失效。

在 maxmemory-policy 方面,同样可以使用 lur 或 ttl 策略来合理管理缓存的过期和淘汰,以减少缓存雪崩的风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1575009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STL库 —— vector 的编写

一、成员变量 二、容量成员 2.1 size 函数 我们在定义私有成员时就会发现,其中 _finish 相当于 string 中的 size 的地址, _endofstorage 相当于 string 中的 capacity 的地址,所以 size 函数和 capacity 函数其实基本没有改变。 size_t s…

MIT6.828 Lab1 Xv6 and Unix utilities

2023MIT6.828 lab-1 官方地址 一、sleep 实验内容 调用sleep(系统调用)编写用户级别程序能暂停特定时常的系统滴答程序保存在user/sleep.c 实验过程 xv6的参数传递 查看官方文档提示的文件中,多采用如下定义: int main(in…

如何在nuxt中优雅使用swiper,实现过渡反向+贴合无缝+循环播放【核心代码分析】

视频效果 20240402-1723 图片效果 技术栈 Nuxt3 + Swiper11 Nuxt3 Nuxt: The Intuitive Vue Framework Nuxt Swiper11 Swiper - The Most Modern Mobile Touch Slider (swiperjs.com) 当然你也可以是使用nuxt-swiper Nuxt-Swiper GitHub - cpreston321/nuxt-swiper: Swi…

CPU+GPU+NPU三位一体AI边缘控制器,三屏异显,搭载RK3588处理器

XMS-201采用了Rockchip RK3588八核64位处理器,集成ARM Mali-G610 MP4四核GPU,内置AI加速器NPU,可提供6Tops算力,支持主流的深度学习框架;性能强劲的RK3588可为各类AI应用场景带来更强大的性能表现,适用于机…

【40分钟速成智能风控1】互联网金融风险管理简介

目录 瓦联网金融的发展和现状 风险管理类型划分 欺诈风险 第一方和第三方 账户级和交易级 个人和团伙 互联网金融是传统金融业务与新兴互联网技术结合的一个交叉领域,例如互联网公司开展的金融业务,或者金融机构的线上化服务,都属于互联…

Brain.js 的力量:构建多样化的人工智能应用程序

机器学习(ML)是人工智能 (AI) 的一种形式,旨在构建可以从处理的数据中学习或使用数据更好地执行的系统。人工智能是模仿人类智能的系统或机器的总称。 机器学习(ML)与复杂的数学纠缠在一起,让大多数初学者…

08 | Swoole 源码分析之 Timer 定时器模块

原文首发链接:Swoole 源码分析之 Timer 定时器模块 大家好,我是码农先森。 引言 Swoole 中的毫秒精度的定时器。底层基于 epoll_wait 和 setitimer 实现,数据结构使用最小堆,可支持添加大量定时器。 在同步 IO 进程中使用 seti…

three.js能实现啥效果?看过来,这里都是它的菜(01)

经常有老铁问我,这里炫酷效果是如何实现的,还有问我想实现什么效果怎么办,甚至还有想实现动态效果,但是描述不出来的。 好吧,统统满足老铁们呢,本期开始分享three.js效果图,并附带简要简介&…

usbserial驱动流程解析_Part2_初始化流程_以probe为例(echo cat测试回环打印不停问题解决)

usb转串口设备需要注册usb侧和serial侧两侧的操作,本文将简要分析二者的初始化流程以及一些关键函数的初始化流程。 module_init(usb_serial_init); tty设备初始化 内核会直接调用usb_serial_init,开始进行usb和serial的初始化,首先是进行t…

全面探究 LangChain Text Splitters

全面探究 LangChain Text Splitters 0. 引言1. 文本拆分器的类型2. 探究各个文本拆分器2-1. Split by HTML header2-2. Split by HTML section2-3. Split by character2-4. Split code2-5. MarkdownHeaderTextSplitter2-6. Recursively split JSON2-7. Recursively split by ch…

lv17 CGI移植 5-1

简介 CGIC是一个支持CGI开发的开放源码的标准C库,可以免费使用,只需要在开发的站点和程序文档中有个公开声明即可,表明程序使用了CGIC库,用户也可以购买商业授权而无需公开声明。 CGIC能够提供以下功能: 分析数据&a…

疲劳驾驶预警系统项目知识点整理

参考: 重磅!头部姿态估计「原理详解 实战代码」来啦!-阿里云开发者社区 (aliyun.com) Dlib模型之驾驶员疲劳检测三(瞌睡点头)_疲劳检测 点头-CSDN博客 python毕业设计 深度学习疲劳检测 驾驶行为检测 - opencv cnn…

面试:HashMap

目录 1、底层数据结构,1.7 与1.8有何不同? 2、为何要用红黑树,为何一上来不树化,树化阈值为何是8,何时会树化,何时会退化为链表? 3、索引如何计算? hashCode都有了,为何还要提供hash()方法?数组容量为…

交换机与队列的简介

1.流程 首先先介绍一个简单的一个消息推送到接收的流程,提供一个简单的图 黄色的圈圈就是我们的消息推送服务,将消息推送到 中间方框里面也就是 rabbitMq的服务器,然后经过服务器里面的交换机、队列等各种关系(后面会详细讲&…

保研复习数据结构-图(10)

一.图的定义和基本术语 1.什么是图? 图(Graph)是由顶点的有穷非空集合V(G)和顶点之间边的集合E(G)组成,通常表示为:G(V,E),其中,G表示图,V是图G中顶点的集合,E是图G中边的集合。 2.什么是完全图&#xf…

【第十二篇】使用BurpSuite实现CSRF(实战案例)

CSRF存在前提:简单的身份验证只能保证请求是发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的 业务场景:新增、删除、收藏、编辑、保存使用Burp发现CSRF漏洞的过程如下。 1、如图,存在修改邮箱的功能点如下: 2、修改邮箱的流量包,此时邮箱已被修改: 思路:是…

12、最小覆盖子串

如何想到这个解法 问题的特点: 首先,认识到这是一个关于子串的问题,而且需要考虑子串的最小长度。这提示我们可能需要使用一种方式来逐步探索不同的子串。滑动窗口的适用性:滑动窗口是处理子串问题的常用技巧,特别是当…

X年后,ChatGPT会替代底层程序员吗?

能不能替代,真的很难说,因为机器换掉人,这其实是一个伦理问题。 其实说白了,任何行业在未来都会被AI或多或少的冲击到,因为ChatGPT做为一个可以持续提升智能的AI,在某些方面的智能程度超过人类并不是什么难…

笛卡尔树[天梯赛二叉树专项训练]

文章目录 题目描述思路AC代码 题目描述 输入样例1 6 8 27 5 1 9 40 -1 -1 10 20 0 3 12 21 -1 4 15 22 -1 -1 5 35 -1 -1 输出样例1 YES 输入样例2 6 8 27 5 1 9 40 -1 -1 10 20 0 3 12 11 -1 4 15 22 -1 -1 50 35 -1 -1 输出样例2 NO思路 见注释 AC代码 #include <bits/st…

5. 4 二重循环将二维数组的某列、某矩形转大写

5. 4 二重循环将二维数组的某列、某矩形转大写 1. 把每一行的b都变成大写 assume cs:codesg,ds:data,ss:stack data segmeNTstr db aaaaabbbbbcccccdb aaaaabbbbbcccccdb aaaaabbbbbcccccdb aaaaabbbbbccccc,$ data endsstack segmentdb 10 dup(0) stack endscodesg SEgments…