ESB - 日志记录和监控





5.00/5 (8投票s)
一种记录 ESB 事务和转换的简单方法。
引言 - 范围
实现 ESB 本身并不难,但通常人们会忽略围绕它构建一个报告框架,以便让相关的利益相关者能够准确地看到哪些事务在系统之间流动,实际发送了什么数据以及接收了什么数据。然而,这是一个相当重要的组成部分,无论是对您(用于调试、公开和推广您的服务)还是对用户/利益相关者,尤其是在合规/控制/审计方面。
同样,ESB 的各种集成健康监控的需求也并非总是明确提出,这通常导致对 ESB 是否在运行并做有用的事情的理解非常模糊。
本项目旨在演示如何满足最基本的需求,同时也是对 ESB 是什么的一个简单介绍。
与其仅仅推测如何实现,不如呈现一个超小型的 ESB 应用程序,以便所有实现中的实际问题都能显现出来。
ESB
实现 ESB 有许多原因。其中一个原因是通过创建一个抽象层,让数据发布者和订阅者/消费者可以在此层见面并交换数据,从而简化不同类型系统之间的消息传递。这种抽象允许更多的系统发布相同类型的数据(例如订单或发票),并让更多的系统订阅相同的数据。
使用 Mulesoft 和 BizTalk 等产品最大的优势在于它们提供的适配器包——能够开箱即用,连接到许多大型且通用的业务系统、ERP、CRM 和 HR 系统,如 SAP、NetSuite、Salesforce、Workday 等。
连接到系统可能需要一些时间才能正常工作,因为业务系统(尤其是 SaaS 系统)的接口设计旨在最好地满足安全性、负载均衡、性能等非功能性需求,但一旦您克服了这些障碍,您的连接解决方案就可以重复用于您与该特定系统的下一个集成,而且通常并不困难——Making connections 的文档通常都很详尽。
然而,在企业环境中,选择带有标准连接器的标准软件的最大驱动因素并非技术,而是合规性和审计。如果您拥有商业连接器,审计师不会对其提出疑问,但如果您自己制作,您将不得不验证是否存在对商业库等的依赖(从而可能存在违规行为)。
因此,尽管技术实现可能相当直接,但在企业环境中选择技术时,法律合规性将发挥重要作用。
但这与我在此无关,所以让我们总结一下 ESB 应该做什么,以及有哪些需求。
当然,主要功能是系统能够向 ESB 发布消息 - 提交数据 - 以及其他对该数据感兴趣或依赖该数据的系统订阅这些消息,并以合适的格式接收它们。功能需求可以形式化为:
- ESB 是实时集成
- ESB 实现发布-订阅模式
- ESB 流是异步的(这意味着,除其他外,没有保证的传递顺序)
- ESB 流是单向的(这意味着,除了告知消息已被 ESB 消费之外,没有同步响应)
从更架构的术语来说,ESB 必须提供:
- 接收位置
- 路由机制
- 转换机制
- 传递机制
一些 ESB(例如 BizTalk)会在入口转换(转换为内部规范格式)和出口转换(转换为目标格式)时进行转换。由于这本质上是两次相同的操作,因此可以由相同的组件进行建模。
示例应用程序将实现上述组件。更详细地说,ESB 应用程序将包括:
- 一个用于接收消息的 Web 服务
- 消息队列/路由
- 转换和
- 传递到外部 Web 服务
大多数 ESB 解决的问题之一是来自不同系统的消息可能采用各种不同的格式:XML、JSON、二进制、专有格式等。由于大多数系统可以 XML 或 JSON 格式传递数据,我将缩小范围到最小程度,并专注于 JSON 消息。传入 JSON 消息,以及传出已转换的 JSON 消息。
设计
为了实现一个简单的应用程序,我将使用 NodeJS 作为我的编码框架,RabbitMQ 用于消息队列和路由,Mongodb 用于存储配置和日志记录。这些是演示项目的好选择 - 但不适用于生产环境。稍后将详细介绍技术选择。
设计决策
- Web 服务将接受任何负载。路由键和描述性(消息类型)数据将在标头中提供。
- 路由将基于 amqp 标头消费者规范中的键:值对。
- Mime 类型: json
- 路由将使用 RabbitMQ 为每个源系统定义一个交换机,并为每个订阅系统创建相关的队列。
- 消费者将定义为数据库中的记录,并实例化为 NodeJS 中实现的消费者。消费者将能够根据为其定义的模板转换消息,并将消息传递到 http 端点。
所有逻辑都将在同一个 NodeJS 应用程序中运行,该应用程序将公开接收位置 Web 服务,并在数据库中实例化定义的消费者。
因此,基本的函数设计(应用程序运行时会是什么样子)将如下所示,针对单个源应用程序发布由单个目标应用程序消费的消息:
图中显示了一个源系统 (A)、RabbitMQ 路由(交换机和队列)、转换(消费者)和目标系统 (B)。
ESB 的要点在于能够允许更多消费者消费相同的源数据。路由将为每个消费者创建单独的消息实例,因此消费者在逻辑上是分离的。在本例中,消费者将在 Node 中实例化。在企业级应用程序中,此组件通常是 Mule 流或类似组件。这确实是该模式的美妙之处:消费者可以在不同的技术中创建并共存,没有任何问题,除了监控和管理挑战。
我选择 NodeJS 作为应用程序框架,对于与演示和管理相关的部分是合理的,但 NodeJS 的单线程特性使其非常不适合消费者部分,因为这会创建消费者之间的依赖和脆弱性。一个消费者可能会导致整个程序崩溃,并导致所有其他消费者也崩溃。
出于演示目的,我将创建一个 Go 语言的消费者应用程序并包含它,Go 语言具有完全不同的线程模型,更适合此目的。在企业环境中,您可能希望进一步确保各个流程的封装,例如将每个流程打包为独立的组件,并配备自己的运行时环境。在 Mule 4.0 中,可以将各个流程运行在自己的 Docker 容器中,从而有效地防止一个流程危害另一个流程。
日志记录
上述 ESB 设计将接收消息,分发它们,转换它们,并将它们传递到正确的目的地。然而,它不会记录传入和传出的内容 - 这正是引言中提到的需求。
满足系统所有者利益相关者查询的基本需求是能够记录源系统发送的消息以及目标系统接收的消息。出于调试原因,在这些两条消息之间的中间点记录消息的状态可能很重要,并且记录目标系统在传递时返回的响应(如果存在)可能非常有价值。
为了对源系统消息产生的消息进行逻辑呈现,将已记录的消息视为属于事务是很有意义的,一个事务导致多个消息(在本例中为四个)被记录。
为了实现此日志记录,消息将在这些四个点写入数据库。实际上,路由部分(交换机和队列)中的消息将通过标准的 RabbitMQ 功能 - 跟踪 - 进行记录。RabbitMQ 通过一个接收所有消息副本的额外队列来实现跟踪,日志记录只是将这些跟踪消息写入日志数据库。
转换部分的日志记录是通过让消费者流程在相关点写入日志数据库来实现的。
为了将所有内容联系起来,接收 Web 服务会将相关 ID 添加到消息标头中。
数据库
消息应与所有相关元数据一起记录,以便能够以正确的上下文呈现。为此,用于保存已记录消息的数据库表可能包含以下字段:
- 时间戳
- 相关 ID
- 外部消息/事务 ID(如果存在)
- 来源(消息来自哪里 - 交换机、队列、转换流程、目标系统)
- 目的地(消息去向何处)
- 路由键
- Headers
- 正文(消息!)
- 流程名称
- 用户(如果已知/相关)
演示
有了日志数据库中的所有消息,剩下的就是为用户提供一个界面来搜索和显示他们感兴趣的事务。
用户界面本身是一门独立的学科,测试应用程序的实现只是一个非常基础的示例,展示了它可能的样子。它由三个部分组成,可以通过单击模型图中的各个部分进行导航:
-
一个设置消费者的页面,定义路由键和转换模板等。转换逻辑可以通过多种方式实现,在本例中,使用了 `node-json-transform` 库,因为它提供了一种简单的方法来处理复杂的 JSON 文档。
出于演示目的,此管理页面允许用户停止一个流程而不停止订阅,因此消息会排队等待,直到消费者重新启动,这是一个非常实用的功能。
-
一个显示最新事务的页面。
在这里,用户应该能够按给定的 ID 或在指定的时间搜索进出他们系统的事务。测试应用程序仅提供最新的 50 个事务的视图 (!)。
从这个页面,可以显示实际的消息负载,甚至可以编辑和重新提交 - 这可能只应该授予有限访问权限的功能。
-
一个模拟源系统的页面,从而创建事务。
如上截图所示,实现了一些额外的功能,但基本上消息数据的呈现可以采取任何期望的形式。
结论
此演示应用程序是一个示例,说明如何通过对路由和转换机制中的简单日志记录来记录 ESB 消息并将文档提供给用户。这些机制可能与此处使用的组件大不相同,选项也可能不同 - 但原则应该保持不变。
用户手册
如果您选择下载包含的应用程序并运行和安装它,以下说明可能会有所帮助:
应用程序首次启动时,没有消费者,因此也没有处理传入消息的逻辑。事实上,只要没有消费者,路由 RabbitMQ 组件中就没有交换机或队列,因为它们是由消费者定义的。因此,第一步是设置至少一个消费者。
当应用程序启动时(假设应用程序在本地运行),并且浏览器指向 https://:3000/,将出现流程页面。单击左下角的加号以添加消费者。
在消费者定义窗口中,添加流程/消费者名称、流程描述、队列名称和绑定(源系统将消息发送到的交换机的名称)、一个或多个路由键:值对、匹配模式(“all
”或“any
”)、一个指示接收的 JSON 是列表还是单个记录(类型“List
”或“Object
”)、目标 URL 和 `node-json-transform` 的转换模板。最后,您可以设置转换器在应用程序启动或重启时是否自动启动(“yes
”或“no
”)。
当消费者启动时,它将创建交换机和队列(如果它们尚不存在)。因此,源系统现在可以通过标头中的适当路由键值对,将消息发布到 https://:3000/exchange/“exchange-name”,并将消息路由到消费者并在此处处理消息负载。
无论成功与否,消息都应该至少在路由组件中记录。如果成功,消息还应该在转换消费者中记录。
为了测试目的,已经制作了一个示例 Web 服务,它将消费任何负载并返回一个包含已消费负载长度的消息。该服务的地址是 https://:3000/consumer/sampleendpoint。
示例模板和数据可以在 `node-json-transform` 的 GitHub 页面找到。
请注意,该应用程序是演示标准:您可能需要查看代码才能理解如何操作!