当前应用程序开发模式倾向于微服务和微服务架构。虽然这种方法为开发团队提供了在独立部署和开发速度方面的巨大灵活性,但当你尝试在生产环境中追踪错误时,缺点就显而易见了。
单体应用程序位于单个位置,您可以检查代码流程和应用程序的运行时状态。这在微服务架构中更具挑战性,因为单个业务事务可能跨越部署在独立进程和计算节点上的数十个服务。
您可以依赖传统的日志记录方法,在这种方法中,您需要在一个集中的位置收集和关联日志,以便尝试重建业务事务路径。这是我们可以使用的工具之一,但它仍然可能很粗糙,并且无法提供所有必要的上下文。 分布式追踪 在这里提供了帮助。
分布式跟踪
分布式追踪允许服务在执行过程中留下“面包屑”,并提供足够的信息来创建业务事务的执行路径,并用“谁”、“什么”和“哪里”等上下文数据进行丰富。SRE 团队和开发人员随后可以使用它来浏览记录的执行,并检查执行中的错误或异常,这些错误或异常可能表示部署问题(服务不可用)甚至 bug。
而这正是 Debezium 发挥作用的地方。Debezium 从数据库捕获的数据变更事件,通过 Kafka Connect 和 Apache Kafka 传播给一个或多个下游消费者,是数据流的一部分,对这些数据流进行洞察非常有价值。变更事件从源数据库流向目标系统的耗时多久?管道中最耗时的部分在哪里?是否存在端到端延迟峰值等异常情况?将分布式追踪与 Debezium 集成可以帮助回答这些问题。
OpenTracing
有多种分布式追踪解决方案,但作为起点,我们决定遵循并使用 OpenTracing 规范。OpenTracing 是 Cloud Native Computing Foundation 的一个孵化项目,它保证用户通过遵循开放标准来摆脱任何供应商锁定。
| OpenTracing 项目正在与 OpenCensus 合并,以改进 OpenTelemetry 标准。Debezium 目前使用 OpenTracing 是出于与其他项目(例如 Quarkus)保持一致的原因,但将来也会使用和支持 OpenTelemetry。 |
OpenTracing 中的分布式追踪由一组 span 组成。每个 span 代表一个已执行的逻辑工作单元。span 可以形成一个树状结构,其中一个 span 代表的业务事务的更大一部分可以由多个任务组成,这些任务由具有父子关系的附加 span 表示。
OpenTracing 只是规范和插桩 API。要使用它,您还需要一个实现。虽然 Debezium 可以使用任何 OpenTracing 客户端实现,但我们的示例和文档基于 Jaeger 分布式追踪平台。
Jaeger 由负责数据收集和存储的多个组件以及以 Web 应用程序形式提供的图形用户界面组成。Jaeger 的 All-In-One 容器镜像将用于简化部署。
Debezium 和 OpenTracing
Debezium 与 OpenTracing 的集成由三个不同的组件组成:
-
ActivateTracingSpanSMT -
Quarkus 应用程序的 Debezium Outbox 扩展 中的
EventDispatcher -
EventRouterSMT
第一个组件用于通用用途。后两个组件必须一起使用,以便对使用 Outbox 模式的(基于 Quarkus 的)服务进行追踪。
Outbox 分布式追踪
追踪集成中最大的问题是如何跨越进程边界保持追踪,以便所有相关的 span 都记录在同一个追踪中,从而实现端到端追踪。OpenTracing 规范提供了一种导出和导入与追踪相关的元数据的方法,从而可以将追踪在不同进程之间传递。
在 Outbox 扩展中,我们使用这种方法将元数据导出到 Outbox 表中的特定列,以便事件路由器 SMT 可以导入它们并恢复追踪。在执行的每个步骤中,都会创建一个或多个 span。
-
当事件到达
EventDispatcher时,会创建一个新的 spanoutbox-write。它被创建为当前活动 span(例如,由当前应用程序的 REST API 调用启动)的子 span,或者如果不存在父 span,则作为根 span。 -
span 元数据被导出到 Outbox 事件的一个特定字段中。
-
Outbox 事件被写入 Outbox 表。
-
Event Router SMT 接收事件并从该字段导入 span 元数据。
-
创建两个新的 span:
-
db-log-write,其开始时间戳设置为数据库写入时间戳。来自source块的字段被添加为 span 的 **tags**。 -
debezium-read,其开始时间设置为处理时间戳。来自 envelope 的字段被添加为 span 的 **tags**。
-
-
如果 Kafka 生产者级别启用了 OpenTracing 集成,则 Kafka 生产者会创建一个新的 span,代表将消息写入 Kafka 主题,并附带相关元数据。
演示
已将 Outbox 示例 扩展了分布式追踪支持以演示此功能。此示例包含两个基本的微服务:一个订单服务,它公开用于下订单的 REST API;以及一个订单服务,它通过 Outbox 模式通知订单服务新订单。
| 此演示使用 Strimzi 容器镜像作为 Kafka Connect,因为它已经内置了 OpenTracing 在 Kafka 生产者级别的集成。 |
要亲自尝试,您需要:
-
检出存储库并切换到
outbox目录。 -
构建服务。
$ mvn clean install
-
部署应用程序。
export DEBEZIUM_VERSION=1.4 docker-compose up --build
-
注册一个 Debezium 连接器来监听 Outbox 表。
$ http PUT https://:8083/connectors/outbox-connector/config < register-postgres.json HTTP/1.1 201 Created
-
执行多个业务请求。
$ http POST https://:8080/orders < resources/data/create-order-request.json $ http PUT https://:8080/orders/1/lines/2 < resources/data/cancel-order-line-request.json
-
查看 Jaeger UI。
完成以上所有步骤后,您应该会看到 Jaeger UI 的欢迎屏幕。
将服务筛选为 order-service,然后点击 Find Traces。应该有两个追踪可用。
点击 addOrder 服务。将打开一个树状图,显示通过 REST API 传入的初始请求是如何:
-
由 Outbox 扩展写入数据库。
-
被 Debezium 读取并由 Outbox SMT 处理。
-
被写入 Kafka 主题。
-
被
shipment-service从 Kafka 主题读取。 -
在不同的
shipment-service业务方法中处理。
点击 db-log-write 和 debezium-read span。每个 span 的 **tags** 都包含提取的 Debezium 相关元数据,例如 operation 或 source 字段。
结论
在本文中,我们讨论了什么是分布式追踪以及使用它的好处。我们看到了 Debezium 层面的分布式追踪集成是如何实现的,以实现端到端追踪,并一起尝试了一个演示应用程序和 Jaeger UI 的探索。
虽然这个示例侧重于通过 Outbox 模式进行微服务数据交换的特定用例,但 Debezium 也可以独立于这个特定模式与分布式追踪集成。通过 ActivateTracingSpan SMT,Debezium 可以生成代表源数据库变更时间以及 Debezium 连接器处理事件时间的 span。
分布式追踪支持是 Debezium 1.4 的一项新功能(最初在 Beta1 中添加),并且将在后续版本中不断发展和成熟。我们非常欢迎您对这项新功能的反馈!
关于 Debezium
Debezium 是一个开源的分布式平台,可以将现有数据库转变为事件流,使应用程序能够几乎即时地看到并响应数据库中已提交的每个行级更改。Debezium 构建在 Kafka 之上,并提供了 Kafka Connect 兼容的连接器,用于监控特定的数据库管理系统。Debezium 将数据更改的历史记录在 Kafka 日志中,这样您的应用程序可以随时停止和重新启动,并可以轻松地消费在未运行时错过的所有事件,确保所有事件都被正确且完整地处理。Debezium 在 Apache 许可证 2.0 下是 开源 的。