Magento2 main.ERROR: Broken pipe or closed connection错误信息解决方法
1. 场景描述:
Magento2.4.1 使用rabbitmq 3.8.x,连接时出现管道破裂或关闭连接(/var/log/system.log)
2. 排查问题与了解AMQP原理
AMQP (Advanced Message Queuing Protocol) 是一种网络协议,它用于在应用程序之间传输异步消息。在使用 AMQP 时,有两种参数可以帮助保持连接的活动状态。这两种参数是 heartbeat 和 keepalive。
Heartbeat 是 AMQP 协议的一部分,它允许客户端和服务器之间定期发送消息以保持连接的活动状态。当客户端和服务器之间的连接空闲时,会启用 heartbeat 机制。如果服务器在 heartbeat 时间内没有收到客户端的响应,则会认为客户端已经无响应,关闭连接。
Keepalive 是操作系统级别的参数,它允许操作系统在网络连接空闲时发送保持活动状态的消息。Keepalive 参数可以设置操作系统发送 keepalive 消息的频率和超时时间。当操作系统发送 keepalive 消息时,它会检测网络连接是否正常,并确保连接处于活动状态。如果操作系统在 keepalive 时间内没有收到响应,则会认为连接已经关闭。
总的来说,heartbeat 和 keepalive 参数都是用来保持连接的活动状态的。Heartbeat 是 AMQP 协议的一部分,它在应用程序层面上保持连接的活动状态,而 keepalive 是操作系统级别的参数,它在操作系统层面上保持连接的活动状态。
AMQP heartbeat 参数指定了客户端和服务器之间定期发送的心跳消息的间隔时间,这个间隔时间是以秒为单位的。在AMQP协议中,这个heartbeat参数的默认值是60秒,但是可以根据具体的需求进行配置。如果heartbeat时间过长,则可能会导致连接在长时间的空闲期之后被关闭,如果heartbeat时间过短,则可能会影响到网络带宽的使用。因此,在设置heartbeat参数时,需要根据实际情况进行调整,以保证连接的可靠性和网络性能。
AMQP keepalive 参数被设置为60秒。这意味着在网络空闲期间,操作系统将会发送 keepalive 消息,以保持连接处于活动状态。
需要注意的是,在 Magento 2 中,AMQP 连接的 keepalive 参数是通过设置操作系统级别的 TCP keepalive 参数来实现的。因此,在设置 keepalive 参数时,需要确保操作系统也已经正确地配置了相应的参数。
在 Magento 2 中,可以通过在 app/etc/env.php 文件中添加 AMQP 连接配置参数来设置 keepalive 参数。以下是一个示例配置:
'queue' => [
'amqp' => [
'host' => 'localhost',
'port' => '5672',
'user' => 'guest',
'password' => 'guest',
'virtualhost' => '/',
'ssl' => 'false',
'heartbeat' => '30',
'connection_timeout' => '30',
'retry_delay' => '5',
'max_retries' => '3',
'keepalive' => '60',
],
],
当然,使用env.php配置的方式我有尝试过,但貌似无效,暂时还没查到原因,要是有大神知道请指教。那我接着讲我的解决方法吧。
3. 解决方法
在vendor/magento/framework-amqp/Connection/Factory.php中
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\Framework\Amqp\Connection;
use Magento\Framework\App\ObjectManager;
use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Connection\AMQPSSLConnection;
use PhpAmqpLib\Connection\AMQPStreamConnection;
/**
* Create connection based on options.
*/
class Factory
{
/**
* Create connection according to given options.
*
* @param FactoryOptions $options
* @return AbstractConnection
*/
public function create(FactoryOptions $options): AbstractConnection
{
$connectionType = $options->isSslEnabled() ? AMQPSSLConnection::class : AMQPStreamConnection::class;
$parameters = [
'host' => $options->getHost(),
'port' => $options->getPort(),
'user' => $options->getUsername(),
'password' => $options->getPassword(),
'vhost' => $options->getVirtualHost() !== null ? $options->getVirtualHost() : '/',
/*
* keepalive开启
* heartbeat频率设定10秒
*/
'keepalive' => true,
'heartbeat' => 10,
];
if ($options->isSslEnabled()) {
$parameters['ssl_options'] = $options->getSslOptions() !== null
? $options->getSslOptions()
: ['verify_peer' => true];
}
return ObjectManager::getInstance()->create($connectionType, $parameters);
}
}