Dify 配完了怎么知道对不对?5 个关键指标 + 诊断命令
前 5 篇把 Nginx、Gunicorn、Celery、GraphEngine、模型网关全调了一遍。参数改完了,但你怎么知道改对了?有没有哪个地方悄悄在排队?有没有哪个参数你调了但没生效?
📌 适用版本:Dify v1.9.x --- e-1.15.0 | 最后更新:2026-07-08
⚠️ 前置条件:
- 本文假定你已完成前 5 篇的配置调整(Nginx/Gunicorn/Celery/GraphEngine/LiteLLM)。链路全调完了才轮到验证,否则你看到的问题可能来自没调对的地方而非参数本身。
- 本文所有诊断命令均为社区版可用,不依赖任何商业版功能。
核心结论
Dify 调完参数不是终点,验证才是。 很多人改完 .env 就以为搞定了,过两天用户喊慢才回来查------问题不是参数调错了,是根本没验证参数是否生效、瓶颈是否转移到了别的地方。
5 个指标就够了:
- Redis 队列深度 --- 哪里在排队
- 任务执行时长 --- 哪里跑得慢
- Worker 资源占用 --- CPU/内存是否到顶
- 错误模式 --- 429 / 连接池耗尽 / 超时分别指向不同层
- 端到端延迟 --- 用户感知到的最终结果
每个指标配一条诊断命令,复制粘贴就能跑。文末有一页诊断流程图,按图索骥。
🧭 本文是「Dify 并发急救手册」系列第 6 篇。前五篇覆盖了 Nginx → Gunicorn → Celery → GraphEngine → LiteLLM 五层链路,本文回答最后一个问题:链路调通了,怎么验证?
指标一:Redis 队列深度------哪里在排队
Dify 的所有异步任务(工作流执行、知识库索引、邮件发送、数据集操作)都经过 Celery 投递到 Redis 队列。队列深度直接反映哪里积压了。
看什么
bash
# 进入 Redis 容器
docker exec -it dify-redis-1 redis-cli
# 查看核心队列长度(Dify 社区版共 16 个 Celery 队列,以下是日常最需要关注的 5 个)
LLEN workflow_based_app_execution
LLEN workflow
LLEN dataset
LLEN mail
LLEN ops_trace
两个 workflow 队列的区别:
workflow_based_app_execution是你在 Web UI 里点击"运行"触发的 Chatflow/Workflow。workflow是定时触发、API 触发等异步触发的 Workflow。日常负载主要看前者。
怎么看
| 队列 | 正常值 | 警戒值 | 超过警戒值意味着 |
|---|---|---|---|
workflow_based_app_execution |
0-5 | >20 | Chatflow/Workflow 执行排队,GraphEngine Worker 不够 |
workflow |
0-3 | >15 | 触发器/定时工作流排队 |
dataset |
0-3 | >15 | 知识库索引/处理排队,检查 TENANT_ISOLATED_TASK_CONCURRENCY |
mail |
0 | >5 | 邮件发送卡住,通常无关紧要 |
ops_trace |
0-2 | >10 | 运维/追踪任务堆积 |
⚠️ 如果某个队列持续 >50,建议先清空队列再查原因。命令:
DEL workflow(慎用------会丢弃所有等待中的工作流任务)。
联动排查
| 队列暴涨 | 先查哪个参数 | 参考文章 |
|---|---|---|
workflow_based_app_execution |
GRAPH_ENGINE_MIN_WORKERS → MAX_PARALLEL_LIMIT → MAX_SUBMIT_COUNT |
#4 |
workflow |
GRAPH_ENGINE_MIN_WORKERS → Celery Worker 数量 |
#3, #4 |
dataset |
TENANT_ISOLATED_TASK_CONCURRENCY → Celery worker 数量 |
#3 |
ops_trace |
Celery Worker 资源 → 数据库连接池 | #2, #3 |
指标二:任务执行时长------哪里跑得慢
队列深度告诉你"有东西在排队",执行时长告诉你"每个任务跑多久"。这俩要一起看。
看什么
bash
# 最近 100 条工作流日志,提取执行时间
docker logs dify-worker-1 2>&1 | grep -i "task.*succeeded|task.*duration" | tail -20
# 看 Celery Worker 统计(不同 Celery 版本输出结构可能有差异)
docker exec dify-worker-1 celery -A app.celery inspect stats 2>/dev/null
# 如果上面命令报错或输出为空,用这个看 Worker 当前状态:
docker exec dify-worker-1 celery -A app.celery inspect active 2>/dev/null
怎么看
| 工作流类型 | 正常 | 偏慢 | 异常 |
|---|---|---|---|
| 简单对话(1-2 节点) | <3s | 3-8s | >10s |
| 中等工作流(5-10 节点) | <15s | 15-30s | >45s |
| 复杂工作流(含知识库) | <30s | 30-60s | >90s |
如果持续偏慢,先查 GraphEngine 并行是否生效(见 #4),再查模型 API 延迟(见 #5)。
额外检查:调度延迟
任务在队列里等了多久才被取走------这个值反映的是 Worker 是否忙不过来。
perl
# 看 Celery 调度队列的积压任务数
docker exec dify-worker-1 celery -A app.celery inspect reserved 2>/dev/null
# 统计每个 Worker 有多少任务在排队等待执行
docker exec dify-worker-1 celery -A app.celery inspect active 2>/dev/null | grep -c '"id"'
如果 reserved 或 active 任务数持续接近 Worker 并发上限(默认 4),说明 Worker 已经处理不过来了------加 Worker 副本或调大并发。
指标三:Worker 资源------CPU 和内存到顶没
Dify 的瓶颈可能在 CPU(计算密集型工作流)、内存(大量知识库加载)、或两者都不高但就是慢(排队/锁/IO)。
看什么
css
# 实时查看所有 Dify 容器的资源占用
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}" \
$(docker ps --filter "name=dify" -q)
怎么看
| 指标 | 正常 | 预警 | 危险 |
|---|---|---|---|
| API Server CPU | <50% | 50-80% | >80% 持续 5 分钟 |
| Worker CPU | <70% | 70-90% | >90% 持续 5 分钟 |
| API Server 内存 | <60% | 60-80% | >85% |
| Worker 内存 | <70% | 70-85% | >90% |
CPU 满但内存低 → 调大 Worker 数量或垂直升配 内存满但 CPU 低 → 知识库/数据集太大,考虑调大容器内存限制 都不高但慢 → 不是资源问题,回到指标一查排队,或指标四查错误
单机全貌
ruby
# 宿主机层面:所有 Dify 容器 + Redis + PostgreSQL 的总资源
htop -p $(pgrep -d, -f "dify|redis|postgres")
指标四:错误模式------不是所有报错都一样
错误日志里的不同关键词指向完全不同的瓶颈层。别一看到报错就乱调参数。
常用 grep 速查
bash
# 所有错误汇总(替换容器名为实际名称)
docker logs dify-api-1 2>&1 | grep -iE "error|exception|timeout|refused|429|413|502|503" | tail -50
docker logs dify-worker-1 2>&1 | grep -iE "error|exception|timeout|retry|failed" | tail -50
错误模式 → 根因
| 错误关键词 | 问题层 | 先查哪个参数 | 参考文章 |
|---|---|---|---|
429 Too Many Requests |
模型 API | LiteLLM Key 数量 + RPM 配额 | #5 |
QueuePool limit / connection timed out |
数据库连接池 | SQLALCHEMY_POOL_SIZE |
#2 |
WorkerLostError / missed heartbeat |
Celery Worker | Worker 内存不足或 OOM | #3 |
413 Request Entity |
Nginx 入口 | NGINX_CLIENT_MAX_BODY_SIZE |
#2 |
Task timeout / SoftTimeLimitExceeded |
任务超时 | WORKFLOW_MAX_EXECUTION_TIME |
#3 |
Connection refused (Redis) |
Redis | REDIS_MAX_CONNECTIONS / Redis 内存 |
--- |
could not connect / remaining connection slots |
数据库不可达 | PostgreSQL 连接数耗尽 / 磁盘空间 | --- |
指标五:端到端延迟------用户实际感知
前四个指标看的是内部,这个看的是外部------用户打开页面到工作流跑完的全链路时间。
看什么
perl
# Nginx 访问日志:看每个请求的响应时间
# 注意:需要 Nginx log_format 包含 $request_time,否则以下提取不准确
docker logs dify-nginx-1 2>&1 | grep -v "health|static|.js|.css" | tail -50
# 更直接:用 curl 模拟一次工作流请求,看端到端耗时
time curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" \
-H "Authorization: Bearer YOUR_API_KEY" \
"http://localhost:5001/v1/workflows/run"
怎么看
| 响应时间 | 状态 | 行动 |
|---|---|---|
| <2s | ✅ 良好 | --- |
| 2-5s | ⚠️ 尚可 | 观察趋势 |
| 5-10s | 🔶 偏慢 | 查指标一 + 二 |
| >10s | 🔴 有问题 | 逐个跑五个指标的全链路诊断 |
一页诊断流程图
出问题时,按这个顺序排查:
bash
用户反馈慢/报错
│
▼
┌─ 指标五:端到端延迟 >5s? ──否──▶ 正常,观察趋势
│ │ 是
│ ▼
├─ 指标四:日志里有明显错误?
│ ├─ 429 → 去 #5 调 LiteLLM
│ ├─ QueuePool → 调 SQLALCHEMY_POOL_SIZE
│ ├─ heartbeat → Worker 资源不足
│ └─ timeout → 调执行时限
│ │
│ ▼
├─ 指标三:CPU/内存满载?
│ ├─ CPU 满 → 升配或加 Worker
│ ├─ 内存满 → 调大容器限制
│ └─ 都正常 → 继续
│ │
│ ▼
├─ 指标一:哪个队列在排队?
│ ├─ workflow_based_app_execution 暴涨 → GraphEngine Worker
│ ├─ workflow 暴涨 → Celery Worker 不够
│ └─ dataset 暴涨 → TENANT_ISOLATED
│ │
│ ▼
└─ 指标二:任务执行时长偏慢?
├─ GraphEngine 并行没生效 → 回到 #4
└─ 模型 API 慢 → 回到 #5
三个最常被忽视的验证点
1. 参数改完不等于生效
Dify 的大部分环境变量是启动时读一次 ,改 .env 后必须重建容器才能生效:
docker compose down && docker compose up -d
不是 restart------restart 只重启容器进程,不会重新读取 .env 文件。docker compose up -d(不带 down)在检测到配置变更时也会重建容器,但 down + up 最保险。
2. 没设基线
调参之前,先在你自己的环境里跑一次基线测试:
bash
# 用 wrk 或 ab 模拟并发(注意:/health 太轻量,建议换成实际接口)
wrk -t4 -c20 -d30s --timeout 10s http://localhost:5001/v1/workflows/run
记下基线 QPS、P50/P99 延迟。调完后跑同样的测试,数字说话。实测示例:4核8GB 默认配置下基线 QPS ≈ 3-5,调完前 5 篇全部参数后 QPS ≈ 12-18------3-6 倍差距,数据不撒谎。
3. 只看平均值,不看 P99
平均值骗人。20 个请求平均 2 秒,但其中 1 个等了 30 秒------平均看不出来。Nginx 日志里记录的是单个请求时间,多收集几个看分布。真实案例:默认配置下 P50=2.1s、P99=28s------差了 13 倍。调完 GraphEngine 并行 + LiteLLM 双 Key 后 P50=1.8s、P99=4.3s,P99 降了 85%。
系列索引
| # | 文章 | 覆盖层 |
|---|---|---|
| 1 | Dify 自部署为什么跑不动? | 全链路诊断框架 |
| 2 | Gunicorn + Nginx 的正确打开方式 | 入口层 + 数据库连接池 |
| 3 | 拆解 Dify 的 Celery | 任务队列层 |
| 4 | 你的 Dify 并行节点其实在串行? | 工作流引擎层 |
| 5 | LiteLLM 网关双 Key 负载均衡 | 模型 API 层 |
| 6 | 本文:监控诊断 | 验证 + 排错 |
📦 本系列完结后,会整理一份配置工具箱------包含参数联动速查表、4核/8核完整配置文件,以及网上流传配置的纠错清单。关注「辉的技术笔记 · 知乎/掘金同步更新」,上线第一时间通知。
下一篇是收官篇:《从 10 并发到 100 并发:Dify 扩容路线图》------什么时候垂直升配、什么时候水平扩容、什么时候该拆服务、K8s 值得上吗。