3. Azure Event Hubs架构与原理
Azure Event Hubs 是 Azure 上的分布式事件流平台,定位是“事件入口层”:它把来自应用、设备、日志代理、Kafka 生产者的事件按顺序写入分区日志,再由下游消费者按自己的节奏读取。理解 Event Hubs 的关键,不是把它当成一个消息队列,而是把它看成一个按分区组织的追加式日志——写入只追加,读取靠偏移量,事件在保留期内可被多个消费者组重复读取。
分区:并行度的基本单位
Event Hub 在创建时确定分区数(1~32,部分层级可到 1024),分区数一旦创建不可更改。每个分区是一条独立、有序的日志,事件进入某个分区后,在该分区内保持顺序。分区键(Partition Key)决定事件落到哪个分区:相同分区键的事件进入同一分区,从而保证同一业务实体的顺序。例如订单事件用 orderId 作为分区键,同一订单的状态变更就会按顺序写入同一分区。
分区数直接决定最大并行消费者数量。若一个消费者组内有 5 个消费者,而 Event Hub 只有 4 个分区,则最多 4 个消费者能各占一个分区,第 5 个会空闲。因此分区数应结合预期吞吐和消费者并行度来定,而不是随意取默认值。
吞吐量单位与自动扩充
标准层用吞吐量单位(Throughput Unit,TU)计量容量。1 个 TU 提供:入口约 1 MB/s 或 1000 事件/s,出口约 2 MB/s 或 4096 事件/s。例如某应用每秒产生 3000 条、平均 600 字节的事件,入口速率约 1.8 MB/s,按入口计算至少需要 2 个 TU;若下游还要以 2 倍速率读取,出口约 3.6 MB/s,需要 2 个 TU 的出口容量,综合取 2~3 个 TU 更稳妥。这只是示例估算,实际应以监控中的 Incoming/Outgoing Messages 和 Throughput 指标为准。
标准层支持自动扩充(Auto-inflate),可在负载升高时自动增加 TU,但不会自动缩减。专用层(Dedicated)和高级层(Premium)则按处理单元(PU)或容量单位计费,适合需要隔离和更低延迟的场景。
消费者组:多套独立读取视图
消费者组(Consumer Group)是 Event Hub 上的“读取视图”。每个消费者组维护自己的偏移量,互不影响。同一消费者组内,一个分区同一时刻只能被一个消费者读取;不同消费者组可以同时读取同一分区。典型用法是:一个消费者组给实时告警用,另一个给归档写入用,第三个给离线分析用,它们各自从不同位置开始读,互不干扰。
偏移量(Offset)是事件在分区中的位置,检查点(Checkpoint)是消费者把“已处理到哪”持久化的动作。消费者崩溃后从最近检查点恢复,因此检查点频率决定了故障时可能重复处理的事件量。
事件保留与捕获
事件保留(Retention)决定事件在 Event Hub 中保存多久,标准层默认 1 天,可设 1~7 天;高级层和专用层可更长。保留期内的数据可被多个消费者组重复读取,过期后自动清除。保留期不是归档方案,长期存储应使用捕获(Capture)功能。
捕获功能可把进入 Event Hub 的事件按时间或大小窗口自动写入 Azure Blob Storage 或 Azure Data Lake Storage,格式为 Avro。例如设置窗口为 5 分钟或 300 MB,捕获会生成类似 {Namespace}/{EventHub}/{PartitionId}/{Year}/{Month}/{Day}/{Hour}/{Minute}/{Second}.avro 的文件。捕获是旁路写入,不影响正常消费,适合做冷数据归档和批处理输入。
AMQP 与 Kafka 协议支持
Event Hubs 原生支持 AMQP 1.0,这是其首选协议,提供高效的双向通信和流控。同时,Event Hubs 提供 Kafka 端点,兼容 Kafka 生产者和消费者 API。已有 Kafka 应用只需把 bootstrap.servers 指向 {namespace}.servicebus.windows.net:9093,并配置 SASL/PLAIN 或 SASL/OAUTHBEARER 认证,即可把数据写入 Event Hubs,无需改代码。这使 Event Hubs 可以作为 Kafka 的托管替代入口,同时保留 AMQP 生态的 SDK 接入能力。
把参数落到配置上
下面是一段示例配置,用于说明分区键、消费者组和捕获窗口如何在实际代码中体现。参数为教学示例,不是实测结果。
// 生产者:用 orderId 作为分区键,保证同一订单顺序
var producer = new EventHubProducerClient(connStr, "orders");
using var batch = await producer.CreateBatchAsync(new CreateBatchOptions {
PartitionKey = orderId
});
batch.TryAdd(new EventData(Encoding.UTF8.GetBytes(json)));
await producer.SendAsync(batch);
// 消费者:指定消费者组,从检查点恢复
var consumer = new EventHubConsumerClient(
"alert-group", connStr, "orders");
await foreach (var evt in consumer.ReadEventsAsync()) {
// 处理事件
await consumer.CheckpointAsync(evt);
}
捕获配置则通过 Azure 门户或 ARM/Bicep 设置:选择目标存储账户、容器、命名格式,以及时间窗口和大小窗口。捕获文件按分区写入,因此下游批处理可以按分区并行读取。
如何判断配置是否合理
在 Azure 门户的 Event Hubs 指标中,重点观察 Incoming Messages、Outgoing Messages、Incoming Bytes、Outgoing Bytes 和 Throttled Requests。若 Throttled Requests 持续大于 0,说明 TU 不足或分区热点明显;若某个分区的 Incoming Messages 远高于其他分区,说明分区键分布不均,需要重新设计分区键。消费者侧则观察 Consumer Lag(消费者滞后),滞后持续增长说明消费者处理速度跟不上入口速率,需要增加消费者实例或优化处理逻辑。
总结来看,Event Hubs 的架构可以概括为:生产者按分区键写入分区日志,分区提供顺序和并行度;TU 提供容量,自动扩充应对突发;消费者组提供多套独立读取视图,检查点保证故障恢复;保留期控制在线可读窗口,捕获把数据旁路归档到存储;AMQP 和 Kafka 双协议让不同技术栈都能接入。把这些参数和机制配合好,Event Hubs 才能稳定承担实时数据入口的角色。