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

Zor*_*rik 4 azure data-partitioning azure-eventhub azure-blob-storage

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

稍后,另一个云服务下载 blob 并对事件运行一些检测逻辑。他按 MachineId 对事件进行分组,并尝试从机器时间线中了解某些内容

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

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

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

提前致谢

Sre*_*ati 5

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

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

 --------------                     -----------                 ----------
|              |    =========      |           |    ====       |          |
|  INJESTING   |    RE-PARTITION > |  INTERIM  |    BLOB \     |   BLOB   |
|  EVENTHUB    |    =========      |  EVENTHUB |    PUMP /     |          |
|              |                   |           |    ====        ----------
 --------------                     -----------
Run Code Online (Sandbox Code Playgroud)

最重要的是,不要直接在Ingesting EventHub上对数据进行分区,因为以下因素:

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

使用临时 EventHub作为数据分区的一种方式。即,在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"))
}
Run Code Online (Sandbox Code Playgroud)

这确保了 - 是 -EventData具有特定的所有内容MachineID都可以在1 and 1 - EventHubs Partition. 您不需要创建 1M EventHubs Partitions。每个分区可以容纳无限数量的PartitionKeys。您可以使用EventProcessorHost每个分区逻辑或Azure Stream analytics Job.

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

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