

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Apache Kafka 客户端的最佳实践
<a name="bestpractices-kafka-client"></a>

使用 Apache Kafka 和 Amazon MSK 时，正确配置客户端和服务器以获得最佳性能和可靠性非常重要。本指南提供了 Amazon MSK 最佳实践客户端配置的建议。

有关 Amazon MSK 复制器最佳实践的信息，请参阅[使用 MSK 复制器的最佳实践](msk-replicator-best-practices.md)。有关标准代理和快速代理的最佳实践，请参阅[标准代理和快速代理的最佳实践](bestpractices-intro.md)。

**Topics**
+ [Apache Kafka 客户端可用性](#bestpractices-kafka-client-client-availability)
+ [Apache Kafka 客户端性能](#bestpractices-kafka-client-performance)
+ [Kafka 客户端监控](#bestpractices-kafka-client-monitoring)

## Apache Kafka 客户端可用性
<a name="bestpractices-kafka-client-client-availability"></a>

在 Apache Kafka 这样的分布式系统中，确保高可用性对于维护可靠且容错的消息传递基础设施至关重要。代理将因计划内和计划外事件（例如升级、修补、硬件故障和网络问题）而离线。Kafka 集群可以容忍代理离线，因此 Kafka 客户端也必须妥善处理代理失效转移。为了确保 Kafka 客户端的高可用性，我们推荐这些最佳实践。

**生产者可用性**
+ 设置 `retries` 以指示生产者在代理失效转移期间重试发送失败的消息。对于大多数使用场景，我们建议使用整数最大值或类似的高值。不这样做将破坏 Kafka 的高可用性。
+ 设置 `delivery.timeout.ms` 以指定从发送消息到从代理收到确认之间的总时间上限。这应该反映消息有效期的业务要求。将时间限制设置得足够高，以允许足够的重试来完成失效转移操作。对于大多数使用场景，我们建议将值设置为 60 秒或更高。
+ 将 `request.timeout.ms` 设置为在尝试重新发送之前单个请求应等待的最长时间。对于大多数使用场景，我们建议将值设置为 10 秒或更高。
+ 设置 `retry.backoff.ms` 以配置重试之间的延迟，以避免重试风暴和可用性影响。对于大多数使用场景，我们建议最小值设置为 200 毫秒。
+ 设置 `acks=all` 以配置高持久性；这应与服务器端配置 `RF=3` 和 `min.isr=2` 一致，以确保 ISR 中的所有分区都确认写入。在单个代理离线期间，这是 `min.isr`，即 `2`。

**消费者可用性**
+ 对于新的或重新创建的消费者组，最初将 `auto.offset.reset` 设置为 `latest`。这样可以避免因消费整个主题而增加集群负载的风险。
+ 使用 `enable.auto.commit` 时设置 `auto.commit.interval.ms`。对于大多数使用场景，我们建议将最小值设置为 5 秒，以避免额外负载风险。
+ 在消费者的消息处理代码中实现异常处理以处理暂时性错误，例如断路器或指数回退休眠。不这样做可能会导致应用程序崩溃，从而导致过度重新平衡。
+ 设置 `isolation.level` 来控制如何读取事务消息：

  我们建议始终默认隐式设置 `read_uncommitted`。一些客户端实现缺少此功能。

  我们建议在使用分层存储时使用 `read_uncommitted` 值。
+ 将 `client.rack` 设置为使用最近的副本读取。我们建议设置为 `az id `，以最大限度地降低网络流量成本和延迟。请参阅 [Reduce network traffic costs of your Amazon MSK consumers with rack awareness](https://aws.amazon.com/blogs/big-data/reduce-network-traffic-costs-of-your-amazon-msk-consumers-with-rack-awareness/)。

**消费者重新平衡**
+ 将 `session.timeout.ms` 设置为大于应用程序启动时间的值，包括任何实现的启动抖动。对于大多数使用场景，我们建议将值设置为 60 秒。
+ 设置 `heartbeat.interval.ms` 以微调组协调器如何将消费者视为正常。对于大多数使用场景，我们建议将值设置为 10 秒。
+ 在应用程序中设置关闭钩子，以便在 SIGTERM 上干净地关闭消费者，而不是依靠会话超时来识别消费者何时离开组。Kstream 应用程序可以将 `internal.leave.group.on.close` 设置为 `true` 值。
+ 将 `group.instance.id` 设置为消费者组中的特定值。理想情况下是主机名、任务 ID 或容器组（pod）ID。我们建议在故障排除期间始终设置此项以实现更确定的行为和更好的 client/server 日志关联。
+ 将 `group.initial.rebalance.delay.ms` 设置为与平均部署时间一致的值。这会停止部署期间持续重新平衡。
+ 设置 `partition.assignment.strategy` 以使用粘性分配器。我们建议 `StickyAssignor` 或 `CooperativeStickyAssignor`。

## Apache Kafka 客户端性能
<a name="bestpractices-kafka-client-performance"></a>

为了确保 Kafka 客户端的高性能，我们推荐这些最佳实践。

**生产者性能**
+ 设置 `linger.ms` 以控制生产者等待批次填充的时间。对于 Kafka 来说，较小的批次计算成本很高，因为它们可以同时转换为更多的线程和 I/O 操作。我们建议使用以下值。

  对于所有使用场景（包括低延迟），最小值为 5 毫秒。

  对于大多数使用场景，我们建议最大值设置为 25 毫秒。

  我们建议不要在低延迟使用场景中使用零值。（零值通常会导致延迟，而与 IO 开销无关。）
+ 设置 `batch.size` 以控制发送到集群的批次大小。我们建议将其值增加到 64 KB 或 128 KB。
+ 使用较大的批次大小时设置 `buffer.memory`。对于大多数使用场景，我们建议将值设置为 64MB。
+ 设置 `send.buffer.bytes` 以控制用于接收字节的 TCP 缓冲区。我们建议将值设置为 -1，以便在高延迟网络上运行生产者时让操作系统管理此缓冲区。
+ 设置 compression.type 来控制批次的压缩。我们建议在高延迟网络上运行生产者时使用 lz4 或 zstd。

**消费者性能**
+ 设置 `fetch.min.bytes` 以控制有效的最小提取大小，从而减少提取次数和集群负载。

  对于所有使用场景，我们建议最小值设置为 32 字节。

  对于大多数使用场景，我们建议最大值设置为 128 字节。
+ 设置 fetch.max.wait.ms 以确定在忽略 fetch.min.bytes 之前消费者将等待多长时间。对于大多数使用场景，我们建议将值设置为 1000 毫秒。
+ 我们建议使用者的数量至少等于分区的数量，以改善并行性和弹性。在某些情况下，对于比低吞吐量主题，可以选择少于分区数量的使用者数量。
+ 设置 `receive.buffer.bytes` 以控制用于接收字节的 TCP 缓冲区。我们建议将值设置为 -1，以便在高延迟网络上运行消费者时让操作系统管理此缓冲区。

**客户端连接**

连接生命周期对 Kafka 集群具有计算和内存成本。一次创建过多连接会导致负载过大，从而影响 Kafka 集群的可用性。此可用性影响通常会导致应用程序创建更多连接，从而导致级联故障，最终导致完全中断。如果以合理速度创建，则可以实现大量连接。

我们建议采取以下缓解措施来管理高连接创建率：
+ 确保您的应用程序部署机制不会 producers/consumers 一次全部重启，而最好是小批量重启。
+ 在应用程序层，开发人员应确保在创建管理客户端、生产者客户端或消费者客户端之前执行随机抖动（随机休眠）。
+ 在 SIGTERM 时，关闭连接时应执行随机休眠，以确保不会同时关闭所有 Kafka 客户端。随机休眠应在 SIGKILL 发生之前的超时时间内。  
**Example 示例 A（Java）**  

  ```
  sleepInSeconds(randomNumberBetweenOneAndX);
                          this.kafkaProducer = new KafkaProducer<>(this.props);
  ```  
**Example 示例 B（Java）**  

  ```
  Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      sleepInSeconds(randomNumberBetweenOneAndTwentyFive);
      kafkaProducer.close(Duration.ofSeconds(5));
  });
  ```
+ 在应用程序层，开发人员应确保在单例模式中每个应用程序仅创建一次客户端。例如，使用 lambda 时，应在全局范围内创建客户端，而不是在方法处理程序中创建。
+ 我们建议监控连接数，以保持稳定。在部署和代理故障转移期间，连接creation/close/shift正常。

## Kafka 客户端监控
<a name="bestpractices-kafka-client-monitoring"></a>

监控 Kafka 客户端对于维护 Kafka 生态系统的运行状况和效率至关重要。无论您是 Kafka 管理员、开发人员还是运营团队成员，启用客户端指标对于了解计划内和计划外事件期间的业务影响都至关重要。

我们建议使用您的首选指标捕获机制来监控以下客户端指标。

向提出支持请求时 AWS，请包括事件期间观察到的任何异常值。还请包括详细说明错误（而非警告）的客户端应用程序日志示例。

**生成者指标**
+ byte-rate
+ record-send-rate
+ records-per-request-avg
+ acks-latency-avg
+ request-latency-avg
+ request-latency-max
+ record-error-rate
+ record-retry-rate
+ error-rate

**注意**  
重试时出现的暂时错误无需担心，因为这是 Kafka 处理临时问题（例如领导者失效转移或网络重新传输）的协议的一部分。`record-send-rate` 将确认生产者是否仍在继续重试。

**消费者指标**
+ records-consumed-rate
+ bytes-consumed-rate
+ fetch-rate
+ records-lag-max
+ record-error-rate
+ fetch-error-rate
+ poll-rate
+ rebalance-latency-avg
+ commit-rate

**注意**  
高提取率和提交率将对集群造成不必要的负载。最好以较大批次执行请求。

**通用指标**
+ connection-close-rate
+ connection-creation-rate
+ connection-count

**注意**  
高连接 creation/termination 会给集群带来不必要的负载。