服务器是使用 nginx
+ php-fpm
的架构,redis用的是connect来连接,每个网络请求应该都会有单独的php-fpm
进程。我写了一个 循环,循环中有blPop/brPop
和 sleep(5)
。浏览器先后开了两个标签页跑,然后 lpush
了4个数据进 list
发现总是先跑的那个标签页能读到前两个数据。也就是说blPop/brPop
堵塞了整个服务器的所有其它侦听同一key的blPop/brPop
?
以下是我测试的代码:
//堵塞出队列
public function test(){
tool::load('hRedis.php');
$timeOut = 20;//堵塞20秒
$cn = 'test_blist';
$ress = [];
for($i=0;$i<2;$i++){
$ress[] = hRedis::cacheListBPop($cn,$timeOut);//这里面封装了redis的blPop/brPop
sleep(5);
}
print_r($ress);
}
为什么在 先跑的进程的sleep 期间,后跑的进程还会被堵塞?
又做了进一步的测试,把循环去掉了,每个进程只执行一次,并且每次读取完 使用 redis->close()
发现两个进程的结束时间,还是相差了16秒左右。
上一条测试,我又放到两台服务器上去测,这次不是同一台的两个进程了,而是两台服务器,发现两台服务器的结束时间,相差的秒数就是我插入两条数据相隔的时间!这次没有延迟了!
首先Redis是单线程的,任何发送到服务器端的请求都是排队按顺序执行. 所以你说的每个网络请求应该都会有单独的进程,我认为是不正确的.
blPop指令是阻塞客户端的,而非服务器端,不然对于单线程的Redis来说是致命的.
你打开两标签页后,就等于打开了2个客户端. 在你打开2个标签后没有push数据之前,这2个客户端都处于阻塞状态,你的阻塞时间设置了20秒.
当你push数据到list后,这2个客户端对同一个键执行brpop操作,那么最先执行brpop命令的客户端可以获取pop的值,也就是第1个标签页.sleep 5s,再pop一个数据, 之后就输出,第一个客户端执行完退出后,如果第二个客户端还在执行着pop那行的话,我想应该会输出后续的值的,如果2个客户端打开间隔很短,估计也就退出了. 你可以调整2个客户端的打开时间间隔测试一下. 然后告诉我答案. 谢谢
"网络请求应该都会有单独的进程"这句话有误,已经改成“每个网络请求应该都会有单独的
php-fpm
进程”。第二个问题是你说的那样,第二个客户端会输出后续的值,但是第二个客户端输出值的时间,比第一个客户端平均晚了16秒,我想知道为什么会晚这么多,能不能缩短?还有第二个客户端为什么不能和第一个客户端同时监听?