> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-fbfa8bee.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 异步插入 (async_insert)

> 使用异步插入作为批量处理数据的替代方案。

当客户端侧批处理不可行时，ClickHouse 的异步插入提供了一种强有力的替代方案。这在可观测性工作负载中尤其有价值，因为成百上千个 agent 会持续发送数据——日志、指标、链路追踪——而且这些数据通常都是小型、实时的载荷。在这类环境中，在客户端侧缓冲数据会增加复杂性，因为需要集中式队列来确保能够发送足够大的批次。

<Note>
  不建议在同步模式下发送大量小批次，这会导致创建许多 parts，进而造成查询性能下降，并引发["too many part"](/zh/resources/support-center/knowledge-base/troubleshooting/exception-too-many-parts)错误。
</Note>

异步插入会先将传入数据写入内存缓冲区，再根据可配置的阈值将其刷写到存储，从而把批处理责任从客户端转移到服务器端。这种方式可显著减少 parts 创建开销、降低 CPU 使用率，并确保摄取即使在高并发下也能保持高效。

其核心行为由 [`async_insert`](/zh/reference/settings/session-settings#async_insert) 设置控制。

<Image img="/images/bestpractices/async_inserts.png" size="lg" alt="异步插入" />

异步插入同时支持 HTTP 和原生 TCP 接口。

启用后 (`async_insert = 1`) ，插入操作会先被缓冲，只有在满足以下某个刷写条件时才会写入磁盘：

* 缓冲区达到指定的数据大小 ([`async_insert_max_data_size`](/zh/reference/settings/session-settings#async_insert_max_data_size)，默认 100 MiB) 。
* 达到时间阈值 ([`async_insert_busy_timeout_ms`](/zh/reference/settings/session-settings#async_insert_busy_timeout_max_ms)，默认 200 ms，在 Cloud 上为 1000 ms) 。
* 累积到最大插入查询数 ([`async_insert_max_query_number`](/zh/reference/settings/session-settings#async_insert_max_query_number)，默认 450) 。

哪个阈值先达到，就会触发刷写。

这一批处理过程对客户端是透明的，并帮助 ClickHouse 高效合并来自多个来源的插入流量。不过，在发生刷写之前，这些数据无法被查询。需要特别注意的是，针对每种插入形态与设置组合，都会有多个缓冲区；而在集群中，缓冲区则按节点分别维护——从而能够在多租户环境中实现细粒度控制。除此之外，插入机制与[同步插入](/zh/concepts/best-practices/selecting-an-insert-strategy#synchronous-inserts-by-default)中描述的内容完全相同。

<div id="choosing-a-return-mode">
  ### 选择返回模式
</div>

可以通过 [`wait_for_async_insert`](/zh/reference/settings/session-settings#wait_for_async_insert) 设置进一步细化异步插入的行为。

当该值设为 1 (默认值) 时，ClickHouse 只有在数据成功写入磁盘后才会确认插入。这样可以提供更强的持久性保障，也让错误处理更直接：如果在刷写期间发生问题，错误会返回给客户端。对于大多数生产场景，尤其是在必须可靠跟踪插入失败时，建议使用此模式。

[基准测试](https://clickhouse.com/blog/asynchronous-data-inserts-in-clickhouse) 表明，得益于自适应插入以及稳定的 part 创建行为，它在并发场景下也能很好地扩展——无论是运行 200 个还是 500 个客户端。

将 `wait_for_async_insert = 0` 设为 0 会启用“发出即忘”模式。在这种模式下，server 会在数据进入缓冲区后立即确认插入，而不会等待其写入存储。

这种方式可实现超低延迟插入和最高吞吐量，非常适合高速度、低关键性的数据场景。但这也有代价：无法保证数据一定会持久化，错误只会在刷写期间暴露，而且失败的插入也没有 dead-letter queue——要追踪失败，只能事后检查服务器日志和系统表。只有在你的 workload 可以容忍数据丢失时，才应使用此模式。

[基准测试还表明](https://clickhouse.com/blog/asynchronous-data-inserts-in-clickhouse)，当缓冲区刷写不频繁时 (例如每 30 秒一次) ，part 数量会显著减少，CPU 使用率也会更低，但静默失败的风险依然存在。

我们的强烈建议是：如果使用异步插入，请使用 `async_insert=1,wait_for_async_insert=1`。使用 `wait_for_async_insert=0` 风险很高，因为即使发生错误，你的 INSERT 客户端也可能毫不知情；此外，如果客户端在 ClickHouse server 需要降低写入速度并施加反压以确保服务可靠性时仍持续快速写入，还可能导致潜在过载。

<div id="adaptive-async-inserts">
  ### 自适应异步插入
</div>

从 24.2 版本开始，ClickHouse 默认使用自适应刷写超时 ([`async_insert_use_adaptive_busy_timeout`](/zh/reference/settings/session-settings#async_insert_use_adaptive_busy_timeout)) 。不再使用固定的刷写间隔，而是根据传入数据速率，在最小值 ([`async_insert_busy_timeout_min_ms`](/zh/reference/settings/session-settings#async_insert_busy_timeout_min_ms)，默认 50 毫秒) 和最大值 ([`async_insert_busy_timeout_max_ms`](/zh/reference/settings/session-settings#async_insert_busy_timeout_max_ms)，默认 200 毫秒，Cloud 上为 1000 毫秒) 之间动态调整超时。

当数据频繁到达时，超时会保持更接近最小值，以便更早刷写并降低端到端延迟。当数据较为稀疏时，超时则会增大并趋近最大值，以积累更大的批次。这在默认模式 (`wait_for_async_insert=1`) 下尤其有用，因为如果使用固定且较高的超时，即使数据已经可以刷写，客户端仍需阻塞等待整个时间间隔结束。

<div id="error-handling">
  ### 错误处理
</div>

Schema 验证和数据解析发生在缓冲区 刷写 时，而不是在收到插入时进行。如果某个插入查询中的任意一行出现解析错误或类型错误，**该查询中的所有数据都不会被 刷写**——整个查询的载荷都会被拒绝。在默认模式 (`wait_for_async_insert=1`) 下，错误会返回给客户端。在发出即忘模式下，错误会被写入服务器日志和 [`system.asynchronous_inserts`](/zh/reference/system-tables/asynchronous_inserts) 表。

每次 刷写 都会针对缓冲区中每个不同的分区键值至少创建一个 part。即使对于没有分区键的表，如果缓冲数据超过 [`max_insert_block_size`](/zh/reference/settings/session-settings#max_insert_block_size) (默认约 100 万行) ，单次 刷写 也可能生成多个 parts。

<Note>
  即使使用了异步插入，如果分区键的基数较高，你仍然可能遇到["parts 过多"](/zh/resources/support-center/knowledge-base/troubleshooting/exception-too-many-parts)错误。
</Note>

<div id="deduplication-and-reliability">
  ### 去重与可靠性
</div>

默认情况下，ClickHouse 会对同步插入自动去重，因此在发生故障时进行重试也是安全的。不过，对异步插入而言，除非显式启用，否则该功能默认关闭 (如果你有依赖它的 materialized view，则不应启用——[参见 issue](https://github.com/ClickHouse/ClickHouse/issues/66003)) 。

在实际使用中，如果开启了去重，并且同一次插入因超时或网络中断等原因被重试，ClickHouse 就可以安全地忽略重复数据。这有助于保持幂等性，避免数据被重复写入。

<div id="enabling-asynchronous-inserts">
  ### 启用异步插入
</div>

可以为特定用户或特定查询启用异步插入：

* 在用户级别启用异步插入。此示例使用用户 `default`；如果你创建了其他用户，请将其替换为相应的用户名：
  ```sql theme={null}
  ALTER USER default SETTINGS async_insert = 1
  ```
* 你可以通过插入查询的 SETTINGS 子句指定异步插入设置：
  ```sql theme={null}
  INSERT INTO YourTable SETTINGS async_insert=1, wait_for_async_insert=1 VALUES (...)
  ```
* 使用 ClickHouse 编程语言客户端时，也可以将异步插入设置指定为连接参数。

  例如，使用 ClickHouse Java JDBC 驱动连接到 ClickHouse Cloud 时，可以在 JDBC 连接字符串中这样设置：

  ```bash theme={null}
  "jdbc:ch://HOST.clickhouse.cloud:8443/?user=default&password=PASSWORD&ssl=true&custom_http_params=async_insert=1,wait_for_async_insert=1"
  ```

<Note>
  异步插入不适用于 `INSERT INTO ... SELECT` 查询。当插入包含 `SELECT` 子句时，无论 `async_insert` 设置如何，查询始终都会同步执行。
</Note>

<div id="flushing-buffers-on-shutdown">
  ### 关闭时刷新缓冲区
</div>

如需刷新所有待处理的 async insert 缓冲区 (例如在优雅关闭期间或维护前) ，请运行：

```sql theme={null}
SYSTEM FLUSH ASYNC INSERT QUEUE
```

这可确保在服务器停止前，所有缓冲的数据都会先写入存储。

<div id="comparison-with-buffer-tables">
  ### 与缓冲表的比较
</div>

异步插入是 [缓冲表](/zh/reference/engines/table-engines/special/buffer) 的现代替代方案。主要区别如下：

* **无需修改 DDL。** 异步插入对用户是透明的——你只需启用一个设置，无需创建额外的表。
* **按形态缓冲。** 异步插入会针对每种唯一的查询形态和设置组合维护单独的缓冲区，从而实现更细粒度的刷写策略。缓冲表则是每个目标表只有一个缓冲区。
* **持久性。** 在默认模式 (`wait_for_async_insert=1`) 下，客户端收到确认之前，数据就已写入磁盘。缓冲表的行为类似“发出即忘”——如果发生崩溃，缓冲中的数据会丢失。
* **集群行为。** 在集群中，异步插入缓冲区按节点分别维护。缓冲表则需要在每个节点上显式创建。
