一、问题背景

最近在整一个大模型的项目,生产环境用的是一台标准的 8核 16G 云服务器,上面自己独立部署了 Dify 平台。

我们的业务主要已AI对话+工作流为主,没有大文件处理和知识库管理。

  • 不玩重活:完全没有大文件解析、数据集批量导入,或者知识库切片这种疯狂吃内存的“重体力活”。
  • 全是业务:纯粹的 Workflow 工作流和 Agent 智能体调度,里面塞满了各种大模型(LLM)节点,而且基本全是 Stream 流式输出。

刚上线并发一上来,前端和 API 就频繁蹦出 504 Gateway Timeout。去服务器上一看,16G 内存还剩一大截,但 CPU 各个核心忙得不均匀,Web 请求排大队。

进一步排查发现,Dify 的默认配置(尤其是官方 docker-compose.yml.env 模板)主要面向本地开发或单实例部署优化,部分核心参数过于保守,在高并发或生产级负载下会成为性能瓶颈。

经过一系列参数排查与调优,重点围绕 API 服务层(Gunicorn)与后台任务层(Celery)两组核心配置展开。

二、Dify官方关键参数详解

2.1 API 服务层(Gunicorn)参数

Dify 的 API 服务基于 Gunicorn 作为 WSGI HTTP 服务器。以下三个参数直接决定了 API 的并发处理能力:

参数 作用 默认值 说明
SERVER_WORKER_AMOUNT Gunicorn 工作进程数 1 每个进程可独立处理请求,充分利用多核 CPU
SERVER_WORKER_CLASS 工作模式 gevent 使用协程处理 I/O 密集型并发连接
SERVER_WORKER_CONNECTIONS 每个进程的最大连接数 10 配合 gevent 模式生效,决定单进程并发通道数

注意:Dify API 服务的理论最大并发连接数可近似理解为:

SERVER_WORKER_AMOUNT × SERVER_WORKER_CONNECTIONS

实际并发能力还受数据库连接池、下游 LLM API 延迟等因素制约。

2.2 后台任务层(Celery)参数

知识库文档上传、解析、向量化、索引构建等耗时操作由 Celery 异步任务队列处理。相关核心参数如下:

参数 作用 默认值
CELERY_WORKER_AMOUNT Celery Worker 进程数(并发消费能力) 1
CELERY_AUTO_SCALE 是否启用自动扩缩容 false
CELERY_MAX_WORKERS 自动扩缩容时的最大 Worker 数
CELERY_MIN_WORKERS 自动扩缩容时的最小 Worker 数

2.3 数据库连接池参数

调高 API 并发后,数据库连接数会成为新的瓶颈,需同步调整:

参数 作用 默认值
SQLALCHEMY_POOL_SIZE SQLAlchemy 连接池大小 30
SQLALCHEMY_MAX_OVERFLOW 连接池溢出上限 10
POSTGRES_MAX_CONNECTIONS PostgreSQL 最大连接数 100

三、配置实践

3.1 问题诊断流程

在调整参数前,建议按以下步骤完成诊断:

  1. 检查服务器资源基线

    free -h          # 查看内存
    df -h            # 查看磁盘
    nproc 或 lscpu   # 查看 CPU 核心数
    
  2. 确认 Celery 队列积压情况

    redis-cli -h redis -p 6379 llen celery   # 查看队列长度
    
  3. 检查 Worker 日志

    docker logs -f dify-celery-worker        # 观察是否有异常或长时间无日志
    
  4. 确认 Worker 存活状态

    celery -A app.celery_worker inspect ping  # 检查所有 Worker 心跳
    

3.2 生产环境8核CPU配置修改

首先是web服务的Gunicorn参数。官方默认使用gevent作为处理方式。

woker推荐并发数:CPU 核心数 × 2 + 1, 保证 8 个物理核心在全并发的时候,每个核心都有至少 2 个进程在疯狂轮询。

每个worker的任务数设置为200,合计可以处理 17 * 200并发量,估计我们系统也没有这么高并发,可以再往下降低,后续看情况调整。

# ============ API 服务层(Gunicorn)============
SERVER_WORKER_AMOUNT=17
# gevent 模式:利用协程处理 I/O 密集型并发
SERVER_WORKER_CLASS=gevent
# 每个 Worker 的最大连接数
SERVER_WORKER_CONNECTIONS=200

别忘了,咱们是纯 Agent/Workflow 场景,绝大多数同步工作流在 Web 进程(SERVER)里直接就跑完了,Celery 顶多接一点零星的异步重试或者后台调度。Celery 进程开多了,反而会跟 SERVER 抢 CPU 资源,光是上下文切换就够系统内耗的了。

所以, Celery 这边我们可以调小一点:

CELERY_WORKER_AMOUNT=4
CELERY_WORKER_CLASS=gevent
CELERY_WORKER_CONCURRENCY=200

3.3、 容易忽视的死穴:数据库 连接池

当全 Gevent 给你提供了几千个潜在并发通道时,底层的数据库(PostgreSQL)立马就成了新的瓶颈。这块要是配不对,Python 端会疯狂报连接池干了,要么数据库直接 down 掉。

# ============ 数据库连接池 ============
# 连接池大小需与 API 并发能力匹配
SQLALCHEMY_POOL_SIZE=200

3.3 配置生效

修改 .env 文件后,需重启相关容器使配置生效:

docker-compose down
docker-compose up -d

若仅需重启 Celery Worker,可执行:

docker-compose restart celery-worker

3.4 验证方法

配置生效后,建议通过以下方式验证:

  1. 观察队列长度下降

    redis-cli -h redis -p 6379 llen celery
    

    确认队列长度持续下降至个位数。

  2. 检查 Worker 状态

    celery -A app.celery_worker inspect active   # 查看当前执行的任务列表
    celery -A app.celery_worker inspect stats    # 获取 Worker 实时负载
    
  3. 在 Dify Web UI 中观察:知识库文件状态是否由“排队中”逐步转为“已完成”。

四、常见问题与排查要点

4.1 后台任务长期卡在“排队中”

现象:上传文档后长期处于 “Processing…” 状态,无法完成。

根因:Celery Worker 并发处理能力不足,任务积压在 Redis 消息队列中,形成“生产快、消费慢”的局面。

解决方案

  • 提升 CELERY_WORKER_AMOUNT
  • 启用 CELERY_AUTO_SCALE 实现动态扩缩容
  • 若积压严重且为测试环境,可考虑清空队列(生产环境慎用

4.2 API 响应慢、聊天卡顿

排查方向

  • 检查 SERVER_WORKER_AMOUNT 是否过低
  • 确认 SERVER_WORKER_CLASS 是否设置为 gevent
  • 检查 CPU、内存资源是否已耗尽
  • 确认数据库连接池是否已满(SQLALCHEMY_POOL_SIZE 不足)

4.3 数据库连接数耗尽

现象:高并发下出现数据库连接失败错误。

根因:API 并发提升后,每个 Worker 需要独立的数据库连接,默认连接池大小不足。

解决方案:同步调高 SQLALCHEMY_POOL_SIZEPOSTGRES_MAX_CONNECTIONS

五、总结

Dify 生产环境性能调优的核心在于不同层次的并发调整:

  1. API 接入层SERVER_WORKER_AMOUNT 决定并行处理能力,推荐 CPU 核心数 × 2 + 1
  2. 后台任务层CELERY_WORKER_AMOUNT 决定异步任务吞吐能力,推荐 CPU 核心数,配合自动扩缩容
  3. 数据库连接层SQLALCHEMY_POOL_SIZE 必须与 API 并发能力匹配,否则上层调优将受制于连接池瓶颈

这台 8核 16G 的机器在跑纯 Workflow/Agent 的时候,吞吐量直接翻了好几倍,再也没卡出过 504 延迟。