03 May 2018

在一个项目里,写过下面的一段小代码,没想到是个坑

$content = file_get_contens("http://path/to/file.tar.gz");
...

在 rabbitmq 的 consumer 里面去执行这段代码,获取压缩文件的内容,然后解压..

测试的时候好好的,线上跑了一段时间也没问题。但是,有时候会突然反馈说用户一直卡在那个页面不动了。看了下 rabbitmq 里面的内容,发现是某个消息没被 ack

搜了下,感觉是 rabbitmq 网络的原因造成的,就重启了 consumer,过了些天又出现了

会不会是 php rabbitmq 的 bug,然后我把 rabbitmq 改为了自动 ack。过了几天,发现问题还是存在

看了下 consumer 还在,就用 strace 去跟了一下,发现没什么用(我不会用)。觉得不行,尝试用 gdb

➜ gdb -p $PID
(gdb) source /path/to/php-src/.gdbinit
(gdb) zbacktrace

然后看到了 consumer 卡死在了 file_get_contens 这个函数上

本来是个小功能,觉得就不用 curl 那套去实现了,直接 file_get_contens 一行代码搞定。没想到就是这一行代码把整个服务卡住了。。。

又搜了下,确实是有这个问题的。奇怪的是,我用命令行去跑 file_get_contens 就算失败,也不会卡住,暂时没想到是什么原因。可能是 rabbitmq consumer 和 file_get_contens 一起跑的时候就会有这个问题。

解决的办法也很简单,在获取 FILE.tar.gz 的时候加个超时,如果失败,提示用户重试

教训:

  1. 网络请求要加上 timeout 参数
  2. php 和 gdb 调试代码可以用来调试代码死循环或者卡住的问题