Chinaunix首页 | 论坛 | 博客
  • 博客访问: 152086
  • 博文数量: 10
  • 博客积分: 207
  • 博客等级: 入伍新兵
  • 技术积分: 380
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-10 12:44
文章存档

2015年(2)

2013年(1)

2012年(7)

我的朋友

分类: 系统运维

2015-01-24 23:26:51

博客密码找回来了,心血来潮,又准备写写了。。
前几日在使用我们自己修改过的多线程redis的过程中, 出现几千qps就把redis压死了的情况。。与预期严重不符。
我们使用的时候每个key,value都会设置一个ttl,而这个ttl很段,一般几十秒到几分钟

现象:
1.    登陆上去瞅了下mpstat 命令看到各cpu %50左右都处于%sys,
2.    sar 命令看到每秒收包1万个,但是出包只有几百个。
3.    通过perf top看到锁占用非常高

进入看发现

可以看到这个是个系统调用产生的,可以看到这个锁在内核态,
问题在于我们修改之后的redis中也没有什么地方调用这种锁,关键是我们调用锁的地方,perf里面也没有显示。
那么说明我们使用的redis程序中,某个函数可能通过glibc发起了锁操作的系统调用
也就是说我们的程序不一定使用了锁,但是通过glibc提供的某个函数,导致了锁的产生
进到uRedis程序中,看到

瓶颈在于dictGetRandomKey这个函数,
查看代码发现activeExpireCycle会调用dictGetRandomKey,而dictGetRandomKey又会调用glibc的random()函数,
难道是glibc的这个random()
函数有问题?
网上随便搜了下,有讲到glibc里面random() 函数使用了锁,good,接下来需要验证一下准确性
rpm -qa|grep glibc 查看到我们当前使用的是glibc-2.12,下载glibc-2.12的tar包下来,查找random()函数到达咋写的

good,glibc的random()函数是__random()的别名,最终调用上面这段代码
基本可以确定就是这个问题了。
问题归结为:
我们使用的多线程redis,每个线程在处理过期key的时候,每个线程通过redis的函数dictGetRandomKey调用了glibc的random()函数,而random()函数里面有锁导致各线程阻塞,内核态自旋锁飙高,%sys就高了。

问题明确了,那么我们可以修改dictGetRandomKey()函数去掉对random()的调用,改为顺序从头到尾调用(每次记住上次更新的位置),或者每个线程搞一个random变量,再启动一个线程,专门调用glibc()的random(),把结果不停的写到各线程的random变量里边去就行了。
修改了下,问题解决,服务恢复正常,进出包基本持平,整体cpu利用率%1.5左右。

问题:我们在压力测试的时候关注set key对应的ttl 设置和实际运用不太一样,测试的时候只set/get key,value,结果流量一上来就出问题了。。前期工作没做好。。
阅读(4397) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~