踩坑redis混部,导致AOF写磁盘过多,导致影响其他实例。通过与sre协作、分析日志,解决了问题。

背景

组内维护了一个较老的服务,从22年10月国庆开始,偶发出现了redis相关报错。

报错示例:

1
2
org.springframework.data.redis.cache.RedisCacheManager|-1|redis异常:key=[QueryParam(codeList=[3149904936829982727], codeType=2)|], exception=Could not get a resource from the pool; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
org.springframework.dao.InvalidDataAccessApiUsageException: Could not get a resource from the pool; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool

这个服务的这种报错,以假期的规律出现,比如国庆假期第一天上午,开始频繁报警。

同周期出现的,还有另一个报错:

1
org.springframework.data.redis.cache.RedisCacheManager|-1|redis异常:key=[XL18332|440300|], exception=java.net.SocketTimeoutException: Read timed out; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out",

对应报错的接口是一个资质查询的缓存。一周维度的请求数据为:

近一周总访问量 12,595,893qps 352

分析

分析日志

首先通过日志,可以看到报错给出两个信息:

  • 拿不到连接
    • 可能的原因:
      • Redis宕机了。
      • 应用使用了比服务端连接池更多的连接。
      • 应用使用完连接后,没及时释放连接资源。
  • 连接超时
    • 读取响应超时,可能的原因:
      • Redis服务器的资源利用率过高或内存不足。
      • Redis连接池配置错误,导致连接过多或连接过少。
      • Redis客户端未启用自动断开连接功能,导致连接空闲时间过长。
      • Redis命令执行时间过长,例如在BLPOP操作时,阻塞等待响应时间超过了socket_timeout设置的时间。
      • Redis建立连接超时时间过短,例如socket_connect_timeout设置的时间过短。

排查应用流量

观察到报错随着假期(高峰期)的周期出现,于是通过日志平台与监控验证下我们服务的流量是否有高峰激增。

日志、监控显示,我们的流量并没有激增太多。结合背景部分的具体数据,qps 352 对于Redis即使是单实例也完全形不成压力。

所以问题流量并没经过我们这个服务。

那么这就奇怪了!!!

与sre协作

本服务内找不到问题,尝试找sre,看看有没有什么有效信息。

一问,sre给出了关键日志:

1
Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.

如果熟悉Redis,可以get到,此时我们的Redis实例正被阻塞于AOF fsync写文件的操作上,但是由于磁盘IO过高,磁盘此时压力过大, fsync一直卡着。

这也是导致我们的服务一直拿不到Redis连接的直接原因!

接着我们验证了服务对应RedisAOF写入量,发现并不多!这就奇怪了!

再次询问sre,得知这台Redis与其他20+个实例混合部署在同一台机器上。

此时,所有疑点都明朗了。

破案

我们的Redis由于与其他20+个实例混部在同一台机器上,其他实例流量激增导致磁盘压力过大,导致我们的实例迟迟无法获取到IO权限。

服务端这边也迟迟拿不到连接,看到的假象就是Redis停止服务!

解决

捋清脉络,并且与相关干系人快速沟通后,我们决定切换Redis实例到独立的机器上。

操作后,此报错在多个假期未出现,问题解决!

Ref