环境
分别使用了三个库使用RabbitMq。
- 使用python的pika库,适用于python。
- 使用rabbitmq-c库,-lrabbitmq,适用于c/c++语言。
- 使用AMQP-CPP库,-lamqpcpp,适用于c++。
主要对使用过程中出现的调试错误进行小结,适合新手参考。
pika库
- pika.exceptions.ProbableAuthenticationError: ConnectionClosedByBroker: (403) ‘ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.’
- 登录信息不全,需要使用用户名和密码登录。或者用户名、密码不正确。
如,connection = pika.BlockingConnection(pika.ConnectionParameters(host='192.168.1.2'))
,未使用用户名和密码等登录参数。可以参考下面的代码片段:
#!/usr/bin/env python
import pika
credentials = pika.PlainCredentials('the_user', 'the_pass')
parameters = pika.ConnectionParameters('132.45.23.14',
5672,
'/',
credentials)
connection = pika.BlockingConnection(parameters)
- pika.exceptions.ProbableAccessDeniedError: StreamLostError: (“Stream connection lost: ConnectionResetError(10054, ‘远程主机强迫关闭了一个现有的连接。’, None, 10054, None)”,)
- 服务未对该用户开放相关的权限,如 Virtual Host权限。需要登录服务端开放开头权限,以 Virtual Host权限为例:
- 启动web管理服务:在安装目录执行:
rabbitmq-plugins enable rabbitmq_management
- 在浏览器中输入
http://127.0.0.1:15672
,使用默认的用户名和密码登录:‘guest’, ‘guest’ - 增加一个新用户
- 点击用户名,点击开通权限即可
- 启动web管理服务:在安装目录执行:
- pika.adapters.utils.connection_workflow.AMQPConnectorStackTimeout: Timeout during AMQP handshake’192.168.1.33’/(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, ‘’, (‘192.168.1.33’, 15672)); ssl=False
- 超时错误,可能是填写的端口号不正确
- pika.exceptions.ChannelClosedByBroker: (406, “PRECONDITION_FAILED - inequivalent arg ‘durable’ for exchange ‘CLP_STG’ in vhost ‘/’: received ‘false’ but current is ‘true’”)
- 创建Exchange时,该Exchange已经存在,且本次创建时使用的参数与之前不符。具体到本异常,为
durable
属性设置的值不同。durable
属性默认为false,无消息持久化特性- 创建Exchange时使用
durable=True
设置为true,使用消息持久化特性
rabbitmq-c库
- open channel error: server channel error 406h, message: PRECONDITION_FAILED - unknown delivery tag 1
- 消费者关闭了默认的ack机制,但仍然发送了ack,或者使用了ack,但发送ack时未使用与接收消息相同的通道
- 调用 amqp_channel_open 函数后,在管理界面查看通道已经打开,但该函数阻塞,一直未返回
- 可能是在多线程中使用了同一个连接,或者多线程使用了同一个通道。在我的测试中,多线程使用同一个连接时,即使通道不同,也会出现该问题
- 详情可以参考 amqp_channel_open issue
AMQP-CPP库
使用libevent事件驱动库。
- 执行了一系列创建工作,但在管理后台上查看时并未创建。
- 所有的指令会在事件循环启动后执行,所以需要启动
event_base_dispatch(evbase);
循环 - 当持续有需要监听的事件时,该循环不会退出,所以不要在主进程中启动它,在线程中启动
- 如何注册事件回调函数
- 所有的操作都是异步的,所以执行某指令后返回的值并不能判断该指令执行成功,需要注册回调函数,以及时处理错误
- AMQP-CPP库内部使用的是类似
std::function<void(void)>
形式的回调函数,在传入时使用std::bind
即可,参数使用占位符表示,如:
m_channel->publish(exchangeName, routingKey, msg)
.onError(std::bind(&Foo::PublishMsgErrCb, this, std::placeholders::_1));
- 报错:UNEXPECTED_FRAME - expected content header for class 60, got non content header frame instead
- 在功能测试通过的情况下,在压力测试下出现这个问题
- 经过调试,是多个线程使用了同一个通道造成的问题。在RabbitMq中,connection是线程安全的,但channel不能多个线程共用一个。
- 为不同的线程开启了不同的channel,问题解决
版权声明:本文为guotianqing原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。