首页 > 运维 > linux运维 > 正文

Redis详解(5)常见问题和解决方法

星夢妙者
发布: 2025-07-12 09:28:15
原创
172人浏览过

1、redis master 数据库性能调优

  1. Master 执行内存快照时,会调用 save 命令触发 rdbSave 函数,这会阻塞主线程,导致服务性能大幅下降。因此,Master 不应执行内存快照操作。

  2. Master 使用 AOF 持久化时,若不重写 AOF 文件,对性能的影响较小。但 AOF 文件会持续增大,影响 Master 重启时的恢复速度。

  3. 当 Master 执行 BGREWRITEAOF 重写 AOF 文件时,会消耗大量 CPU 和内存资源,导致服务负载过高,出现短暂的服务中断现象。

在我的一个实际项目中,配置为一个 Master 和四个 Slave,没有使用 Sharding 机制,仅进行读写分离。Master 负责写入和 AOF 日志备份,AOF 文件大约 5G,Slave 负责读操作。当 Master 执行 BGREWRITEAOF 时,Master 和 Slave 的负载突然激增,Master 的写入请求几乎不响应,持续约 5 分钟,Slave 的读请求也无法及时响应。Master 和 Slave 的服务器负载图如下:

Master Server load:

Slave server load:

这种情况本不应发生,原因是原先的 Master 机器曾作为 Slave 使用,设有一个每日上午 10 点执行 BGREWRITEAOF 的 shell 定时任务。由于 Master 机器宕机,将备份的 Slave 切换为 Master 时忘记删除该定时任务,导致上述问题。经过几天的排查才找到原因。

通过将 no-appendfsync-on-rewrite 配置设为 yes,可以缓解这个问题,设置为 yes 表示在重写期间不执行 fsync 操作,新的写入操作暂时存储在内存中,等重写完成后再写入。最佳方案是不在 Master 上启用 AOF 备份功能。

  1. Redis 主从复制的性能问题:第一次 Slave 与 Master 同步时,Slave 向 Master 发送同步请求,Master 生成 rdb 文件并全量传输给 Slave,然后 Master 将缓存的命令转发给 Slave,完成初次同步。之后的同步,Master 将变量的快照实时发送给各个 Slave。无论何种原因导致 Slave 和 Master 断开重连,都会重复上述过程。Redis 的主从复制依赖于内存快照的持久化,只要有 Slave 存在,就会有内存快照发生。虽然 Redis 声称主从复制无阻塞,但由于使用单线程服务,如果 Master 的快照文件较大,第一次全量传输会耗费较长时间,且传输过程中 Master 可能无法提供服务,导致服务中断,对于关键服务来说,这是一个严重问题。

以上 1、2、3、4 的根本问题都源于系统的 I/O 瓶颈,即硬盘读写速度不足,导致主进程的 fsync()/write() 操作被阻塞。

  1. 单点故障问题:由于 Redis 的主从复制机制还不够成熟,存在明显的单点故障问题,目前只能通过自定义方案解决,如主动复制、Proxy 实现 Slave 对 Master 的替换等。这也是 Redis 作者目前优先处理的任务之一,作者提出的解决方案简单优雅,详见 Redis Sentinel design draft https://www.php.cn/link/8a662c4cd8df28eeda49c30da8bcb92c

总结:

  1. Master 最好不进行任何持久化操作,包括内存快照和 AOF 日志文件,尤其是不要使用内存快照进行持久化。

  2. 如果数据关键,某个 Slave 应启用 AOF 备份数据,策略为每秒同步一次。

  3. 为了主从复制的速度和连接的稳定性,Slave 和 Master 最好位于同一局域网内。

  4. 尽量避免在负载较高的 Master 上添加 Slave。

  5. 为了 Master 的稳定性,主从复制应使用单向链表结构而非图状结构,即主从关系应为:Master -> Slave1 -> Slave2 -> ...

2、解决 Redis 连接错误:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to...

在连接 Redis 数据库时,服务器突然报错:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

翻译为:Redis 被配置为保存数据库快照,但它目前无法持久化到硬盘。用于修改数据集的命令不能使用。请查看 Redis 日志以获取有关 RDB 错误的详细信息。

原因是强制关闭了 Redis 快照,导致无法持久化的问题。通过将 stop-writes-on-bgsave-error 值设置为 no 可以避免这种问题。

有两种修改方法,一种是通过 Redis 命令行修改,另一种是直接修改 redis.conf 配置文件。

命令行修改示例:

127.0.0.1:6379> config set stop-writes-on-bgsave-error no
登录后复制

修改 redis.conf 文件:使用 vi 打开 redis-server 配置的 redis.conf 文件,然后使用快捷匹配模式:/stop-writes-on-bgsave-error 定位到 stop-writes-on-bgsave-error 字符串所在位置,接着将后面的 yes 改为 no 即可。

3、解决 Redis AOF 文件过大的问题

Redis 的 AOF 机制类似于 MySQL 的 binlog,是 Redis 提供的一种持久化方式(另一种是 RDB),它会按照一定频率(no, always, every seconds)将所有写命令写入日志文件中,Redis 停机重启后恢复数据库。

AOF 重写:

  1. 随着 AOF 文件越来越大,里面会有大部分重复命令或可合并的命令(如 100 次 incr = set key 100)。
  2. 重写的好处:减少 AOF 日志尺寸,减少内存占用,加快数据库恢复时间。

执行 AOF 文件重写操作会创建一个当前 AOF 文件的体积优化版本。即使 BGREWRITEAOF 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 BGREWRITEAOF 成功之前不会被修改。从 Redis 2.4 开始,AOF 重写由 Redis 自行触发,BGREWRITEAOF 仅用于手动触发重写操作。但有网友提到在 3.2.5 版本中,Redis 似乎没有自动触发 BGREWRITEAOF 的稳妥方法,建议编写脚本每天定时执行。

  1. 出现问题:Redis 集群中某个节点报错如下:
Starting automatic rewriting of AOF on 307% growth Error opening /setting AOF rewrite IPC pipes: Numerical result out of range
登录后复制

这个错误表示 Redis 中 AOF 文件超出了存储的最大内容。

  1. 解决方法:将 AOF 文件重命名为【文件.aof.(数字)】,如 appendonly.aof.1,然后创建原文件。如果问题尚未解决,重启出现问题的 Redis 节点。

4、Redis 突然挂掉后,无法启动,查看 log 日志,发现报错:Short read or OOM loading DB. Unrecoverable error, aborting now

解决办法:

rm -f redis/dump.rdb
rm -f redis.pid
登录后复制

5、background save db 不成功

如果 Redis 有时 background save db 不成功,通过 log 发现以下告警,很可能是由它引起的:

# WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
登录后复制

当执行 Redis 的 bgsave 命令时,Redis 会 fork 一个进程将 Redis 中的内存数据写入磁盘。这样的好处是 copy on write,有效节省了内存占用。但是,bgsave 时,如果有数据变更,同样需要申请内存。当申请内存时,如果发现内存不足,可能就会报上述错误。

首先需要了解内核参数:overcommit_memory

它是内存分配策略

可选值:0、1、2。

0,表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。

2,表示内核允许分配超过所有物理内存和交换空间总和的内存。

什么是 Overcommit 和 OOM

Linux 对大部分申请内存的请求都回复 "yes",以便能运行更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术称为 Overcommit。当 Linux 发现内存不足时,会发生 OOM killer(OOM = out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。

当 OOM-killer 发生时,Linux 会选择杀死哪些进程?选择进程的函数是 oom_badness 函数(在 mm/oom_kill.c 中),该函数会计算每个进程的点数(0~1000)。点数越高,这个进程越有可能被杀死。每个进程的点数跟 oom_score_adj 有关,而且 oom_score_adj 可以被设置(-1000 最低,1000 最高)。

解决方法:将 vm.overcommit_memory 设为 1

有三种方式修改内核参数:

1)编辑 /etc/sysctl.conf,改 vm.overcommit_memory=1,然后 sysctl -p 使配置文件生效。

2)sysctl vm.overcommit_memory=1

3)echo 1 > /proc/sys/vm/overcommit_memory

5、Redis 进程占用 CPU 100%

通过 top 发现 Redis 进程 CPU 使用率 100%

Redis详解(5)常见问题和解决方法

  1. 通过 info 命令检查当前的执行命令情况:instantaneous_ops_per_sec

  2. 检查慢查询 slowlog get,发现大量的 keys 命令,相关服务去掉 keys 命令后,服务恢复正常。

Redis详解(5)常见问题和解决方法

以上就是Redis详解(5)常见问题和解决方法的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号