[TOC] #### 1. 前言 --- 前面三种 Exchange 都是根据消息的标记(routing key)来路由,但有些场景,routing key 不够用 如果 routing key 不够用怎么办 ? 假设你做了一个跨平台的消息系统,消息来自不同的设备和语言: + 来源:iOS / Android / Web + 语言:中文 / 英文 + 类型:通知 / 推送 你想把「iOS 端的中文通知」发给一个队列,「Android 端的英文推送」发给另一个队列 如果用 Topic Exchange,将 routing key 写成 `ios.chinese.notification` ? 可以,但你会发现: + 标记越来越长,越来越难维护 + 有些维度是可选的(比如有些消息没有「语言」维度) + 想按「所有中文消息」来匹配,Topic 写起来很别扭 你需要的不是按字符串匹配,而是按「属性」匹配 #### 2. Headers Exchange --- Headers Exchange 的思路:不看 routing key,它看的是消息的 属性头(headers) Producer 发消息的时候,在属性里附带一组键值对: ```php $message = new AMQPMessage(json_encode($data), [ 'headers' => [ 'platform' => 'ios', 'language' => 'chinese', 'type' => 'notification', ], ]); ``` Queue 绑定的时候,也指定一组键值对: ```php $args = new AMQPTable([ 'platform' => 'ios', 'language' => 'chinese', ]); $channel->queue_bind('ios_chinese_queue', 'header_exchange', '', false, $args); ``` 只要消息的 headers 和队列绑定的 headers 匹配,消息就会投递(不看标记,只看属性) Headers Exchange 支持两种匹配模式: + x-match = all(默认):所有键值对都匹配才算匹配 + x-match = any:只要有一个键值对匹配就算匹配 ```php $args = new AMQPTable([ 'x-match' => 'any', // 任意一个匹配就行 'platform' => 'ios', 'language' => 'chinese', ]); ``` 这个灵活性比 Topic Exchange 更高 但实际上,它用得不多,说实话,Headers Exchange 在实际项目中使用频率很低 原因有几个: + 性能不如 routing key 匹配:routing key 是字符串匹配,速度很快,Headers 要逐个对比键值对,开销更大 + 大多数场景用 Topic 就够了:日志分级、模块分流、通配符匹配,Topic Exchange 基本能覆盖 + 代码不够直观:routing key 一目了然,headers 要看代码才知道绑定了什么。 管理界面上也不如 routing key 好辨认 什么时候会用到 ?Headers Exchange 适合这些场景: + 消息的维度很多,routing key 无法表达 + 需要按多个属性组合来匹配 + 消息结构复杂,不适合用简单的字符串标记 但大多数情况下,你会先想到用 Direct 或 Topic 所以,了解 Headers Exchange 的存在就行,实际用到的时候再查文档也不迟 #### 3. 本文小结 --- Headers Exchange 的核心规则:不看 routing key,看消息的属性头(headers),按键值对匹配 特点: + 灵活性最高,支持多维度匹配 + 性能不如 routing key 匹配 + 实际使用频率较低 四种 Exchange 我们都讲完了: | 类型 | 规则 | 常用程度 | | ------------ | ------------ | ------------ | | Direct | 精确匹配 routing key | 最常用 | | Fanout | 全部广播 | 常用 | | Topic | 通配符匹配 | 最常用 | | Headers | 属性头匹配 | 较少用 | 实际开发中,Direct 和 Topic 用得最多,Fanout 次之,Headers 最少 下一讲,我们用一个完整的实战案例,把 Exchange 的知识串起来