← 返回文章列表

Dify 韧性验证实验(05):并发与可靠性——高并发下 AI 应用如何保证可靠?

1. 业务场景

先讲一个我们实际遇到的场景。

一家做客服工单 SaaS 的公司,通过 Webhook 接收外部事件:用户反馈、系统告警、支付回调。事件进来后要验签、去重、处理、通知。某天支付平台重试,同一条回调消息投递了两次——系统没做幂等,处理了两次,用户收到了两条重复的「支付成功」通知;又某天凌晨断线五分钟,期间的告警事件全部丢失,等运维发现时,故障已经持续了一整晚没人处理。

我们第一次接这类需求时,第一反应是「AI 应用嘛,重点在模型效果,消息可靠性是中间件的活」。真正动手才发现——AI 应用也是应用,事件通道该有的可靠性,一条都不能少。我们把传统消息系统那套「不丢、不重、有序」直接搬进 Dify 工作流,发现不仅能搬,还能量化——这比「模型答得好不好」更容易跟客户讲清楚。

这不是个例。任何「外部事件经 Webhook 进入系统」的场景都是这个模式:支付回调、物流状态推送、监控告警——AI 应用也是应用,消息可靠性一点都不能少。

2. 场景痛点

这套链路的痛点,在事件处理链上体现得最直接:

本质上,事件通道的可靠性指标(到达率/重复处理率/乱序率)可以直接量化——这是最容易向客户展示「可靠」的模块

3. 方案:为什么是事件通道可靠性验证

Dify 工作流里验证事件链路最直接的方法,就是把传统消息系统的老三样(不丢/不重/有序)搬到 AI 应用的事件链路上,再加上幂等与可恢复。

选它的理由:

这篇文章我们就用它搭一条「事件处理链」:事件接收 → 验签 → 幂等去重 → 事件处理 → 通知,把消息可靠性验证跑一遍。

4. 整体架构

graph TD start["开始:event_id / payload / signature"] verify{"验签:md5(event_id + payload + secret) 匹配"} rej["end_rej(验签拒绝)"] dedup{"幂等去重:KV 读已处理列表"} dup["end_dup(不重复处理)"] process["事件处理:解析 → 分类 → 响应"] enqueue["入队(KV 写)"] notify["通知(http fail-branch 降级)"] audit["审计(KV 写处理记录)"] end1["end_recv"] start --> verify verify -- "不匹配" --> rej verify -- "匹配" --> dedup dedup -- "已存在" --> dup dedup -- "未处理" --> process process --> enqueue --> notify --> audit --> end1

链路很清晰:事件进入 → 验签 → 幂等去重 → 处理入队 → 通知 → 审计。关键设计是验签失败和重复投递都走独立出口(end_rej / end_dup),与正常路径完全隔离——拒绝和去重都是「正确行为」,不是缺陷。

5. 模块设计

5.1 验签规则(防伪造)

signature = md5(event_id + payload + secret),默认 secret dify105-demo-secret测试输入必须按此规则构造签名,否则 reject 是正确行为,不是缺陷(104-03 实测教训):

def main(event_id: str, payload: str, signature: str) -> dict:

    import hashlib

    secret = "dify105-demo-secret"

    expect = hashlib.md5((event_id + payload + secret).encode()).hexdigest()

    return {"valid": signature == expect}

5.2 幂等去重(本实验核心)

KV 存储记录已处理 event_id,重复投递返回 dup_message(不重复处理、不重复副作用):

def main(event_id: str) -> dict:

    # seen = KV 读已处理列表(http + KV 容器,code 沙箱禁写文件)

    if event_id in seen_list:

        return {"dup": True, "queue_len": len(queue)}

    return {"dup": False, "queue_len": len(queue)}

5.3 消息可靠性三验证(本实验核心)

验证项 方法 判定
不重 同一事件投递两次 → 只处理一次 重复副作用 = P1
不丢 断线模拟 → 恢复后补齐 到达率 100%
有序 多事件顺序保持 乱序 = P2

5.4 枚举校验纪律

事件类型 select 用合法选项——非法值 400 是校验生效,判通过非缺陷(三批实测)。

6. 运行验证

用例 输入要点 预期 结果
正常验签 正确 md5 签名 end_recv「事件已接收并入队,队列长度 1」 通过(实测)
幂等 同 event_id 二次投递 end_dup(不重复入队/不重复副作用) 通过(实测)
伪造签名 错误 signature end_rej(验签 reject = 正确行为) 通过(实测)
并发洪峰 同秒 3 事件 全部入队(队列长度 2/3/4,不丢) 通过(实测)
事件分类 feedback / alert / other feedback「已受理」/ alert「已升级处理」/ other「已记录」 通过(实测)
通知失败降级 通知地址不可达 partial-succeeded + final_result 含「(已降级)通知通道异常,事件已记录待人工补偿」 通过(实测)
枚举校验 event_type 非法值 400 = 校验生效(非缺陷) 通过(实测)

7. 实战坑

现象 修复
签名测试输入不符 签名不按 md5 规则构造 → reject 误判 FAIL 测试输入按 md5(event_id+payload+secret) 构造(实测,104-03)
幂等无去重键 重复投递重复处理(重复副作用,P1) event_id 作为去重键,KV set 语义判重(实验文档设计约束)
KV 跨运行持久化 code 沙箱禁写文件 存储走 http + 外部 KV 容器(实测,104 全批)
枚举非法值 400 误报 FAIL 校验生效 = 通过非缺陷(实测,三批)

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。

联系我

15088711270

手机端点击号码可直接拨打 · 桌面端可复制

微信二维码

扫码加微信 · 备注「门户」更快通过