教程里“直接往队列发消息”其实是发给一个名字为空的 exchange。它是什么、有哪些限制、写错队列名会怎样、会比显式 exchange 更快吗?这篇一项项在 RabbitMQ 4.3.6 上验证。
$ rabbitmqctl list_queues name messages
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
name messages
hello 1
basic_get → ['hi']
$ rabbitmqctl list_bindings source_name destination_name routing_key
Listing bindings for vhost /...
source_name destination_name routing_key
hello hello
list_bindings 里的第一列为空串,就是默认 exchange;这个绑定不是我建的,队列一声明就有默认 exchange 的名字是空串,direct 类型。每个队列声明时 broker 自动给它加一个以队列名为 key 的绑定,所以 basic_publish(exchange='', routing_key=队列名) 就等于“直接发到这个队列”。这个绑定在 list_bindings 里能看到,删除队列时跟着消失。
不加 mandatory:发布没有任何错误,消息也没有去哪(没有这个队列) mandatory=True + confirm: UnroutableError: 1 unroutable message(s) returned 对存在的队列 mandatory=True: 成功
routing key 对不上任何队列时,消息被悄悄丢弃,发布方没有错误。要得到反馈需要 mandatory 加 publisher confirm(得到 UnroutableError)。
exchange_delete(""): ChannelClosedByBroker: (403, 'ACCESS_REFUSED - operation not permitted on the default exchange')
queue_bind("hello", "", k): ChannelClosedByBroker: (403, 'ACCESS_REFUSED - operation not permitted on the default exchange')
queue_unbind(…, ""): ChannelClosedByBroker: (403, 'ACCESS_REFUSED - operation not permitted on the default exchange')
exchange_declare("", fanout): ChannelClosedByBroker: (403, 'ACCESS_REFUSED - operation not permitted on the default exchange')
exchange_declare("amq.foo"): ChannelClosedByBroker: (403, "ACCESS_REFUSED - exchange name 'amq.foo' contains reserved prefix 'amq.*'")
管理 API 里它叫 amq.default: {'durable': True, 'internal': False, 'name': '', 'type': 'direct'}不能删除、绑定、解绑或重新声明默认 exchange(403 ACCESS_REFUSED);自己声明的 exchange 名字也不能以 amq. 开头。管理 API 里默认 exchange 的名字是 amq.default。
queue_declare("") → 服务器生成名字 amq.gen-…(共 30 个字符,前缀 amq.gen-)
用生成的名字作 routing key 发布 → ['to-generated']
队列 'a.b.c': 通过默认 exchange 收到 ['x']
队列 'with space': 通过默认 exchange 收到 ['x']
队列 '中文队列': 通过默认 exchange 收到 ['x']
队列 'UPPER': 通过默认 exchange 收到 ['x']
255 字节的名字: 成功
256 字节的名字: ShortStringTooLong(pika 在客户端就拒绝了,字符串超过 255 字节,没有发给 broker)
routing key 256 字节: ShortStringTooLong(pika 在客户端就拒绝了,字符串超过 255 字节,没有发给 broker)
list_bindings 里有没有 a.b.c 那一行:删除队列前 True,删除后 False
$ rabbitmqctl list_bindings source_name destination_name routing_key
Listing bindings for vhost /...
source_name destination_name routing_key
UPPER UPPER
hello hello
with space with space
中文队列 中文队列空队列名由 broker 生成 amq.gen-…;中文、空格、大写都可以;名字和 routing key 都是 AMQP 短字符串,上限 255 字节,超出时 pika 在客户端就拒绝。
默认 exchange:中位数 545 ms(最小 532、最大 672);显式 direct exchange:中位数 536 ms(最小 530、最大 685)
20000 条消息走默认 exchange 与走显式 direct exchange 耗时一样(中位数 545 ms 与 536 ms,轮间波动更大)。默认 exchange 的好处是少两步声明,不是更快。