PHP RabbitMQ连接超时问题

问题背景

Error: The connection timed out after 3 sec while awaiting incoming data

看到这个报错,我不以为意,认为是我设置的超时时间不够导致的,那就设置长一点

Error: The connection timed out after 300 sec while awaiting incoming data

当我等待了300秒看到了这个报错,我眉头一皱,此事比不简单。

错误分析

很明显这个问题有几种可能,我一一排查

因为我是从测试环境转到生产环境的,代码一样,测试环境没有问题,只是RabbitMQ不一样。

首先测试MQ是否能通

使用telnet 命令测试,发现不能通,原来是生产环境的MQ加了IP限制。把IP加到白名单后能通,但是代码连接仍然超时。

测试我怀疑是不是给过来的端口不对,因为测试环境的端口是5672,这个是默认端口,而生产环境的端口是5671,修改端口后发现端口不通,连接失败,拒绝连接。那就端口没有问题

接着我认为可能是账号密码不对,修改后发现报错还是超时,说明代码都还没连上RabbitMQ。
连接代码

此时我去网上寻找答案,恰巧也有人跟我遇到了类似的问题,在github上向开发者提了Issuses

PHP 致命错误:未捕获的异常"PhpAmqpLib\Exception\AMQPTimeoutException",并显示消息"在等待传入数据时,连接在 3 秒后超时" ·问题 #839 ·php-amqplib/php-amqplib ·GitHub的

其中这个提问跟我遇到的问题完全一致

扩展的开发者也对这个问题进行了答复,从这里我就知道这个问题跟SSL有关系了,同时还提供了样例php-amqplib/demo/ssl_connection.php at master · php-amqplib/php-amqplib · GitHub

根据这个样例不难看出是要我们使用ssl进行连接,因为MQ的5671端口是支持SSL的。

可是很多人都跟我一样,没有这个证书,或者说即使有也不知道怎么使用。确实,我也是一脸懵,就像开发者说的,你需要深入学习一下TLS/SSL的工作原理

当然了,这都不是我们的重点,重点是解决当前遇到的问题。

有了样例,那我们直接拿过来用

php 复制代码
$sslOptions = array(
    'cafile' => CERTS_PATH . '/ca_certificate.pem',
    'local_cert' => CERTS_PATH . '/client_certificate.pem',
    'local_pk' => CERTS_PATH . '/client_key.pem',
    'verify_peer' => true,
    'verify_peer_name' => false,
);

$connection = new AMQPSSLConnection(HOST, 5671, USER, PASS, VHOST, $sslOptions);

此时会发现能连上了,但是运行会提示一个信息

不是吧!我刚找的解决方案你就打算弃用了,也不难理解。为什么同样是连接却要用两种方法实现,随着我查看源码我就发现了。

先看最开始连接的方法:AMQPStreamConnection

一般很少人会去看这个,因为这个方法只有前面4个参数是必填的,后面都有默认值,例如最开始报错超时3秒也是在这设置。这里我们就看到在参数里篇有个$ssl_protocol和?AMQPConnectionConfig $config两个参数,不难看出这个就是能够支持SSL的,这也是AMQPSSLConnection方法会弃用的原因,不然我本地用着AMQPStreamConnection方法好好的,到其他地方,用不了了。

知道了AMQPStreamConnection可以支持SSL了,我们看一下AMQPConnectionConfig类

这个类是用来设置连接参数的

根据样例我们不难设置这个ssl相关的数据,不过因为我没有证书,所以自然不用去管这个。

接下来回头看看支持SSL的类AMQPSSLConnection

对的,你没看错,AMQPSSLConnection继承了AMQPStreamConnection,合着搞了大半天你们本来就是一起的。这里我们看到$ssl_options参数就是样例中ssl参数配置的位置

弄完之后AMQPSSLConnection又构建父类初始化,就是还是AMQPSSLConnection,把ssl参数加上,加的参数位置是$context,直接把方法拿过来用就可以了

AMQPSSLConnection并没有用AMQPConnectionConfig来设置ssl参数,那我们也可以不用,直接整

解决方案

php 复制代码
        $sslOptions = array(
            'verify_peer' => false,
        );
        $ssl_context = stream_context_create();
        foreach ($sslOptions as $k => $v) {
            stream_context_set_option($ssl_context, 'ssl', $k, $v);
        }
        
        $connection = new \PhpAmqpLib\Connection\AMQPStreamConnection(
            $config['host'],
            $config['port'],
            $config['user'],
            $config['password'],
            '/',
            false,
            'AMQPLAIN',
            null,
            'en_US',
            3.0,
            3.0,
            $ssl_context
        );

看到没,verify_peer设置为false,是不是很眼熟,就是平时我们在https请求时忽略证书校验那样。至于AMQPConnectionConfig类设置参数这个我就不再细细研究了,原理是一样的。

verify_peer:验证证书是否对等,也就是是否需要校验证书的意思,设置为true就是要校验。

要校验就申请CA证书或者自签证书,放在参数里即可。

我这都没给我提供就懒得去折腾了,解决问题即可,遇到问题我们再解决。

相关推荐
Kika写代码3 小时前
【大数据技术基础】 课程 第1章 大数据技术概述 大数据基础编程、实验和案例教程(第2版)
java·大数据·数据仓库·hive·分布式·spark
nchu可乐百香果3 小时前
spark-sql配置教程
大数据·分布式·spark
The博宇11 小时前
Spark常问面试题---项目总结
大数据·分布式·spark
冧轩在努力11 小时前
redis的应用--分布式锁
数据库·redis·分布式
AI航海家(Ethan)11 小时前
分布式爬虫那些事儿
分布式·爬虫
java1234_小锋12 小时前
Zookeeper的通知机制是什么?
分布式·zookeeper·云原生
喝醉酒的小白13 小时前
Kafka 数据写入问题
分布式·kafka
baozhengw13 小时前
IntelliJ+SpringBoot项目实战(23)--整合RabbitMQ
spring boot·rabbitmq·java-rabbitmq·消息中间件
晚风 -13 小时前
SprinBoot整合KafKa的使用(详解)
spring boot·分布式·kafka