事件驱动架构正从少数服务之间的有限模型,转变为由大量生产者、消费者和消息通道组成的广泛网络。在这一阶段,核心问题不再是发送消息,而是了解发送的内容、所有者、依赖者,以及如何在不造成生产故障的情况下更改其模式或重新创建基础设施。这正是 Ian Cooper 关于大规模管理异步 API 的演讲主题,内容基于 Just Eat Takeaway 的实际工程实践。
为什么规模扩大后事情会变得复杂?
在小型企业中,团队成员可能了解哪些服务发布和消费事件,也可以通过消息传递框架或直接向平台团队提出请求来创建主题或通道。但随着团队和服务数量增加,这种方式会失去成效。某个特定端点由谁负责、描述消息的契约是什么,或者数据与分析团队中是否存在未知消费者,都可能变得不明确。
当一个团队仅与已知消费者协商后便更改消息模式,而其他团队在未被纳入沟通范围的情况下依赖该消息时,风险就会出现。如果没有可靠的方法来确定某个主题的所有者,或重新发布所需基础设施,删除被认为未使用的主题可能会导致关键路径丢失,尤其是在唯一的恢复方式是重新部署系统大部分组件的情况下。
事件接口管理的三个方面
Cooper 将这一问题划分为发现、治理和供应。首先,需要理解任何端点应描述哪些内容,这可以通过他所谓的“ABC”来实现:地址、绑定和契约。地址确定消息流的位置,绑定描述协议、传输方式和编码,而契约则确定消息所携带的标头和数据。
在这一背景下,AsyncAPI 为 HTTP 接口文档机制(如 OpenAPI)提供了对应方案,能够对服务器、通道、消息、操作以及协议相关的绑定进行建模。它支持使用 JSON Schema、Avro 和 Protobuf 描述消息,也允许复用定义,而不是在多个文件中重复定义。不过,Cooper 强调,在一个仓库中放置数百个 AsyncAPI 文件并不能单独解决发现问题;当事件资产库不断扩大时,文本搜索仍然十分有限。
因此,企业可能需要 EventCatalog 或 Marmot 等目录工具,或使用 xRegistry 这类开放注册表,以展示消息流及其关系,并将模式与生产者和消费者关联起来。这些工具在可视化程度和现成界面方面各不相同,但它们的共同作用,是将发现过程从在 Slack 中提问或在分散的仓库中搜索,转变为可查询的服务。
CloudEvents 在统一元数据方面的作用
CloudEvents 负责解决问题的另一个方面,它提供一组统一的元数据,例如标识符、来源、版本和类型,并提供用于数据内容类型、主题、时间和模式链接的可选字段。当多个类型共用一个通道时,可以使用事件类型来路由消息,或选择其反序列化机制。
演讲解释说,CloudEvents 的 binary 和 structured 两种模式,取决于传输协议承载标头的能力,而不是消息在通常意义上是否为“二进制”或“结构化”。这一细节在 SNS 等系统中尤为重要:如果将所有 CloudEvents 数据放入标头,数量有限的消息属性可能会很快被消耗,因此在某些场景下,将其封装在消息正文中是更实际的选择。
治理不仅限于文档
契约文档能够让消费者了解消息的内容,但无法阻止生产者发布会破坏其依赖关系的更改。因此,所介绍的方法建议使用模式注册表,在更新契约时应用兼容性规则,并拒绝不符合既定规则的消息或更改。
安全实践通常包括将新增字段设为可选,推迟删除字段,直到所有消费者都不再使用这些字段,并将重命名视为由删除和新增组成的更改。而字段类型变更通常被视为破坏性更改,可以通过添加所需类型的新字段来实施,然后将消费者迁移到新字段,最后删除旧字段。
实际会发生哪些变化?
给技术读者的核心信息是,大规模事件管理需要一条相互连接的链路,而不是单一工具:使用 AsyncAPI 描述接口,使用 CloudEvents 统一元数据,使用目录或注册表促进发现,使用模式注册表强制执行兼容性,并通过自动化供应基础设施及监控其漂移。缺少这些层次,事件驱动架构可能会变成一个充满不可见依赖关系的网络。
实际限制依然存在:标准本身无法提供对消费者的完整了解,而且各类工具在接口支持、可视化和与代理集成方面存在差异。因此,实施这一方法需要明确契约和通道的所有权,将变更与 CI/CD 流程关联起来,并保留一条能够重新创建资源的恢复路径,而不是依赖个人知识或过时文档。