当前位置:首页 > 问答 > 正文

Redis老是断线宕机,排查原因和解决办法分享

最近在项目里,我们的Redis服务器像闹脾气一样,隔三差五就断线或者直接宕机,搞得整个应用都跟着抽风,经过一番折腾,总算把问题给解决了,今天就把我们排查问题的过程和最终的解决办法分享出来,希望能帮到遇到同样烦恼的朋友,这次经历让我深刻体会到,Redis虽然是个速度快、能力强的家伙,但要是没照顾好,它也会给你点颜色看看。

第一步:先别慌,看看日志说了什么

Redis一罢工,我们的第一反应就是去翻它的“日记”——也就是日志文件,Redis很诚实,基本上出了什么问题都会在日志里记上一笔,日志文件的位置通常在Redis的配置文件(redis.conf)里能找到,有个叫logfile的配置项就是它。

我们当时在日志里看到了好几种不同的错误信息,这也对应了不同的问题原因:

  1. “OOM command not allowed when used memory > 'maxmemory'”:这句话翻译过来就是,内存用爆了,不允许再执行命令了,这是我们遇到的最主要的问题,Redis就像一个柜子,你给它分配的空间(maxmemory)是有限的,如果数据一直往里塞,又不清理,柜子满了,新的东西就放不进去了,它就会拒绝服务,有时候甚至会触发Redis的淘汰机制,开始删掉一些旧数据,如果淘汰策略没设好或者根本就没设置,它就可能直接摆烂不干了。
  2. “Can't save in background: fork: Cannot allocate memory”:这个错误通常出现在Redis需要做持久化(就是把内存里的数据写到硬盘上备份)的时候,Redis创建子进程来干这个活,但创建子进程需要额外消耗内存,如果服务器本身物理内存就不够用,或者操作系统限制了一个进程能创建的内存大小(比如ulimit设置过低),这个“分身”过程就会失败,导致持久化做不了,严重时也会影响服务。
  3. “MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk”:这个错误是说,Redis被设置成要保存数据快照,但现在没法往硬盘里写了,这多半是磁盘空间满了,或者Redis进程对配置的持久化文件目录(dir)没有写的权限。
  4. 连接数过多:有时候日志里会提示客户端连接数超过了最大限制(maxclients),这可能是因为应用代码里有连接泄漏,就是打开了Redis连接用完没关,久而久之,连接池就被耗尽了,新的连接就进不来了。

第二步:顺藤摸瓜,多维度排查

光看日志还不够,我们得像侦探一样,从多个方面去找线索:

Redis老是断线宕机,排查原因和解决办法分享

  • 检查内存使用:我们用info memory这个Redis命令查看了详细的内存信息,果然,used_memory已经非常接近maxmemory了,这说明日志里报的内存不足是确确实实存在的。
  • 检查系统资源:我们登到Redis所在的服务器上,用free -h命令一看,发现整个服务器的物理内存也所剩无几,这不仅影响了Redis,其他程序也快喘不过气了,用df -h检查磁盘,发现有一个分区的空间使用率超过了90%,这解释了为什么持久化会失败。
  • 检查连接情况:用info clients命令看到连接数(connected_clients)确实很高,而且用netstat命令发现有很多连接处于CLOSE_WAIT状态,这通常意味着应用程序没有正确关闭连接,导致了泄漏。
  • 检查慢查询:用slowlog get命令查看有没有执行起来特别慢的命令,果然发现有几个同事写的复杂查询,一次性获取几十万条数据,或者用了模糊匹配(KEYS *)这种会拖慢整个服务器的操作。

第三步:对症下药,解决问题

找到原因后,解决办法就相对明确了:

  1. 解决内存爆满(最重要)

    • 设置合理的maxmemory并配置淘汰策略:我们根据服务器实际内存大小,给Redis设置了一个安全的上限(比如物理内存的70%),在配置文件里设置了淘汰策略maxmemory-policyallkeys-lru,这个策略的意思是,当内存快满时,自动淘汰掉最近最少使用的键,你也可以根据业务需求选择其他策略,比如只淘汰设定了过期时间的键(volatile-lru)。
    • 优化数据结构,清理无用数据:我们检查了业务代码,删掉了一批已经没用的缓存键,对于一些存储大对象(比如很大的JSON字符串)的场景,我们考虑是否可以用更节省内存的数据结构,比如Hash来分段存储。
    • 考虑集群方案:如果单机内存实在不够用,最终的解决方案是搭建Redis集群,把数据分片存储到多个实例上,这是解决内存问题的根本办法。
  2. 解决持久化失败

    Redis老是断线宕机,排查原因和解决办法分享

    • 清理磁盘空间:我们立刻清理了服务器上没用的日志文件和大文件,为Redis的持久化操作腾出足够的磁盘空间。
    • 检查目录权限:确保Redis进程用户对配置的持久化文件目录拥有读写权限。
  3. 解决连接数过多

    • 修复代码中的连接泄漏:这是治本的方法,我们检查了所有使用Redis的代码,确保每一次获取连接(getConnection)后,都在finally块中正确地关闭连接(close)。
    • 设置合理的超时时间:在Redis配置中调整timeout参数,让闲置过久的连接能自动断开,释放资源。
    • 适当调大maxclients:在服务器资源允许的情况下,可以适当增加最大连接数,但这只是临时缓解,根本还是要解决泄漏问题。
  4. 解决慢查询

    • 禁用危险命令:在生产环境,我们干脆在配置文件中用rename-commandKEYS *这种危险命令给禁用了,或者重命名成一个复杂的名字,防止误用。
    • 优化查询:让开发同事改写那些慢查询,比如用SCAN命令代替KEYS,避免一次性获取大量数据,做好分页。

总结一下

Redis断线宕机,十有八九是资源问题(内存、磁盘、连接数)引起的,排查的思路就是“一看日志,二查资源,三验代码”,平时要做好监控,时刻关注Redis的内存使用率、连接数等关键指标,别等出了问题才手忙脚乱,把Redis这个“大爷”伺候好了,它才能为你提供飞一般的速度。

(参考来源:日常运维经验、Redis官方文档、以及一些技术社区如Stack Overflow和CSDN上的相关讨论)