超时问题调研
我们的消息中间件,要在每个通信的机器上启一个daemon,负责转发。我们还为这个中间件开发了php接口(尽管我并不看好php,但它毕竟是前端的常用语言)。
在 处理业务部门反馈的问题时,发现一个奇特的现象:php程序通过中间件收发消息,设置是3ms超时,运行正常,没有超时的消息;但如果在php里加一个循 环(加循环的位置与中间件的调用无关),超时出现了。php自己傻循环怎么会影响中间件消息的response time呢?
先是怀疑我们的php module写得不对,参考了一下别人的代码,发现没有什么特别的,用的是极简单的php module API,如果这样写都不对,真不知道什么是对的了。
再 是怀疑php本身,于是换了几个php版本(php接口也要重新编译,累人),问题依然出现。再把我们的中间件API加入php的 basic_function里,即做为php的内置函数(就像split,sleep这些函数一样),问题还是一样。可能不是php的问题。
接着怀疑apache,于是降低apache的进程数,发现httpd进程数为1或2的时候真的没有超时了,但进程数如果多于3就不行。难道apache的调度有问题?我们默认用的是prefork任务模式,换成worker试试(参见这里),换mpm了,php给apache的so也要重新编译(还是累人),最后发现换成worker任务内模式当进程数多了还是一样超时。
难道和php、apache都没有关系?干脆启动两个独立的php进程,没有超时;启动3个,没有超时;启动4个,超时来了。看来4这个数字很神秘。最后猜测是机器乃4核CPU,4个php进程占完了4个CPU,中间件daemon就没有保障了。
这个猜测有点跳跃,要想办法证明之,于是想到了CPU affinity,我们用taskset把4个php进程都绑定到0,1,2三个CPU上,此时超时消失了。看来之前确实是php进程占了4个CPU,导致中间件daemon无法足够快的分配到CPU。
解决方案呢?
如果我改改daemon,是不是能解决这个问题?于是把daemon的优先级设为最高(RT),超时依旧。
仔 细想想有了个结论:daemon用的CPU并不多,但是其睡眠和唤醒非常频繁(daemon主要是IO操作,转发来自网络的包),当其从睡眠中醒来时,必 须很快分配给它一个CPU,但是php占了4个CPU,所以不能很快的给daemon,所以daemon出现了延时(睡过头了),造成消息超时。这大概能 说明为什么把daemon设成高优先级不能解决问题——优先级虽高,但终究是要睡的。
我的结论就是这样,最后的证明还是要看看内核代码了。未完待续。
相关文章
- 《独辟蹊径品内核》 - 02 07, 2010
- [linux-kernel] tcp连接在断网后的恢复能力 - 01 14, 2010
- “我能见一下为我做这份晚餐的厨师吗?” - 01 08, 2010
很复杂的东西
个人认为, Linux里面10毫秒一个时间片,如果中间没有其他的硬件中断或者主动让出CPU是不可能发生进程切换的。
你说的没有错。
但问题在于,我们的daemon要频繁的等待IO,所以进程自己会经常去睡眠。而问题就发生在它醒来的时候——无法每次都快速醒来(当然,目前还是猜测 )。
不知道这个问题最终的原因是不是进程切换的问题?
linux里面高优先级的线程不会抢占吗?
阁下点中要害了,仔细想来,确实是只要有进程切换就会超时,跟优先级高低似乎没有关系。
请问DongHao兄这个问题最终查出的原因是预想的那样吗?Linux内核不能抢占吗?
Linux内核肯定是能抢占的,目前为止我怀疑的可能是:
1. rhel5的老调度算法给高优先级进程的优先度不够
或者:
2. 只要进程切换,必然就拖慢
可以安装新的内核或改用bfs patch来验证第一条怀疑,但是一直没时间再弄了。
以后再抽空。
记不起来是搜什么东西的时候看到这个文章了,没想到随手问了一下,DongHao兄就回复了。
我是做嵌入式方面的,接触的都是一些RTOS,所以考虑的角度可能和DongHao兄不一样:
1 linux的tick是10ms,php设置3ms超时,也就是说当前请求发出后,如果下一个被调度运行的不是daemon的话,就超时了;当然4核的情况下如果可以在其他的核上执行daemon,不会发生超时。如果所有的核都被占用了呢?这个时候就和抢占以及优先级有关了。
2 如果在一个rtos里,daemon的优先级高,那么只有daemon ready,它马上就可以打断其他的任务得到CPU(当然其他任务不能在执行临界代码),和上面说的有空闲的cpu其实差不多。
linux我只是了解,它的任务优先级和抢占是什么样的策略我不知道,下面的是猜测:
3 php请求daemon的服务之后是sleep了吗?如果是的,应该会引起重新调度,这个时候如果daemon的优先级高,应该会在调度中得到cpu而运行,应该也不会超时;
4 如果php请求daemon服务之后没有sleep,而linux的抢占又不是那种“rtos式”的抢占,很可能daemon还没运行的时候php那边已经“等得不耐烦”(超时)了……
感谢ip2004兄的分析,看来细节还有很多啊。。。