APP下载

排查Redis存储失败

2020-12-31河南刘建臣

网络安全和信息化 2020年6期
关键词:磁盘命令进程

■ 河南 刘建臣

单位的一台Web服务器后台使用的是Redis服务器,其工作一直比较正常。而最近出现无法写入数据的故障,给业务带来了很大的影响。

该机安装的是CentOS6.X系统,使用的是四核的CPU,内存为16GB,在该机上执行“top”命令,发现内存的使用率为70%,CPU的负荷并不大。执行“df”“lsof”“iotop”等命令,发现磁盘读写情况没有问题。进入Redis日志文件路径(这里为“/var/log/redis”),然后执行“vi redis.log”命令,发现其中存在“Can't save in background:fork:Cannot allocate memory”错误提示。

故障排查

根据以上错误信息,说明当Redis存储数据时,因为内存无法分配导致故障的发生。但是执行“top”命令发现内存并没有耗尽,似乎应该可以为Redis分配足够的内存。

执行“vi/etc/redis/redis.conf”命令,在Redis配置文件中发现“save 900 1” “save 300 10” “save 60 10000” “appendonly no”“maxmemory 10GB”等信息。其中三个“save”项目指的是自动触发Redis数据持久化到磁盘的策略,即当指定的时间内数据发生设定次数变动时,就会触发“bgsave”命令将数据存储到磁盘。

例如,对于“save 900 1”来说,当900秒内数据变化为1次时,就将变化的数据存储到磁盘中。根据Redis日志文件提供的信息,可以看到当触发了“save 60 1000”策略时,才出现了无法分配内存的故障。这意味着在60秒时间内,当数据变化的次数达到10000次时,才出现无法分配内存的问题。

但是对于其他两个Save策略来说,在存储数据时是没有问题的。在“appendonly”项中的参数为“no”,说明并没有开启Resia的AOF持久化机制。如果开启该机制,那么当每次执行写操作时,都会自动记录对应的Log日志,这将提高数据安全性。

我们知道,Redis是内存型数据库,数据都是存储在内存中,为了避免Redis进程关闭导致数据的永久丢失,需要定期将Redis中的数据以命令等形式从内存保存到硬盘。当以后重启Redis时,就可以利用持久化机制实现数据恢复。

当然,为保护数据安全,还要尽可能的将持久化文件复制到远程存储空间中保存。Redis持久化分为RDB和AOF两种方式,前者是将当前进程中的数据生成快照保存到硬盘,也称快照持久化,保存的文件后缀是“.rdb”。当Redis重新启动时,可以读取快照文件恢复数据。

后者是将Redis执行的每次写命令记录到单独的日志文件中,当Redis重启时再次执行AOF文件中的命令来恢复数据。由于AOF持久化的实时性更好,遇到Redis异常退出时丢失的数据更少,因此AOF是目前主流的持久化方式。在默认状态下,该机制是处于不开启的状态,即Redis会采取异步机制将数据写入到磁盘中。在“maxmemory”参数中执行Redis可以使用的最大的内存量,当Redis在启动时,会加能够数据加载到内存中,当达到最大的内存使用量时,Redis会尝试清除已经或者即将到期的Key键值。

当处理完毕后,如果依然达到最大的内存使用量,就无法执行写入操作,但依然可以执行数据的读取操作。这里的Redis的最大内库存使用量为10GB,但是实际内存量为16GB,看起来还有很多可用的内存,并不应该出现无法分配内存的提示。

继续查阅Redis日志文件,发现了“WARNING overcommit_memory is set to 0!” “Background save may fail under low memory condition”等提示信息,大意是说明在低内存的环境下,后台存储存储数据存在风险。面对这种情况,一般的应对策略是打开“/etc/sysctl.conf”文件,在其中对名为“vm.overcommit_memory”的内存存储参数进行修改。

之后执行“sysctl vm.overcommit_memory=1”命令命令使该修改生效。“vm.overcommit_memory”参数实际对应的是“/proc/sys/vm/overcommit_memory”文件,该文件的主要作用是指定系统内核针对内存的分配策略。该参数默认值为0,表示当内核对于内存分配情况进行检测时,如果发现应有程序没有足够的可用内存的话,那么内存申请操作失败,并将错误信息发送给目标程序。反之,则允许申请内存,保证应用程序正常工作。

如果将该参数的值设置为1,表示不管当前的内存使用情况处于什么状态,都允许分配所有可用的物理内存内存给应用程序。如果参数设置为2,表示内核允许分配超过所有物理内存和交换空间总和的内存量。对于Redis来说,建议将参数的值设置为1,便于其利用所有的物理内存。在本例中该参数的值实际上设置为0,这意味着虽然系统存在一定的空闲内存,但是其小于Redis所申请的内存量,自然会出现无法分配内存的故障。

故障解决

Redis的持久化机制数据回写方式包括同步回写和异步回写。对于前者来说,Redis对应执行的是SAVE命令,即由Redis主进程直接将数据写入磁盘。当写入的数据量较大时,该命令将阻塞主进程,导致客户端无法连接Redis,只有当SAVE操作完成后,主进程才开始工作,客户端才可以正常连接Redis。

对于后者来说,实际上和Redis的BGSAVE命令对应。即Redis主进程通过fork一个子进程,复制主进程的内存并通过子进程将数据写入到磁盘中。

在执行BGSAVE命令过程中,并不影响Redis主进程,客户端可以正常连接Redis,等子进程fork执行存储完成后,通知主进程并关闭子进程。

根据在Redis配置文件,可以看到当满足了自动触发Redis数据持久化到磁盘的策略时,Redis就会后台调用BGSAVE命令,BGSAVE命令需要fork一个子进程,这就相当于复制了一个Redis主进程的内存镜像。该服务器的物理内存是16GB,因为Redis主进程占用了最大10GB内存,对应的由BGSAVE命令行fork的子进程也需占用了最大10GB内存。

这样,Redis就需要最大的内存量就变成了20GB内存,该机的物理内存显然无法满足该要求,所以才出现无法分配内存的故障,这必然导致Redis无法向磁盘写入数据的问题。

根据以上分析,解决问题最直接的方法是对Redis的配置文件进行修改,将“maxmemory 10GB”配置项进行修改,降低其最大内存使用量,例如修改为“maxmemory 5GB”等。之后执行“/etc/init.d/redisserver restart”之类的命令来重启Redis,让配置生效。也可以增加该机的而无力内存量,例如将物理内存增加到32GB,来满足实际的需要。

猜你喜欢

磁盘命令进程
只听主人的命令
它的好 它的坏 详解动态磁盘
安装和启动Docker
创建虚拟机磁盘方式的选择
债券市场对外开放的进程与展望
解决Windows磁盘签名冲突
改革开放进程中的国际收支统计
移防命令下达后
Windows系统下动态磁盘卷的分析与研究
解析Windows10的内部命令