Redis OOM问题排查

Posted by Night Field's Blog on November 9, 2019

问题描述

看到Redis报了OOM的错误,而且服务响应速度非常慢,页面上丢了很多数据,赶紧起来查看问题。

问题排查

我们的系统架构是双边双活的,两个DC都会有数据写进来,通过API把数据存到数据库(双边数据库有复制),同时写到Redis队列一份(这里把Redis当成MQ来用),然后有个Job从redis队列里面把数据取出来,写到两边,流式地处理数据。对于Redis队列来说,API是生产者,Job是消费者。这次只是GSB这边的Redis出了问题,导致了单边不可用。

架构简图

1. 问题定位

一般Redis里的元数据大小是比较稳定的,出现OOM应该先看队列的大小。果然这个数据队列的size已经远远超过了阈值。我们先把队列清空了,然后把数据读取从Redis切换到了DB,GSB侧终于能正常工作了。

2. 进一步跟踪

现在我们的数据量一般是每秒钟三四百条左右,按理来说Job的消费速度肯定是能跟上的。但是看问题侧(GSB侧)队列大小大致呈每秒钟一百条的速度在递增。看了一下GSB侧Job的log,发现消费速度很不稳定,最慢的时候一秒钟只能处理三四十条。按照Redis官方百万级的QPS,这简直可以用龟速来形容了。接下来我们来看具体慢在哪里。可以用

redis-cli –latency -h host -p port

命令来查看命令的延迟情况,此命令会不断给Redis发ping命令然后统计响应时间。先来看本机延时对比:

Primary本机延时

GSB本机延时

通过在Redis本机上通过latency的对比,发现Primary侧和GSB侧的延时接近一致,一个是0.04ms,一个是0.05ms,看来瓶颈不在Redis本身。再来对比一下从其他机器上连Redis的延时情况:

Primary网络延时

GSB网络延时

可以看出来,GSB侧的Redis响应速度明显比Primary侧的慢,一个是0.37ms,一个是1.67ms,有近四五倍的差距。但是按理来说网络速度慢,应该影响到生产者和消费者双方,为什么数据还是能不断堆积呢?这是因为我们API有四台机器,而Job只有一台机器,导致了消费速度跟不上。

3. 问题解决

找到了root cause之后,赶紧联系Network Team,被告知GSB侧有一个Network的Incident,估计就是这次问题的元凶了。我们改了一下代码,检测如果队列大小超过一定的阈值,就删除一部分数据。虽然会导致部分缓存数据的丢失,但是为了不影响到系统的整体可用性,也只能这么做了。

果然第二天,Incident结束了之后,Job的消费速度就恢复正常了。

总结

网络问题导致Redis的响应时间变慢,而且生产者数量比消费者数量多,导致Redis队列数据消费不完,队列堆积,从而OOM。通过这次事件,我们得到教训:

  1. 最好不要用Redis做MQ来用,否则当队列堆积会造成Redis整体不可用,最终导致系统不可用。
  2. 生产者和消费者的数量要大致对等,否则要么会出现任务堆积,要么会出现性能资源浪费。