软件开发: 04 2010存档

我们的消息中间件,要在每个通信的机器上启一个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设成高优先级不能解决问题——优先级虽高,但终究是要睡的。

我的结论就是这样,最后的证明还是要看看内核代码了。未完待续。

1. read与recv

read和recv的语义有差别。read主要用来读文件,recv主要用来读socket,如果非要混用也可以,但有些细节就很磨人:

对着socket(异步的)调用read时,如果返回0,说明数据已经拿完了;而对这个socket调用recv时,如果返回0,说明该链接已经关闭了。

2. TCP_NODELAY

 通常我们记得对于connect到server的socket设上TCP_NODELAY,却忘了accept出来的新socekt也需要设上TCP_NODELAY