异步插入 (async_insert)
ClickHouse 中的异步插入为客户端批量处理不可行时提供了一种强大的替代方案。这在可观察性工作负载中尤其有价值,其中数百或数千个代理持续发送数据——日志、指标、追踪——通常以小型的实时有效负载形式发送。在这些环境中,客户端缓冲数据会增加复杂性,需要一个集中队列来确保可以发送足够大的批次。
不建议以同步模式发送许多小批次,这会导致创建许多部件。这将导致查询性能下降和 “部件过多” 错误。
异步插入将批量处理的责任从客户端转移到服务器,通过将传入数据写入内存缓冲区,然后根据可配置的阈值将其刷新到存储。这种方法显著减少了部件创建开销,降低了 CPU 使用率,并确保了即使在高并发情况下也能保持高效的摄入。
核心行为通过 async_insert 设置控制。
启用后 (1),插入会被缓冲,并且仅当满足以下刷新条件之一时才写入磁盘
(1) 缓冲区达到指定大小 (async_insert_max_data_size) (2) 经过一段时间阈值 (async_insert_busy_timeout_ms) 或 (3) 累积了最大数量的插入查询 (async_insert_max_query_number)。
此批量处理过程对客户端不可见,并有助于 ClickHouse 有效地合并来自多个来源的插入流量。但是,直到发生刷新,数据才能被查询。重要的是,对于插入形状和设置的组合,存在多个缓冲区,并且在集群中,缓冲区是每个节点维护的——从而可以在多租户环境中实现细粒度控制。否则,插入机制与为 同步插入 描述的机制相同。
选择返回模式
异步插入的行为通过 wait_for_async_insert 设置进一步完善。
设置为 1 (默认值) 时,ClickHouse 仅在数据成功刷新到磁盘后才确认插入。这确保了强大的持久性保证,并使错误处理变得简单:如果刷新过程中出现问题,则错误会返回给客户端。对于大多数生产场景,建议使用此模式,尤其是在必须可靠地跟踪插入失败时。
基准测试 表明它在并发性方面表现良好——无论您运行 200 或 500 个客户端——这归功于自适应插入和稳定的部件创建行为。
设置 wait_for_async_insert = 0 启用“发射即忘”模式。在这里,服务器在数据被缓冲后立即确认插入,而无需等待它到达存储。
这提供了超低延迟的插入和最大的吞吐量,非常适合高速度、低关键性数据。但是,这需要权衡:无法保证数据将被持久化,错误可能仅在刷新期间出现,并且很难跟踪失败的插入。仅当您的工作负载可以容忍数据丢失时才使用此模式。
基准测试还表明 当缓冲区刷新不频繁时(例如,每 30 秒一次),部件显著减少且 CPU 使用率降低,但仍然存在静默失败的风险。
我们强烈建议使用 async_insert=1,wait_for_async_insert=1 如果使用异步插入。使用 wait_for_async_insert=0 非常危险,因为您的 INSERT 客户端可能不知道是否存在错误,并且还可能导致潜在的过载,如果您的客户端继续快速写入,而在 ClickHouse 服务器需要减慢写入速度并创建一些反压以确保服务可靠性的情况下。
去重和可靠性
默认情况下,ClickHouse 对同步插入执行自动去重,这使得在失败场景中安全地重试。但是,除非显式启用,否则这对于异步插入被禁用(如果您有依赖的物化视图,则不应启用此功能——请参阅 issue)。
实际上,如果启用去重并且相同的插入被重试——例如,由于超时或网络中断——ClickHouse 可以安全地忽略重复项。这有助于维护幂等性并避免重复写入数据。但是,值得注意的是,插入验证和模式解析仅在缓冲区刷新期间发生——因此错误(例如类型不匹配)仅在该时点才会出现。
启用异步插入
异步插入可以为特定用户或特定查询启用
-
在用户级别启用异步插入。此示例使用用户
default,如果您创建了不同的用户,请替换该用户名 -
您可以使用插入查询的 SETTINGS 子句指定异步插入设置
-
您还可以将异步插入设置指定为使用 ClickHouse 编程语言客户端连接时连接参数。
例如,这是在使用 ClickHouse Java JDBC 驱动程序连接到 ClickHouse Cloud 时,您可以在 JDBC 连接字符串中执行此操作的方法