IT技术博客大学习 共学习 共进步

本周扑火之 redis 不给力

福林雨-博客 2011-05-25 12:35:12 浏览 5,143 次

    Social Graph 高速接口,当前我们使用 Redis 存储。但在实现的过程中,发现了诸多的问题。

    48G 内存的机器上部署了 2 个 Redis 进程,一个 Redis 占用超过 21 G 内存后,在快速写入的过程中同时进行一次 bgsave ,就将机器给弄挂了(微博上的直播)。我们对 Redis 的监控远不如对 Mysql 之类的完善,以至于 Redis 机器假死,居然没有触发任何的报警。

    在经过几天的 debug 后,终于找到了问题所在,复杂的上线流程:源码 svn 合 trunk,发布 jar 包到二进制 svn,配置文件按 IDC 配置,打 tag,上线,发布,终于有一个小小的地方没有控制住,没有进行最终的确认,导致发到线上的配置文件是源码目录中的测试配置,导致 redis hash 出错。而严重缺乏的监控,也没能发挥“最后一道防线”的作用,任由问题越演越烈(微博上的直播)。

    按说找到了问题所在,修复起来就很容易了。但 billion 级别的数据,重新初始化,远比想象的复杂。从上周五开始重新灌数据,周六在家习惯性的用 iphone 登陆看 log 。一看吓一跳:按那个速度计算,重新初始化需要一个月才能完成。而第一次初始化,才花了几十个小时啊。

    首先怀疑是资源的问题:打电话找运维,确认 redis 没有问题,数据库没有问题,queue 队列没有问题。那就是程序的问题了。用 Btrace 一层一层的跟踪,最后定位在 jedis.hset 和 jedis.hdel 上:一次 hset 或 hget 居然需要超过 100 ms (微博上的记录)。周一到单位,给代码加了详细的时间 log ,也印证了周末 Btrace 的结果。这是为什么呢?

    还是怀疑 redis 服务器的问题。写了一个简单的压力测试代码去压测试用的redis,在本机上运行,果然每秒才 4000 来次 hget、hset 。可是拿到服务器上一跑,轻松的就到了 4 万多次。所以本机上慢,应该是网络带宽的原因。

    接下来只能怀疑是程序代码的问题。但在测试环境下回滚版本,换客户端库,各种手段用完都找不到问题之后,只能将目光转向线上环境。 

    直接用压力测试代码压线上服务器,果然也慢。继续看 log ,似乎慢的请求有一个共性:某个时间点,几十个请求的耗时是一样的,都是类似 127ms,132ms 这样的。如果是真实的处理耗时,不应该会如此雷同才对,那么就应该是排队等待耗时了。这一批请求应该是同时发起的,因为某种原因,一同在某个地方排队,等轮到它们的时候,真实的处理耗费的时间连 1 ms 都不到,所以在 log 里看来,耗时如此相似。接下来的问题就是,为什么会排队?在哪排队?后面一个问题比较好回答,Redis 是单线程的,按照网络接收到的包的顺序处理请求,前一个请求没有处理完之前,后面的请求都在 server 的 tcp/ip buffer 里排队,等待处理。那剩下的就只有一个问题了:为什么会有排队现象?

    仔细看业务代码,终于找到一个可疑的地方:hgetAll 。难道是一个 hgetAll 堵住了后面所有的请求?压测的脚本一般都只压 get,set,顶多也就试试 hget,hset,肯定不会压 hgetAll 这么变态的命令的。而用 strace 查看 redis server 的状态,也只能看到网络调用耗时。那么也就只能这么解释了:hgetAll 命令占用了大量的网络带宽,导致它完成之前,其它的命令的回包都在 tcp buffer 里面堵着了。

    试着修改了一下业务处理逻辑,减少了部分冗余的 hgetAll 调用,果然速度有所提升。虽然还是没有第一次的时候快,但好歹升到了一个可接受的范围了。

    接下来,就是重构 redis 相关的代码,让下次的 debug 不至于这么被动。有时间顺便在测试环境下重现一下这种情况,以确定自己的怀疑。

建议继续学习

  1. redis源代码分析 - persistence (阅读 32,104)
  2. Redis消息队列的若干实现方式 (阅读 11,927)
  3. 基于Redis构建系统的经验和教训 (阅读 10,383)
  4. 浅谈redis数据库的键值设计 (阅读 9,223)
  5. redis运维的一些知识点 (阅读 8,522)
  6. redis在大数据量下的压测表现 (阅读 8,203)
  7. Redis和Memcached的区别 (阅读 7,944)
  8. redis 运维实际经验纪录之一 (阅读 7,584)
  9. Redis作者谈Redis应用场景 (阅读 7,545)
  10. 记Redis那坑人的HGETALL (阅读 7,324)