> ## Documentation Index
> Fetch the complete documentation index at: https://enterprise-docs.dify.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Performance Tuning

## Display Helm Chart Values

```bash theme={null}
helm show values dify/dify
```

## 1. Adjust Base Resources

Tune replicas and resource limits based on workload, cluster capacity, database connection limits, and queue backlog.

| Category         | Component            | Replicas | Request CPU | Request Mem | Limit CPU | Limit Mem | Notes                                                                            |
| ---------------- | -------------------- | -------- | ----------- | ----------- | --------- | --------- | -------------------------------------------------------------------------------- |
| Core Application | API                  | 2        | 1           | 1 GB        | 1         | 2 GB      | Scale based on API QPS and latency                                               |
|                  | Worker               | 4        | 4           | 4 GB        | 4         | 8 GB      | Default catch-all worker; for 3.9.x, prefer the additionalWorkers split strategy |
|                  | Worker Beat          | 1        | 1           | 2 GB        | 2         | 4 GB      | Keep one replica                                                                 |
|                  | Web                  | 1        | 0.5         | 1 GB        | 1         | 2 GB      | Scale based on frontend traffic                                                  |
|                  | Sandbox              | 1        | 2           | 2 GB        | 2         | 4 GB      | Tune based on code execution workload                                            |
| Enterprise       | Enterprise           | 1        | 2           | 2 GB        | 2         | 2 GB      | Scale as needed                                                                  |
|                  | Enterprise\_Audit    | 1        | 1           | 2 GB        | 2         | 4 GB      | Scale as needed                                                                  |
|                  | Enterprise\_Frontend | 1        | 1           | 2 GB        | 1         | 2 GB      | Scale as needed                                                                  |
| Plugin           | Plugin Daemon        | 1        | 1           | 2 GB        | 2         | 4 GB      | Tune for plugin call and install volume                                          |
|                  | Plugin Controller    | 1        | 0.5         | 1 GB        | 1         | 2 GB      | Scale as needed                                                                  |
|                  | Plugin Connector     | 1        | 1           | 2 GB        | 1         | 2 GB      | Scale as needed                                                                  |
|                  | Plugin Manager       | 1        | 1           | 2 GB        | 2         | 4 GB      | Scale as needed                                                                  |
| Infrastructure   | SSRF Proxy           | 1        | 0.5         | 0.5 GB      | 1         | 1 GB      | Scale as needed                                                                  |
|                  | Gateway              | 1        | 1           | 2 GB        | 2         | 4 GB      | Tune for plugin traffic                                                          |
|                  | Unstructured         | -        | -           | -           | -         | -         | Tune based on document parsing workload                                          |
|                  | MinIO                | -        | -           | -           | -         | -         | Tune based on storage throughput and capacity                                    |

Base configuration example:

```yaml theme={null}
api:
  replicas: 2
  serverWorkerAmount: 1

worker:
  replicas: 4
  celeryWorkerAmount: 1

workerBeat:
  resources:
    requests:
      cpu: 1
      memory: 2Gi
    limits:
      cpu: 2
      memory: 4Gi
```

<Warning>
  `workerBeat` should always run as a single replica. Do not scale it horizontally.
</Warning>

## 2. Split Workers by Queue

In 3.9.x, the Helm chart supports `additionalWorkers`. It splits Celery queues that were previously handled by the default `worker` into dedicated Deployments. Each worker can have its own replicas, CPU, memory, and scheduling policy.

The default `worker` is a catch-all worker and consumes all queues. After enabling `additionalWorkers`, use one of the following patterns:

* **Conservative mode**: keep `worker.enabled: true` and only enable dedicated workers for hot queues. The default worker continues to consume queues that have not been split out.
* **Full split mode**: set `worker.enabled: false` and make sure every queue used by your deployment is consumed by an enabled `additionalWorkers` entry. Otherwise, background tasks in uncovered queues will accumulate.

Common worker splits:

| Worker            | Queues                                                                                     | When to use                                                                   |
| ----------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
| `dataset-worker`  | `dataset,priority_dataset,pipeline,priority_pipeline`                                      | Heavy knowledge base import, document parsing, or indexing workloads          |
| `workflow-worker` | `workflow,workflow_storage,workflow_based_app_execution`                                   | High workflow execution or workflow storage load                              |
| `general-worker`  | `mail,ops_trace,app_deletion,conversation,api_token,plugin,retention,enterprise_telemetry` | Email, conversation, plugin, retention, audit, and telemetry background tasks |
| `trigger-worker`  | `schedule_poller,schedule_executor,triggered_workflow_dispatcher,trigger_refresh_executor` | Scheduled tasks and trigger-related workloads                                 |

<Warning>
  If you disable the default `worker`, confirm that dataset, workflow, general background, and trigger queues are all covered by enabled workers. Disabling the default worker after enabling only part of `additionalWorkers` can leave some queues without consumers.
</Warning>

Conservative mode example:

```yaml theme={null}
worker:
  enabled: true
  replicas: 1

additionalWorkers:
  - name: workflow-worker
    enabled: true
    replicas: 2
    celeryQueues: "workflow,workflow_storage,workflow_based_app_execution"
    celeryWorkerAmount: 2
```

Full split mode example:

```yaml theme={null}
worker:
  enabled: false

additionalWorkers:
  - name: dataset-worker
    enabled: true
    replicas: 1
    celeryQueues: "dataset,priority_dataset,pipeline,priority_pipeline"
    celeryWorkerAmount: 4

  - name: workflow-worker
    enabled: true
    replicas: 2
    celeryQueues: "workflow,workflow_storage,workflow_based_app_execution"
    celeryWorkerAmount: 2

  - name: general-worker
    enabled: true
    replicas: 1
    celeryQueues: "mail,ops_trace,app_deletion,conversation,api_token,plugin,retention,enterprise_telemetry"
    celeryWorkerAmount: 1

  - name: trigger-worker
    enabled: true
    replicas: 1
    celeryQueues: "schedule_poller,schedule_executor,triggered_workflow_dispatcher,trigger_refresh_executor"
    celeryWorkerAmount: 1
```

Recommendations:

* If concurrency is high or a queue backlog is visible, increase the corresponding worker's `replicas` first.
* If a single task is memory-heavy, memory usage stays close to the limit, or pods are OOMKilled, increase the corresponding worker's memory limit.
* Do not blindly increase `celeryWorkerAmount`. It increases per-pod concurrency and may increase database connections, Redis connections, and memory usage.
* Keep `workerBeat` at one replica. It schedules tasks but does not replace worker queue consumers.

## 3. Improve External Postgres Performance

Estimate required `max_connections` from API and worker concurrency:

```
Maximum database connections =
  (SQLALCHEMY_POOL_SIZE + SQLALCHEMY_MAX_OVERFLOW) × API serverWorkerAmount × API replicas
+ (SQLALCHEMY_POOL_SIZE + SQLALCHEMY_MAX_OVERFLOW) × default worker celeryWorkerAmount × default worker replicas
+ Σ[(SQLALCHEMY_POOL_SIZE + SQLALCHEMY_MAX_OVERFLOW) × additionalWorker celeryWorkerAmount × additionalWorker replicas]
```

Example:

* API: replicas=2, serverWorkerAmount=1
* Default worker: replicas=4, celeryWorkerAmount=1
* `SQLALCHEMY_POOL_SIZE=100`
* `SQLALCHEMY_MAX_OVERFLOW=150`

```
(100 + 150) × 1 × 2 + (100 + 150) × 1 × 4 = 500 + 1000 = 1500
```

<Warning>
  Reserve 20-30% headroom for traffic spikes. In this example, set `max_connections` to 1800-2000 or higher, and confirm that your database instance can support it.
</Warning>

## 4. Performance Monitoring

| Symptom                                  | Possible Cause                                                                     | Solution                                                                             |
| ---------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| Slow API responses                       | Insufficient API replicas or `serverWorkerAmount`; database slow queries           | Increase API replicas and investigate database slow queries                          |
| Workflow queue backlog                   | Insufficient `workflow-worker` capacity                                            | Increase `workflow-worker.replicas`; raise resource limits if needed                 |
| Slow knowledge base import               | Insufficient `dataset-worker` resources; slow document parsing or vector DB writes | Enable or scale `dataset-worker`; check Unstructured and vector database performance |
| Delayed email, plugin, or retention jobs | `general-worker` queue backlog                                                     | Enable or scale `general-worker`                                                     |
| Delayed scheduled tasks or triggers      | `trigger-worker` queue backlog                                                     | Enable or scale `trigger-worker`; keep `workerBeat` at one replica                   |
| Database connections exhausted           | API/worker concurrency and pool settings are too high                              | Increase `max_connections` or reduce pool/concurrency settings                       |
| OOMKilled pods                           | Task memory usage is high or memory limit is too low                               | Increase memory limits for the affected component and identify memory-heavy tasks    |
| CPU throttling                           | CPU limit is too low                                                               | Increase CPU limits or replicas for the affected component                           |
