我目前正在做一个涉及嵌套api调用的项目。在我的项目中,我目前面临着一个死锁问题,我有点不知道如何调试这个问题。
设置
在我的设置中,我有两个仓库:
1.面向客户端的Laravel
1.内部Shopware 6
laravel项目将通过REST API调用。在一些API调用的情况下,Laravel将在内部调用Shopware以获取一些客户或店面信息。这些调用通过Guzzle进行。这在大多数测试用例中工作正常,但如果同时发出多个Laravel请求,则会失败。
问题
如果同时进行多个商店相关的API调用,Shopware将不再从Laravel项目接收这些内部调用。对Shopware的内部调用将被推迟,直到Laravel调用失败(由于存储请求超时)。一旦Laravel请求完成,看似排队的内部请求就会到达Shopware,但此时显然为时已晚,因为响应将不再被处理。
所以时间线看起来是这样的:
1.多个请求到达Laravel
- Laravel开始处理请求
- Laravel向Shopware发送内部请求
- Laravel由于超时而停止监听请求
- Laravel返回错误响应
- Shopware开始处理以前的请求
- Shopware完成请求,但Laravel不再侦听
假设
对于初始的Laravel请求,它似乎占用了所有可用的并发请求。因此,Laravel似乎无法发送内部请求到Shopware,直到初始请求(到Laravel)完成。因此,通过这种方式,会创建死锁,其中初始请求等待后续请求,而后续请求正在等待初始请求完成。
思考
有一段时间,我想知道是否在某个地方有一个锁--就像提到的here--它会阻止Shopware请求的执行。但我认为我可以排除这种情况,因为只有在同时发生多个嵌套Shopware调用时才会出现该问题。如果只有几个请求正在发生,那么请求将按预期发送。此外,我可以看到Shopware在Laravel请求完成之前根本不会被调用。由于index.php的第一行甚至没有被调用,我想我可以排除潜在的机制,包括锁。
我的猜测是我的系统达到了同时请求的极限。因此,内部请求将被排队,直到初始请求完成并且请求槽被释放。一旦槽变得可用,则随后将处理排队的请求。
不幸的是,我不知道如何明确地调试/证明我的猜测。我也试过几次试图解决这个问题,但到目前为止,我没有成功。因此,我将感谢任何提示,可以提示我一个解决方案。
尝试次数
我已经尝试增加MaxRequestWorkers
计数,以及其他一些参数。
<IfModule mpm_prefork_module>
StartServers 50
MinSpareServers 50
MaxSpareServers 150
MaxRequestWorkers 150
MaxConnectionsPerChild 5000
</IfModule>
- 结果**:无变化
我尝试将数据库存储在两个独立的MySQL设置中。MySQL 5中的Laravel数据库和MySQL 8中的Shopware,以避免可能的数据库锁定。
- 结果**:无变化
环境
- macOS Ventura
- MAMP Pro 6.6
- Apache 2.4.46
- MySQL 5.7.34
1条答案
按热度按时间q5lcpyga1#
我找到解决办法了!🎉
问题是FastCGI
PHP_FCGI_CHILDREN
配置。这控制了PHP进程产生多少子进程。当fastcgi启动时,它会创建许多子进程,这些子进程一次处理一个页面请求。值0表示PHP不会启动额外的进程,主进程将自己处理FastCGI请求。注意这个进程可能会死(因为PHP_FCGI_MAX_REQUESTS),并且它不会自动重生。值1及以上会强制PHP启动额外的进程来处理请求。主进程将在子进程死亡时重新启动子进程。因此,默认情况下,您将能够处理1个并发的PHP页面请求。其他请求将排队。增加这个数字将允许更好的并发性,特别是如果您有需要大量时间来创建的页面,或者提供大量数据(例如通过PHP下载大文件)。另一方面,运行更多的进程将使用更多的RAM,同时生成太多的PHP页面将意味着每个请求都将变慢。
此参数设置为
4
。因此,只要4个并发请求发送到Laravel,就不会产生进一步的子进程,从而导致前面描述的死锁。该值以
/Applications/MAMP/fcgi-bin/php8.1.0.fcgi
为单位定义我已经将值增加到
PHP_FCGI_CHILDREN=10
,这对于我的开发环境应该足够了,它解决了我的问题。