一、问题说明

业务上接到报警提示服务器内存爆了,登录查看发现机器剩余内存还很多,怀疑是被OOM了,查看/var/log/messages:

kernel: [25918282.632003] Out of memory: Kill process 18665 (redis-server) score 919 or sacrifice child
kernel: [25918282.637201] Killed process 18665 (redis-server) total-vm:17749556kB, anon-rss:14373204kB, file-rss:1236kB
kernel: [25918791.441427] redis-server invoked oom-killer: gfp_mask=0x24280ca, order=0, oom_score_adj=0

发现redis-server被oom kill了,但是登录查看发现redis-server并没有down掉.

二、问题排查

既然redis-server并没有被kill,那被kill的有可能是redis的子进程。

进入redis的data目录查看:

-rw-rw-r-- 1 myuser myuser 18044223152 4月   8 12:01 appendonly.aof
-rw-rw-r-- 1 myuser myuser 3603981186 4月 8 12:01 temp-rewriteaof-25595.aof
-rw-rw-r-- 1 myuser myuser 4083774382 4月 8 11:46 temp-rewriteaof-18665.aof
-rw-rw-r-- 1 myuser myuser 4326578230 4月 8 11:21 temp-rewriteaof-8116.aof

发现有好几个temp-rewriteaof文件,这是redis在进行aofrewrite时产生的临时文件。

注意看其中一个的名字:temp-rewriteaof-18665.aof ,后面的18665即rewrite子进程的pid,上面被oom kill的进程ID也是18665,说明是redis的aofrewrite子进程被kill了。

而多个temp文件,而且时间都是最近的,说明redis已经尝试了多次rewrite,都因为内存不足被中途kill。

查看监控发现,近期确实多次出现了内存突增的情况:

为什么aof重写会导致内存爆涨?这要从它的原理说起。

AOF 是redis的一种持久化方式,用来记录所有的写操作,但是随着时间增加,aof文件会越来越大,所以需要进行重写,将内存中的数据重新以命令的方式写入aof文件。
在重写的过程中,由于redis还会有新的写入,为了避免数据丢失,会开辟一块内存用于存放重写期间产生的写入操作,等到重写完毕后会将这块内存中的操作再追加到aof文件中。

从原理中可以了解到,如果在重写过程中redis的写入很频繁或写入量很大,就会导致占用大量额外的内存来缓存写操作,导致内存爆涨。

查看redis的访问情况:

从监控中可以看到,redis实际的访问OPS并不高,那么剩下的可能性就只有写入量了。

登录Redis使用monitor监控了一段时间的访问,记录到文件中:

[myuser@redis-00 ~]$ time redis-cli -p 6379 monitor > monitor.log
^C real 0m24.219s
user 0m0.552s
sys 0m0.036s

通过查看monitor.log发现,存在这样一条语句:

1523351418.461744 [0 10.10.10.10:6379] "SET" "xx_xx_id_17791"
"[615249,615316,615488,616246,616498,616580,617117,617291,617510,617879,
618052,618377,618416,619010,619185,619603,619816,620190,620230,620387,
620445,620524,621012,621214,621219,621589,621596,621616,621623,621669,
621670,621682,621683,621820,621994,622168,622207,622245,622384,622442,
622450,622608,622644,622654,622658,622704,622784,622785,622786,622810,
622834,622876,622887,622934,622936,622937,622939,622943,622967,......]"
  • 为了看起来方便,我做了换行处理,并且省略了大部分的key内容,但实际上该set命令的内容一直拉不到头。

过滤该key进行分析:

# monitor.log 大小
[myuser@redis-00 ~]$ du -sh monitor.log
62M monitor.log
[myuser@redis-00 ~]$ wc -l monitor.log
12114 monitor.log [myuser@redis-00 ~]$ grep 'xx_xx_id_17791' monitor.log | grep -v 'GET' > xx_xx_id_17791.log # xx_xx_id_17791 key 大小
[myuser@redis-00 ~]$ du -sh xx_xx_id_17791.log
61M xx_xx_id_17791.log
[myuser@redis-00 ~]$ wc -l xx_xx_id_17791.log
17 xx_xx_id_17791.log

62M的monitor文件,17行 xx_xx_id_17791 的set命令一共占了61M,很明显就是这个key搞的鬼了,去找开发确认,果然是程序出了问题。

三、处理结果

1. 临时处理

在接到报警时是在夜间,而aof rewrite一直失败,因此做了临时处理:

127.0.0.1:6379> config get auto-aof-rewrite-percentage
1) "auto-aof-rewrite-percentage"
2) "200"
127.0.0.1:6379> config set auto-aof-rewrite-percentage 800
OK

auto-aof-rewrite-percentage 是设置aof rewrite触发时机的一个参数,当当前的aof文件大小超过上一次rewrite后aof文件的百分比后触发rewrite。

200 改为 800 ,即当前的aof文件超过上一次重写后aof文件的8倍时才会再次rewrite,这样可以保证短期内不会再次进行重写操作。

2. 问题解决

找开发进行确认后,将该key进行了删除,开发也说已经修改了程序,auto-aof-rewrite-percentage重新改为200。

结果只是消停了一阵子,不久后又出现一个类似的超大key,还是半夜报的警

优化 | Redis AOF重写导致的内存问题 不错的更多相关文章

  1. AOF重写导致的Redis进程被kill

    Redis环境描述 服务器: 阿里云16GB服务器 Redis版本: 5.0.5 持久化方式: AOF 问题描述 阿里云环境,使用docker安装的单节点redis5.x,频繁出现redis进程被操作 ...

  2. Golang 实现 Redis(4): AOF 持久化与AOF重写

    本文是使用 golang 实现 redis 系列的第四篇文章,将介绍如何使用 golang 实现 Append Only File 持久化及 AOF 文件重写. 本文完整源代码在作者GithubHDT ...

  3. Redis之AOF重写及其实现原理

    Reference: https://blog.csdn.net/hezhiqiang1314/article/details/69396887 AOF 重写AOF 持久化是通过保存被执行的写命令来记 ...

  4. redis采用tcmalloc导致无法释放内存的问题

    from:http://wangneng-168.iteye.com/blog/2100379 redis使用tcmalloc管理内存,当删除了redis的key后,通过redis的info命令查看内 ...

  5. Redis(八)理解内存

    Redis所有的数据都存在内存中,当前内存虽然越来越便宜,但跟廉价的硬盘相比成本还是比较昂贵,因此如何高效利用Redis内存变得非常重要. 高效利用Redis内存首先需要理解Redis内存消耗在哪里, ...

  6. 深入剖析 redis AOF 持久化策略

    本篇主要讲的是 AOF 持久化,了解 AOF 的数据组织方式和运作机制.redis 主要在 aof.c 中实现 AOF 的操作. 数据结构 rio redis AOF 持久化同样借助了 struct ...

  7. 解决redis aof文件过大的问题

    执行BGREWRITEAOF命令对redis的AOF进行重写 redis-cli BGREWRITEAOF 相关解释: Redis的AOF机制有点类似于Mysql binlog,是Redis的提供的一 ...

  8. Redis AOF文件

    [Redis AOF文件] 1.关于AOF AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集. AOF 文件中的命令全部以 Redis 协议的格式来保存 ...

  9. redis aof文件过大问题

    http://www.itnose.net/detail/6682725.html 最近新安装了一台redis,版本为redis-3.2.5 数据盘用的是固态硬盘. 之前用的是普通硬盘,redis日志 ...

随机推荐

  1. 关于Mysql 修改密码的记录

    初次安装后完毕,使用管理员身份进入cmd界面, 输入" mysql -u root -p",出现"Enter password:",直接回车输入" s ...

  2. Comet OJ - Contest #3 B -棋盘 (思维+分类讨论)

    题目描述 小猫有一个 2\times N2×N 的棋盘,每一个格子放着一个黑棋子或白棋子. 小熊觉得小猫的棋盘不够好看,想要把棋盘上的一部分白棋子替换成黑棋子,使得所有黑棋子都能够在仅允许上下左右四个 ...

  3. python3-访问限制

    在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑. 但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的na ...

  4. 查看jar包内容

    查看jar包内容 查看jar包内容的基本命令: jar tf jar-file 参数解释: The t option indicates that you want to view the table ...

  5. ubuntu重装--备份/配置

    https://github.com/wenlin-gk/document/blob/master/ubuntu%E5%A4%87%E4%BB%BD%2B%E9%85%8D%E7%BD%AE.txt

  6. v-if 和 v-show

    关于条件渲染 所谓条件渲染,就是根据不同的条件,使用不同的模板来生成 html. 在 Vue.js 中,使用 v-if 和 v-show 指令来控制条件渲染. 区别 v-show 会在app初始化的时 ...

  7. 【bzoj2002】弹飞绵羊

    题目 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数k ...

  8. 【宝藏】题解(五校联考3day1)

    分析 如果打爆搜的话可以拿60分. 首先知道期望是可以累加的,即i通过j去到k的期望,等于i去到j的期望加j去到k的期望. 所以令d[i]表示i的出度,F[i]表示从i到i的父亲的期望,G[i]表示i ...

  9. npm cache clean --force

    当出现这个问题时npm ERR! Unexpected end of JSON input while parsing near '...,"dist":{"shasum ...

  10. JavaScript性能优化之小知识总结

    1.避免全局查找 在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些 2.定时器 如果针对的是不断运行的代码,不应该使用setTimeout,而 ...