高吞吐量发送到 EventHubs 导致 MessagingException / TimeoutException / 服务器无法处理请求错误

High throughput send to EventHubs resulting into MessagingException / TimeoutException / Server was unable to process the request errors

我们在高峰流量期间向 EventHubs 发送事件时遇到很多这样的异常:

"Failed to send event to EventHub. Exception : Microsoft.ServiceBus.Messaging.MessagingException: The server was unable to process the request; please retry the operation. If the problem persists, please contact your Service Bus administrator and provide the tracking id." 要么 "Failed to send event to EventHub. Exception : System.TimeoutException: The operation did not complete within the allocated time "

这里可以看的很清楚:

如您所见,当传入消息超过 400K events/hour(或 ~270 MB/hour)时,我们遇到了很多内部错误、服务器繁忙错误、请求失败。这不仅仅是一个暂时的问题。这显然与吞吐量有关。

我们的 EH 有 32 个分区,消息保留 7 天,并分配了 5 个吞吐量单位。 OperationTimeout 设置为 5 分钟,我们使用默认的 RetryPolicy。

这里还有什么我们需要调整的吗?我们非常关心 EH 的可扩展性。

谢谢

发送吞吐量调整可以使用高效的分区分配策略来实现。没有任何一个旋钮可以做到这一点。以下是您设计高吞吐量场景所需的基本信息。

1) 让我们从命名空间开始:吞吐量单位(又名 TU)在命名空间级别配置。请。请记住,已应用配置的 TU - 该命名空间下所有 EventHub 的集合。 如果您的命名空间上有 5 个 TU 且其下有 5 个 eventhub - 它将分配给所有 5 个 eventhub。

2) 现在让我们看看 EventHub 级别:如果为 EventHub 分配了 5 个 TU 并且它有 32 个分区 - 没有一个分区可以使用所有 5 个 TU。对于前。如果您尝试将 5TU 的数据发送到 1 个分区并将 'Zero' 发送到所有其他 31 个分区 - 这是不可能的。每个分区应规划的最大值为 1 TU。通常,您需要确保数据均匀分布在所有分区中。 EventHubs 支持 3 种类型的发送 - 这为用户提供了对分区分配的不同级别的控制:

  1. EventHubClient.Send(EventDataWithoutPartitionKey) -> 如果您使用此 API 发送 - eventhub 将负责在所有分区之间均匀分布数据。 EventHubs 服务网关会将数据轮询到所有分区。当特定分区出现故障时 - 网关会自动检测并确保客户端不会受到任何影响。 这是发送到 EventHubs 的最推荐方式
  2. EventHubClient.Send(EventDataWithPartitionKey) -> 如果您使用此 API 发送到 EventHubs - partitionKey 将决定您的数据分布。 PartitionKey 用于将 EventData 散列到适当的分区(散列算法是 Microsoft 专有的,而不是共享的)。通常需要关联一组消息的用户会使用这种发送变体。
  3. EventHubSender.Send(EventData) -> 在此变体中,发件人已附加到分区。所以 - 这让客户端可以完全控制跨分区的分发。

衡量您当前的数据分布 - 使用 EventHubClient.GetPartitionRuntimeInfo Api 估计哪个分区过载。 b/w BeginSequenceNumberLastEnqueuedSequenceNumber 的差异应该给出与其他分区相比的分区负载的估计值。

3) 最后但并非最不重要的一点 - 您可以在发送操作级别调整性能(不是吞吐量)- 使用 SendBatch API。 1 TU 最多可以购买 1000 msgs/sec 或 1MBPS - 无论哪个限制先达到,你都会受到限制 - 这是无法更改的。 如果您的消息很小——比如说 100 个字节,而您只能发送 1000 msgs/sec(根据 TU 限制)——您将首先达到 1000 events/sec 的限制。但是,总体上使用 SendBatch API - 你可以批处理 100 字节消息中的 10 条并以相同的速率推送 - 1000 msgs/sec 只需 100 API 调用并改善端到端延迟系统的(因为它也有助于服务有效地保留消息)。请记住,这里唯一的限制是最大。可以发送的消息大小 - 256 kb(如果您使用 SendBatch API,此限制将适用于您的 BatchSize)。

鉴于该背景,对于您的情况: - 有 32 个分区和 5 个 TU - 我真的会仔细检查分区分配策略。

here's some more general reading on Event Hubs...

经过大量挖掘,我们决定停止为发布的消息设置 PK,问题就这样解决了!。我们使用 GUID 作为 PK。我们开始在 Azure 门户上得到很少的错误,并且不再有异常。希望这对其他人有帮助