不建议在同步模式下发送大量小批次,这会导致创建许多 parts,进而造成查询性能下降,并引发”too many part”错误。
async_insert 设置控制。
异步插入同时支持 HTTP 和原生 TCP 接口。
启用后 (async_insert = 1) ,插入操作会先被缓冲,只有在满足以下某个刷写条件时才会写入磁盘:
- 缓冲区达到指定的数据大小 (
async_insert_max_data_size,默认 100 MiB) 。 - 达到时间阈值 (
async_insert_busy_timeout_ms,默认 200 ms,在 Cloud 上为 1000 ms) 。 - 累积到最大插入查询数 (
async_insert_max_query_number,默认 450) 。
选择返回模式
wait_for_async_insert 设置进一步细化异步插入的行为。
当该值设为 1 (默认值) 时,ClickHouse 只有在数据成功写入磁盘后才会确认插入。这样可以提供更强的持久性保障,也让错误处理更直接:如果在刷写期间发生问题,错误会返回给客户端。对于大多数生产场景,尤其是在必须可靠跟踪插入失败时,建议使用此模式。
基准测试 表明,得益于自适应插入以及稳定的 part 创建行为,它在并发场景下也能很好地扩展——无论是运行 200 个还是 500 个客户端。
将 wait_for_async_insert = 0 设为 0 会启用“发出即忘”模式。在这种模式下,server 会在数据进入缓冲区后立即确认插入,而不会等待其写入存储。
这种方式可实现超低延迟插入和最高吞吐量,非常适合高速度、低关键性的数据场景。但这也有代价:无法保证数据一定会持久化,错误只会在刷写期间暴露,而且失败的插入也没有 dead-letter queue——要追踪失败,只能事后检查服务器日志和系统表。只有在你的 workload 可以容忍数据丢失时,才应使用此模式。
基准测试还表明,当缓冲区刷写不频繁时 (例如每 30 秒一次) ,part 数量会显著减少,CPU 使用率也会更低,但静默失败的风险依然存在。
我们的强烈建议是:如果使用异步插入,请使用 async_insert=1,wait_for_async_insert=1。使用 wait_for_async_insert=0 风险很高,因为即使发生错误,你的 INSERT 客户端也可能毫不知情;此外,如果客户端在 ClickHouse server 需要降低写入速度并施加反压以确保服务可靠性时仍持续快速写入,还可能导致潜在过载。
自适应异步插入
async_insert_use_adaptive_busy_timeout) 。不再使用固定的刷写间隔,而是根据传入数据速率,在最小值 (async_insert_busy_timeout_min_ms,默认 50 毫秒) 和最大值 (async_insert_busy_timeout_max_ms,默认 200 毫秒,Cloud 上为 1000 毫秒) 之间动态调整超时。
当数据频繁到达时,超时会保持更接近最小值,以便更早刷写并降低端到端延迟。当数据较为稀疏时,超时则会增大并趋近最大值,以积累更大的批次。这在默认模式 (wait_for_async_insert=1) 下尤其有用,因为如果使用固定且较高的超时,即使数据已经可以刷写,客户端仍需阻塞等待整个时间间隔结束。
错误处理
wait_for_async_insert=1) 下,错误会返回给客户端。在发出即忘模式下,错误会被写入服务器日志和 system.asynchronous_inserts 表。
每次 刷写 都会针对缓冲区中每个不同的分区键值至少创建一个 part。即使对于没有分区键的表,如果缓冲数据超过 max_insert_block_size (默认约 100 万行) ,单次 刷写 也可能生成多个 parts。
即使使用了异步插入,如果分区键的基数较高,你仍然可能遇到”parts 过多”错误。
去重与可靠性
启用异步插入
-
在用户级别启用异步插入。此示例使用用户
default;如果你创建了其他用户,请将其替换为相应的用户名: -
你可以通过插入查询的 SETTINGS 子句指定异步插入设置:
-
使用 ClickHouse 编程语言客户端时,也可以将异步插入设置指定为连接参数。
例如,使用 ClickHouse Java JDBC 驱动连接到 ClickHouse Cloud 时,可以在 JDBC 连接字符串中这样设置:
异步插入不适用于
INSERT INTO ... SELECT 查询。当插入包含 SELECT 子句时,无论 async_insert 设置如何,查询始终都会同步执行。关闭时刷新缓冲区
与缓冲表的比较
- 无需修改 DDL。 异步插入对用户是透明的——你只需启用一个设置,无需创建额外的表。
- 按形态缓冲。 异步插入会针对每种唯一的查询形态和设置组合维护单独的缓冲区,从而实现更细粒度的刷写策略。缓冲表则是每个目标表只有一个缓冲区。
- 持久性。 在默认模式 (
wait_for_async_insert=1) 下,客户端收到确认之前,数据就已写入磁盘。缓冲表的行为类似“发出即忘”——如果发生崩溃,缓冲中的数据会丢失。 - 集群行为。 在集群中,异步插入缓冲区按节点分别维护。缓冲表则需要在每个节点上显式创建。