场景:
PHP通过phpredis(https://github.com/phpredis/phpredis)循环执行如下操作:
1 2 3 4 5 6 7 8 |
<?php while(true) { $r = new Redis(); $r->connect(...); $r->auth(...); $r->set(...); $r->get(...); } |
发现connect会出现大量超过1s的情况,甚至超过3s;但是,如下图抓包所示:两次请求之间间隔了3s才发送syn请求,并且没有失败,也就是说,并非syn丢包所致,而是因为某种原因导致根本没有发送syn包;但是外部表现却是connect花费了很多时间(3s);
所以,从此推断,连接超时未必就一定是网络的问题,你们究竟会是什么原因导致client端3s后才发送syn的呢?
阅读源码发现: redis的connect用的是php提供的connect方法:php_stream_xport_create
其实,fsockopen用的也是该方法,如此的话,不放通过如下脚本直接测试connect:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php $errno = 0; $error = ""; $i = 0; while(true) { $i++; $time_start = microtime(1); $fp = fsockopen("10.172.90.108", 6379, $errno, $error, 5); $time_end = microtime(1); $time_use = $time_end - $time_start; if ($time_use > 1) { echo "timeout: $time_use ($i)\n"; } if ($fp) fclose($fp); } |
结果如下:
- connect超过1s的还挺不少的
- 前面300多次的时候连续出了好几次超过1s的,你们怎么会从374到13489一直没出错呢?而且,运行程序的时候也能感觉到,从第374到第13489花费时间很短的,难道这个区间根本没有发生真正的连接? strace 跟踪统计发现,确实connect了,就是说,一般情况下,connect是很快的
- 该问题可能发生在PHP中,也可能发生在glibc中,也可能发生在系统层面,排查办法:
- 写一个C的,如果不出现问题,那么就是PHP的问题;如果依然如此,很可能是系统问题