价格

架构总览

相关源文件

本页面内容基于以下源文件生成:

Dify 采用前后端分离的微服务化架构设计,后端基于 Flask 框架构建,通过扩展机制集成数据库、缓存、消息队列等基础设施;前端基于 Next.js 实现服务端渲染与状态管理。整体架构强调模块化、可观测性与高可用性,支持从单机部署到分布式集群的平滑扩展。

系统架构总览

正在加载图表渲染器...

架构要点说明:

  1. 前后端分离:前端 Next.js 应用独立部署,通过 REST API 与后端 Flask 服务通信,支持服务端渲染(SSR)优化首屏性能与 SEO
  2. 扩展驱动设计:后端采用 Flask 扩展模式(init_app),将数据库、缓存、任务队列等基础设施解耦为独立模块,便于测试与替换
  3. 异步任务处理:通过 Celery + Redis 实现长时间运行任务的异步化(如工作流执行、数据索引),避免阻塞 HTTP 请求线程
  4. 可观测性集成:OpenTelemetry 提供分布式追踪与指标采集,支持 OTLP 协议导出到 Jaeger/Prometheus 等后端
  5. 高可用支持:Redis 支持 Sentinel 模式实现故障转移,数据库连接池针对 Gevent 协程进行兼容性适配

关键证据点:

应用启动与初始化

Flask 应用入口与工厂模式

后端服务采用工厂模式创建 Flask 应用实例,根据运行环境选择不同的初始化路径。入口文件 api/app.py 通过命令行参数判断当前是否为数据库迁移命令(flask db),从而决定加载轻量级的迁移应用还是完整的生产应用。

python
1# api/app.py 核心逻辑
2def is_db_command() -> bool:
3    if len(sys.argv) > 1 and sys.argv[0].endswith("flask") and sys.argv[1] == "db":
4        return True
5    return False
6
7if is_db_command():
8    from app_factory import create_migrations_app
9    app = create_migrations_app()
10else:
11    from app_factory import create_app
12    app = create_app()
13    celery = cast("Celery", app.extensions["celery"])

职责边界:

  • 做什么:解析命令行参数、选择应用工厂、挂载 Celery 实例到 Flask 扩展字典
  • 不做什么:不直接配置数据库连接、不定义路由、不处理业务逻辑

关键数据结构:

  • sys.argv:命令行参数列表,用于判断运行模式
  • app.extensions["celery"]:Flask 扩展字典,存储 Celery 应用实例引用

错误处理与边界条件:

  • 迁移模式下仅加载数据库配置,避免初始化不必要的扩展(如 Redis、Celery)
  • 生产模式下通过 cast 类型断言确保 Celery 已正确初始化,否则抛出 KeyError

证据点: api/app.py:6-37

数据库连接与 Gevent 兼容性处理

数据库扩展 ext_database.py 在初始化时针对 Gevent 协程环境进行了特殊适配。由于 Gevent 通过 monkey patching 替换标准库的阻塞调用,SQLAlchemy 连接池的 reset 事件可能在协程切换时引发竞态条件,因此需要自定义重置逻辑。

python
1# api/extensions/ext_database.py 核心逻辑
2def _setup_gevent_compatibility():
3    @event.listens_for(Pool, "reset")
4    def _safe_reset(dbapi_connection, connection_record, reset_state):
5        if reset_state.terminate_only:
6            return
7        try:
8            hub = gevent.get_hub()
9            if hasattr(hub, "in_callback") and getattr(hub.loop, "in_callback", False):
10                gevent.spawn_later(0, lambda: _safe_rollback(dbapi_connection))
11            else:
12                _safe_rollback(dbapi_connection)
13        except (AttributeError, ImportError):
14            _safe_rollback(dbapi_connection)

关键调用链:

  1. init_app(app) 被应用工厂调用
  2. db.init_app(app) 初始化 SQLAlchemy 扩展
  3. _setup_gevent_compatibility() 注册连接池事件监听器
  4. 连接归还池时触发 _safe_reset,在安全上下文中执行回滚

错误处理策略:

  • _safe_rollback 捕获所有异常并记录日志,避免回滚失败导致连接泄漏
  • 检测 Gevent hub 状态,在回调上下文中延迟执行回滚,避免嵌套调用

证据点: api/extensions/ext_database.py:16-62

后端核心扩展架构

Celery 异步任务队列配置

Celery 扩展负责配置异步任务队列,支持 Redis 作为 Broker 和 Backend,并提供 SSL 加密、Sentinel 高可用等企业级特性。任务分为两类:即时任务(如工作流触发)和定时任务(如缓存清理)。

python
1# api/extensions/ext_celery.py 核心配置
2celery_app = Celery(
3    app.name,
4    task_cls=FlaskTask,
5    broker=dify_config.CELERY_BROKER_URL,
6    backend=dify_config.CELERY_BACKEND,
7)
8
9# 定时任务调度示例
10if dify_config.ENABLE_CLEAN_EMBEDDING_CACHE_TASK:
11    beat_schedule["clean_embedding_cache_task"] = {
12        "task": "schedule.clean_embedding_cache_task.clean_embedding_cache_task",
13        "schedule": crontab(minute="0", hour="2", day_of_month=f"*/{day}"),
14    }

关键数据结构:

  • FlaskTask:自定义任务基类,在任务执行时自动推送 Flask 应用上下文
  • beat_schedule:Celery Beat 调度字典,定义定时任务的执行计划
  • broker_transport_options:Sentinel 配置,包含主节点名称、超时时间等

SSL 配置逻辑:

  • 仅当 BROKER_USE_SSL=True 且 Broker URL 以 redis://rediss:// 开头时启用
  • 支持配置 CA 证书、客户端证书、密钥文件等 SSL 参数

定时任务分类:

任务类型示例任务调度频率
清理任务clean_embedding_cache_task每月 2:00 AM
监控任务queue_monitor_task每 30 分钟
工作流任务workflow_schedule_task可配置间隔

证据点: api/extensions/ext_celery.py:13-209

Redis 缓存客户端封装

Redis 扩展通过 RedisClientWrapper 类封装客户端实例,支持延迟初始化和动态切换。这种设计特别适用于 Sentinel 模式,当主节点故障转移后,客户端需要重新获取新的主节点地址。

python
1# api/extensions/ext_redis.py 核心封装
2class RedisClientWrapper:
3    _client: Union[redis.Redis, RedisCluster, None]
4
5    def __getattr__(self, item: str) -> Any:
6        if self._client is None:
7            raise RuntimeError("Redis client is not initialized. Call init_app first.")
8        return getattr(self._client, item)

职责边界:

  • 做什么:提供统一的 Redis 操作接口、支持 Sentinel/Cluster 模式、SSL 连接配置
  • 不做什么:不实现缓存策略(如 TTL 管理)、不封装业务逻辑

SSL 配置映射:

python
1cert_reqs_map = {
2    "CERT_NONE": ssl.CERT_NONE,
3    "CERT_OPTIONAL": ssl.CERT_OPTIONAL,
4    "CERT_REQUIRED": ssl.CERT_REQUIRED,
5}

客户端缓存支持:

  • 仅在 RESP3 协议下启用(REDIS_SERIALIZATION_PROTOCOL >= 3
  • 通过 CacheConfig 配置客户端侧缓存,减少网络往返

证据点: api/extensions/ext_redis.py:29-158

OpenTelemetry 可观测性集成

OpenTelemetry 扩展提供分布式追踪和指标采集能力,支持 OTLP 协议导出到 Jaeger、Prometheus 等后端。资源配置遵循 Semantic Conventions 1.32.0 规范,包含服务名称、版本、进程 ID 等标准属性。

python
1# api/extensions/ext_otel.py 资源配置
2resource = Resource(
3    attributes={
4        SERVICE_NAME: dify_config.APPLICATION_NAME,
5        SERVICE_VERSION: f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}",
6        PROCESS_PID: os.getpid(),
7        DEPLOYMENT_ENVIRONMENT_NAME: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}",
8    }
9)

导出器选择逻辑:

协议类型Trace 导出器Metric 导出器
grpcGRPCSpanExporterGRPCMetricExporter
httpHTTPSpanExporterHTTPMetricExporter
其他ConsoleSpanExporterConsoleMetricExporter

采样策略:

  • 使用 ParentBasedTraceIdRatio 采样器,根据配置的 OTEL_SAMPLING_RATE 决定是否采样
  • 采样率范围 0.0-1.0,0.1 表示采样 10% 的请求

批处理配置:

  • max_queue_size:队列最大容量(默认 2048)
  • schedule_delay_millis:导出间隔(默认 5000ms)
  • max_export_batch_size:单次导出批量大小(默认 512)

证据点: api/extensions/ext_otel.py:14-136

邮件服务扩展

邮件扩展支持多种邮件服务提供商,包括 Resend、SMTP、SendGrid。通过配置 MAIL_TYPE 环境变量选择提供商,并在初始化时验证必要参数。

python
1# api/extensions/ext_mail.py 提供商选择
2match mail_type:
3    case "resend":
4        resend.api_key = api_key
5        self._client = resend.Emails
6    case "smtp":
7        self._client = SMTPClient(server=..., port=..., use_tls=...)
8    case "sendgrid":
9        self._client = SendGridClient(sendgrid_api_key=..., _from=...)

错误处理:

  • 未配置 MAIL_TYPE 时记录警告日志但不抛出异常
  • 缺少必要参数(如 RESEND_API_KEY)时抛出 ValueError
  • 发送邮件前验证 tosubjecthtml 参数非空

证据点: api/extensions/ext_mail.py:11-104

前端应用架构

Next.js 根布局与依赖注入

前端应用基于 Next.js App Router 架构,根布局 layout.tsx 负责注入全局依赖,包括状态管理、主题、国际化(i18nn)、监控等 Provider。这种设计确保所有页面共享统一的上下文环境。

tsx
1// web/app/layout.tsx Provider 嵌套结构
2<JotaiProvider>
3  <ThemeProvider attribute="data-theme" defaultTheme="system">
4    <NuqsAdapter>
5      <BrowserInitializer>
6        <SentryInitializer>
7          <TanstackQueryInitializer>
8            <I18nServerProvider>
9              <ToastProvider>
10                <GlobalPublicStoreProvider>
11                  <TooltipProvider>{children}</TooltipProvider>
12                </GlobalPublicStoreProvider>
13              </ToastProvider>
14            </I18nServerProvider>
15          </TanstackQueryInitializer>
16        </SentryInitializer>
17      </BrowserInitializer>
18    </NuqsAdapter>
19  </ThemeProvider>
20</JotaiProvider>

Provider 职责说明:

Provider职责
JotaiProvider原子化状态管理,用于全局状态共享
ThemeProvider主题切换(亮色/暗色/系统)
NuqsAdapterURL 状态同步,将状态持久化到查询参数
TanstackQueryInitializer服务端状态管理,处理数据缓存与同步
I18nServerProvider国际化,服务端获取用户语言偏好
SentryInitializer错误监控,上报前端异常

关键配置:

  • viewport 设置禁止用户缩放(userScalable: false),确保移动端一致性体验
  • suppressHydrationWarning 避免主题切换时的水合警告

证据点: web/app/layout.tsx:5-97

前端全局配置常量

配置文件 web/config/index.ts 定义了前端应用的全局常量,包括 API 端点、正则规则、默认参数、功能开关等。这些配置通过环境变量注入,支持不同部署环境的差异化配置。

typescript
1// web/config/index.ts API 端点配置
2export const API_PREFIX = getStringConfig(
3  env.NEXT_PUBLIC_API_PREFIX,
4  'http://localhost:5001/console/api',
5)
6export const PUBLIC_API_PREFIX = getStringConfig(
7  env.NEXT_PUBLIC_PUBLIC_API_PREFIX,
8  'http://localhost:5001/api',
9)

关键配置分类:

类别配置项默认值
API 端点API_PREFIXhttp://localhost:5001/console/api
安全CSRF_COOKIE_NAMEcsrf_token__Host-csrf_token
验证MAX_VAR_KEY_LENGTH30
功能开关MAX_TOOLS_NUM环境变量控制
正则规则VAR_REGEX/\{\{(#[\w-]{1,50}...)#\}\}/gi

辅助函数:

  • getStringConfig(envVar, defaultValue):优先使用环境变量,回退到默认值
  • getMaxVarNameLength(value):根据字符类型(中文/英文)返回最大变量名长度
  • getMaxToken(modelId):根据模型 ID 返回最大 Token 数

证据点: web/config/index.ts:1-380

前端工具函数

通用工具函数

工具文件 web/utils/index.ts 提供了基础的异步错误处理、文本测量、随机字符串生成等通用函数。其中 asyncRunSafe 函数采用 Go 语言风格的错误处理模式,将异常转换为元组返回。

typescript
1// web/utils/index.ts 异步错误包装
2export async function asyncRunSafe<T = any>(fn: Promise&lt;T&gt;): Promise<[Error] | [null, T]> {
3  try {
4    return [null, await fn]
5  }
6  catch (e: any) {
7    return [e || new Error('unknown error')]
8  }
9}

关键函数说明:

函数职责返回值
asyncRunSafe包装 Promise,捕获异常[Error][null, T]
getTextWidthWithCanvas使用 Canvas 测量文本宽度number(像素)
randomString(length)生成指定长度的随机字符串string
getPurifyHref(href)转义 URL 防止 XSSstring
fetchWithRetry(fn, retries)带重试机制的请求Promise<[Error] | [null, T]>

错误处理策略:

  • asyncRunSafe 捕获所有异常,包括 unknown error 情况
  • fetchWithRetry 在失败时递归调用,直到重试次数耗尽

证据点: web/utils/index.ts:8-47

关键数据流与调用链

正在加载图表渲染器...

数据流要点说明:

  1. 请求入口:浏览器请求首先到达 Next.js 根布局,初始化全局 Provider(状态管理、主题、国际化)
  2. API 调用:前端通过 API_PREFIX 配置的端点发送 HTTP 请求到 Flask 后端
  3. 扩展初始化:Flask 应用启动时通过 init_app 方法初始化数据库、Redis、Celery 等扩展
  4. 异步任务:长时间运行的操作(如工作流执行)通过 Celery 异步化,避免阻塞 HTTP 线程
  5. 结果存储:Celery 任务结果存储在 Redis 中,前端通过轮询或 WebSocket 获取状态更新

关键证据点:

核心设计决策与取舍

1. 工厂模式 vs 单例模式

选择理由:采用工厂模式(create_app / create_migrations_app)而非全局单例,便于在测试环境中创建隔离的应用实例,支持多租户场景下的配置切换。

已知限制:需要显式传递应用实例到扩展初始化函数,增加了代码耦合度。

2. Gevent 协程 vs 线程

选择理由:使用 Gevent 协程处理高并发 I/O 密集型请求,相比线程模型减少内存占用和上下文切换开销。

已知限制:需要 monkey patching 标准库,可能与某些不兼容的第三方库冲突;数据库连接池需要特殊处理。

证据点: api/extensions/ext_database.py:16-62

3. Celery 任务基类设计

选择理由:自定义 FlaskTask 基类在任务执行时自动推送应用上下文,确保任务内部可以访问 Flask 扩展(如数据库、缓存)。

替代方案:在每个任务函数内部手动推送上下文,但会导致代码重复。

证据点: api/extensions/ext_celery.py:13-209

4. Redis 客户端封装

选择理由:通过 RedisClientWrapper 延迟初始化客户端,支持 Sentinel 模式下的动态主节点切换。

已知限制:封装层增加了调用链深度,可能影响性能敏感场景。

证据点: api/extensions/ext_redis.py:29-158

5. OpenTelemetry 采样策略

选择理由:使用 ParentBasedTraceIdRatio 采样器,确保跨服务的追踪链完整性(子 span 跟随父 span 采样决策)。

替代方案:固定采样率可能导致高流量场景下丢失关键追踪,或低流量场景下采样过多。

证据点: api/extensions/ext_otel.py:14-136

6. 前端 Provider 嵌套顺序

选择理由JotaiProvider 作为最外层确保状态管理可用;ThemeProvider 在内部避免主题切换触发状态重置;SentryInitializer 包裹业务组件以捕获所有异常。

已知限制:深层嵌套增加组件树复杂度,调试时需要追踪多层上下文。

证据点: web/app/layout.tsx:5-97

技术选型表格

技术用途选型理由替代方案
Flask后端 Web 框架轻量级、扩展性强、生态成熟Django(过于重量级)、FastAPI(异步支持但生态较新)
Next.js前端框架支持 SSR/SSG、App Router 架构、TypeScript 原生支持Create React App(无 SSR)、Remix(生态较小)
Celery异步任务队列功能完善、支持定时任务、与 Flask 集成良好RQ(功能较少)、Dramatiq(社区较小)
Redis缓存/消息队列高性能、支持多种数据结构、Sentinel 高可用Memcached(无持久化)、KeyDB(生态较小)
PostgreSQL关系型数据库功能强大、支持 JSONB、扩展性好MySQL(JSON 支持较弱)、SQLite(不适合生产)
OpenTelemetry可观测性标准化协议、支持多语言、厂商中立Jaeger(仅追踪)、Prometheus(仅指标)
Jotai状态管理原子化设计、TypeScript 友好、性能优秀Redux(样板代码多)、Zustand(缺少原子化)
TanStack Query服务端状态自动缓存、后台更新、请求去重SWR(功能较少)、RTK Query(绑定 Redux)

模块依赖关系图

正在加载图表渲染器...

依赖关系说明:

  1. 后端核心依赖app.py 作为入口依赖所有扩展模块,扩展模块各自依赖对应的第三方库
  2. 前端依赖链layout.tsx 依赖配置和工具模块,但不直接依赖后端模块
  3. 跨层通信:前后端通过 HTTP API 通信,无直接代码依赖

关键配置与启动流程

环境变量配置清单

变量名用途默认值必需
CELERY_BROKER_URLCelery Broker 地址-
CELERY_BACKENDCelery 结果后端redis
REDIS_USE_SSLRedis SSL 开关False
BROKER_USE_SSLCelery SSL 开关False
OTEL_EXPORTER_TYPEOpenTelemetry 导出器类型console
OTLP_BASE_ENDPOINTOTLP 端点地址-
MAIL_TYPE邮件服务类型-
NEXT_PUBLIC_API_PREFIX前端 API 端点http://localhost:5001/console/api

启动流程时序

  1. 后端启动

    • 解析命令行参数,判断运行模式(迁移/生产)
    • 调用应用工厂创建 Flask 实例
    • 初始化扩展(数据库 → Redis → Celery → OpenTelemetry)
    • 注册路由蓝图
    • 启动 HTTP 服务器(Gunicorn)
  2. 前端启动

    • 加载环境变量到 env 对象
    • 解析根布局,初始化 Provider 树
    • 服务端渲染页面 HTML
    • 客户端水合,绑定事件处理
  3. Celery Worker 启动

    • 加载 Flask 应用上下文
    • 连接 Broker(Redis)
    • 注册任务模块
    • 启动任务消费者

关键证据点: