最佳实践:将 eventhub 数据分区并通过 azure eventhubs 到外部存储(azure blob)实现高规模、低延迟和高吞吐量

Best Practices: to partition eventhub data & achieve high-scale, low-latency and high-throughput via azure eventhubs to external store (azure blobs)

作为安全产品的一部分,我拥有大规模云服务(azure 工作者角色),它从事件中心读取事件,将它们分批处理到 ~2000 并存储在 blob 存储中。 每个事件都有一个 MachineId(发送它的机器)。 事件以随机顺序来自事件中心,我以随机顺序将它们存储在 blob 存储中。 吞吐量高达 125K events/sec,每个事件约为 2K,因此我们的流量高达 250MB/秒。 我们有 ~100 万台机器...

稍后,另一个云服务下载 blob 并对事件运行一些检测逻辑。他按 MachineId 对事件进行分组,并试图从机器时间轴中理解一些东西

问题是今天来自同一台机器的事件被填充到不同的 blob。如果我能以某种方式按事件的 MachineId 对事件进行分组,并确保机器的某个时间 window 填充到同一个 blob,这将增加我可以在云中进行的检测。

我们确实将事件写入另一个 Map reduce 系统,我们在那里进行了很多复杂的检测,但这些检测当然具有高延迟。如果我能在云中更好地对事件进行分组,我就能实时捕获更多

有什么技术可以帮助我吗?

提前致谢

tl;博士: 引入另一个 EventHub - 在原始 eventhub 和 blob 存储之间 - 根据 MachineID 重新分区数据 - 是最好的方法。

一般来说,有一个 INJESTING EVENTHUB - 它只是您监控系统的一个入口点。使用 EventHubClient.send(eventData_without_partitionKey) 方法发送到此 INJESTING EVENTHUB。这将允许您以非常低的延迟和高可用性发送 - 因为它将发送到当前负载较少且可用的分区..

 --------------                     -----------                 ----------
|              |    =========      |           |    ====       |          |
|  INJESTING   |    RE-PARTITION > |  INTERIM  |    BLOB \     |   BLOB   |
|  EVENTHUB    |    =========      |  EVENTHUB |    PUMP /     |          |
|              |                   |           |    ====        ----------
 --------------                     -----------

最重要的是,避免在 Ingesting EventHub 上直接对数据进行分区,因为这些因素:

  1. 高可用性摄取管道 - 不将事件关联到分区 - 将使您的摄取管道保持高可用性。在幕后,我们将您的每个 EventHubs Partition 托管在 Container 上。当您在 EventData 上提供 PartitionKey - PartitionKey 将被散列到特定分区。现在,Send 操作延迟将与单个 Partition 的可用性相关联 - windows OS 升级或我们的服务升级等事件可能会影响它们。相反,如果您坚持 EventHubClient.send(without_PartitionKey) - 我们将尽快将 EventData 路由到可用分区 - 因此,您的摄取管道保证是 Highly available.
  2. 灵活的数据设计——在分布式系统中,您很快就需要根据不同的键重新分区数据。一定要测量你系统中的概率:)。

使用 Interim EventHubs 作为分区数据的方法。即,在 RE-PARTITION 模块中 - 您只需将原始流重播到 INTERIM EVENTHUB,方法是将一个 属性 交换到 EventData.PARTITION_KEY - 最初是空的。

// pseudo-code RE-PARTITION EVENTS
foreach(eventData receivedFromIngestingEventHubs)
{
    var newEventData = clone(eventData);
    eventHubClient.send(newEventData, eventData.Properties.get("machineId"))
}

这可以确保 - 所有具有特定 MachineIDEventData 都可以在 1 and 1 - EventHubs Partition 上使用。 您不需要创建 1M EventHubs 分区。每个分区可以容纳无限数量的 PartitionKey。您可以使用 EventProcessorHost 来托管每个分区逻辑或 Azure Stream analytics Job

此外,这是您过滤和生成最佳流的机会 - 下游处理管道可以使用该流。

BLOB PUMP 模块(您的下游处理管道)中 - 当您使用来自特定 INTERIM EVENTHUBPartition 的事件时- 您现在可以保证在此分区上拥有来自 specific machineid 的所有 Events。根据您需要的大小聚合事件 - 2k - 基于 PartitionId (machineId) - 你不会连续拥有所有事件 - 你需要为此构建一个内存聚合逻辑(使用 EventProcessorHostAzureStreamAnalytics Job.