4. 事件网格高级过滤与重试

在事件驱动集成中,事件网格(Event Grid)承担的是“事件分发中枢”的角色。它并不保证每个事件都被业务系统成功处理,而是保证在既定策略下尽可能完成投递,并把无法投递的事件显式暴露出来。理解高级过滤、重试策略、指数退避与死信队列,是设计可靠事件链路的必修课。

一、事件筛选:在源头减少无效投递

事件网格支持两类过滤:事件类型过滤和主题过滤。事件类型过滤基于 eventType 字段,例如只订阅 Microsoft.Storage.BlobCreated;主题过滤则基于事件数据中的字段路径,例如 data.url、data.contentType 或自定义属性。主题过滤支持 StringIn、StringNotIn、StringBeginsWith、StringEndsWith、StringContains、NumberGreaterThan、BoolEquals 等操作符,并可通过 enableAdvancedFilteringOnArrays 对数组元素逐项匹配。

过滤的价值在于:把不符合业务条件的事件在订阅入口就丢弃,避免下游函数或队列被无关事件淹没。例如只处理 .jpg 与 .png 图片上传,可配置 data.url 以 .jpg 或 .png 结尾;若还要排除缩略图目录,可再加一条 data.url 不包含 /thumbnails/ 的条件。多个条件之间是“与”关系,同一字段的多个取值是“或”关系。

过滤条件越精确,无效投递越少,但过滤规则本身也会增加事件匹配开销。建议把最稳定、最易判定的字段放在过滤条件中,把复杂业务判断留给下游处理逻辑。

二、重试策略与指数退避

当订阅端返回非 2xx 响应、超时或无法连接时,事件网格会按重试策略重新投递。默认策略为:最多重试 30 次,采用指数退避,首次重试约在 10 秒后,之后间隔逐步拉长,最长可达数分钟。实际等待时间带有随机抖动,避免大量事件同时重试造成“惊群”。

重试策略可配置 maxDeliveryAttempts(1~30)、eventTimeToLiveInMinutes(1~1440 分钟)以及重试间隔。事件 TTL 决定事件在网格中保留的最长时间,超过 TTL 仍未成功投递的事件会被丢弃或转入死信。重试次数与 TTL 共同决定“最多尝试多久”:即使重试次数未用完,TTL 到期也会停止投递。

{
  "retryPolicy": {
    "maxDeliveryAttempts": 10,
    "eventTimeToLiveInMinutes": 120
  }
}

指数退避的意义在于给下游恢复时间。若下游因数据库连接池耗尽而短暂不可用,立即高频重试只会加剧拥塞;退避后重试可显著提高最终成功率。但退避也意味着事件延迟增加,因此对实时性要求高的链路,应把重试次数控制在较小范围,并配合死信队列快速暴露问题。

三、死信队列:让失败事件可追踪、可重放

死信队列(Dead-Letter Queue)用于存放无法成功投递的事件。启用后,事件网格会把最终失败的事件写入指定的存储容器(Blob Storage)。死信事件包含原始事件内容、失败原因、投递尝试次数、最后尝试时间等元数据,便于排查与重放。

死信队列不是“垃圾桶”,而是“待处理队列”。典型处理方式包括:人工检查失败原因、修复下游后批量重放、或将死信事件转入告警系统。若未启用死信队列,失败事件在 TTL 到期后会被静默丢弃,问题难以定位。

死信队列需要提前创建存储账户与容器,并授予事件网格系统托管标识写入权限。若权限不足,死信写入本身也会失败,导致事件彻底丢失。

四、投递保障的整体关系

把过滤、重试、退避、TTL 与死信放在一起看,才能理解事件网格的投递保障模型:过滤决定“哪些事件进入投递”,重试与退避决定“投递多少次、间隔多久”,TTL 决定“最多保留多久”,死信决定“最终失败后去哪里”。下图展示了这一关系。

事件网格投递保障:过滤 → 重试/退避 → TTL → 死信 事件源 Blob / 自定义主题 事件筛选 eventType / 主题过滤 StringIn / EndsWith / Number… 投递尝试 HTTP POST / Webhook 成功:2xx 订阅端 Azure Function / 队列 业务处理逻辑 成功 失败:非2xx / 超时 / 连接失败 重试策略 + 指数退避 maxDeliveryAttempts:1~30 eventTimeToLiveInMinutes:1~1440 间隔递增 + 随机抖动 示例:10s → 30s → 1m → 2m → … 重试 TTL 到期? 超过 eventTimeToLive 或重试次数耗尽 死信队列(Blob 容器) 原始事件 + 失败原因 投递次数 + 最后尝试时间 用于排查、告警与重放 最终失败 投递成功 事件被业务消费 无需死信处理 2xx

五、配置与验证要点

在 Azure 门户或 ARM/Bicep 模板中配置事件订阅时,需要同时关注过滤、重试与死信三部分。以下是一个事件订阅的配置片段示例,包含主题过滤、重试策略与死信设置:

{
  "properties": {
    "destination": {
      "endpointType": "AzureFunction",
      "properties": { "resourceId": "/subscriptions/.../functions/ProcessImage" }
    },
    "filter": {
      "includedEventTypes": ["Microsoft.Storage.BlobCreated"],
      "advancedFilters": [
        { "operatorType": "StringEndsWith", "key": "data.url", "values": [".jpg", ".png"] },
        { "operatorType": "StringNotContains", "key": "data.url", "values": ["/thumbnails/"] }
      ]
    },
    "retryPolicy": {
      "maxDeliveryAttempts": 10,
      "eventTimeToLiveInMinutes": 120
    },
    "deadLetterDestination": {
      "endpointType": "StorageBlob",
      "properties": {
        "resourceId": "/subscriptions/.../storageAccounts/dlxstore",
        "blobContainerName": "deadletter"
      }
    }
  }
}

验证时,可先发送一条符合过滤条件的事件,确认订阅端收到;再发送一条不符合条件的事件,确认未被投递;然后模拟订阅端返回 500,观察重试次数与间隔是否符合预期;最后检查死信容器中是否出现失败事件及其元数据。通过这三类验证,可以确认过滤、重试与死信链路均按设计工作。

投递保障的核心不是“永不失败”,而是“失败可见、可重试、可追踪”。过滤减少无效流量,重试与退避提升成功率,TTL 控制资源占用,死信队列保证最终失败不被静默吞没。