你可能用错了 kafka 的重试机制

作者|DaveTaubler译者|王强策划|Tina
ApacheKafka已成为跨微服务异步通信的主流平台 。 它有很多强大的特性 , 让我们能够构建健壮、有弹性的异步架构 。
同时 , 我们在使用它的过程中也需要小心很多潜在的陷阱 。 如果未能提前发现可能发生(换句话说就是迟早会发生)的问题 , 我们就要面对一个容易出错和损坏数据的系统了 。
在本文中 , 我们将重点介绍其中的一个陷阱:尝试处理消息时遭遇失败 。 首先 , 我们需要意识到消息消费可能会 , 而且迟早会遭遇失败 。 其次 , 我们需要确保在处理此类故障时不会引入更多问题 。
1Kafka简介阅读本文的读者应该都对Kafka有所了解 。 网上也有一些介绍Kafka及其使用方法的深度文章 。 话虽如此 , 我们这里还是先简要回顾一下对我们的讨论很重要的一些概念 。
事件日志、发布者和消费者Kafka是用来处理数据流的系统 。 从概念上讲 , 我们可以认为Kafka包含三个基本组件:
一个事件日志(EventLog) , 消息会发布到它这里
发布者(Publisher) , 将消息发布到事件日志
消费者(Consumer) , 消费(也就是使用)事件日志中的消息

你可能用错了 kafka 的重试机制
文章图片
与RabbitMQ之类的传统消息队列不同 , Kafka由消费者来决定何时读取消息(也就是说 , Kafka采用了拉取而非推送模式) 。 每条消息都有一个偏移量(offset) , 每个消费者都跟踪(或提交)其最近消费消息的偏移量 。 这样 , 消费者就可以通过这条消息的偏移量请求下一条消息 。
主题事件日志分为几个主题(topic) , 每个主题都定义了要发布给它的消息类型 。 定义主题是我们这些工程师的责任 , 所以我们应该记住一些经验法则:
每个主题都应描述一个其他服务可能需要了解的事件 。
每个主题都应定义每条消息都将遵循的一个唯一模式(schema) 。
分区和分区键主题被进一步细分为多个分区(partition) 。 分区使消息可以被并行消费 。 Kafka允许通过一个分区键(partitionkey)来确定性地将消息分配给各个分区 。

你可能用错了 kafka 的重试机制
文章图片
分区键是一段数据(通常是消息本身的某些属性 , 例如ID) , 其上会应用一个算法以确定分区 。这里 , 我们将消息的UUID字段分配为分区键 。 生产者应用一种算法(例如按照分区数修改每个UUID值)来将每条消息分配给一个分区 。
以这种方式使用分区键 , 使我们能够确保与给定ID关联的每条消息都会发布到单个分区上 。
还需要注意的是 , 可以将一个消费者的多个实例部署为一个消费者组 。 Kafka将确保给定分区中的任何消息将始终由组中的同一消费者实例读取 。
2在微服务中使用KafkaKafka非常强大 。 所以它可用于多种环境中 , 涵盖众多用例 。 在这里 , 我们将重点介绍微服务架构中最常见的用法 。
跨有界上下文传递消息当我们刚开始构建微服务时 , 我们许多人一开始采用的是某种中心化模式 。 每条数据都有一个驻留的单一微服务(即单一真实来源) 。 如果其他任何微服务需要访问这份数据 , 它将发起一个同步调用以检索它 。
这种方法导致了许多问题 , 包括同步调用链较长、单点故障、团队自主权下降等 。
最后我们找到了更好的办法 。 在今天的成熟架构中 , 我们将通信分为命令处理和事件处理 。
命令处理通常在单个有界上下文中执行 , 并且往往还是会包含同步通信 。
另一方面 , 事件通常由一个有界上下文中的服务发出 , 并异步发布到Kafka , 以供其他有界上下文中的服务消费 。

你可能用错了 kafka 的重试机制
文章图片
左侧是我们以前设计微服务通信的方式:一个有界上下文(由虚线框表示)中的服务从其他有界上下文中的服务接收同步调用 。 右边是我们如今的做法:一个有界上下文中的服务发布事件 , 其他有界上下文中的服务在自己空闲时消费它们 。
例如 , 以一个User有界上下文为例 。 我们的User团队会构建负责启用新用户、更新现有用户帐户等任务的应用程序和服务 。
创建或修改用户帐户后 , UserAccount服务会将一个相应的事件发布到Kafka 。 其他感兴趣的有界上下文可以消费该事件 , 将其存储在本地 , 使用其他数据增强它 , 等等 。 例如 , 我们的Login有界上下文可能想知道用户的当前名称 , 以便在登录时向他们致意 。