async_insert — 배칭 책임을 클라이언트에서 서버로 옮기기
ClickHouse async_insert 공식 문서 종합 (웹 리서치, 2026) — ClickHouse 공식 문서(optimize/asynchronous-inserts) ClickHouse 공식 문서 Asynchronous inserts
이 모듈을 다 읽으면
- async_insert이 클라이언트 대신 서버에서 소량 INSERT를 배칭하는 방식을 설명할 수 있다
- wait_for_async_insert 값에 따른 내구성-지연시간 트레이드오프를 설명할 수 있다
clickhouse-learn-07에서 다룬 'Too Many Parts' 에러(잦고 작은 동기 INSERT가 원인)를 전제로, 클라이언트가 직접 배칭 로직을 구현하지 않고도 서버가 대신 소량 INSERT들을 모아 하나의 파트로 만들어주는 async_insert 기능을 정리한다.
문제 상황 — 배칭을 클라이언트가 직접 해야 했던 부담
수백 개의 에이전트가 실시간으로 소량씩 데이터를 계속 보내는 관측(observability) 워크로드처럼, 각 INSERT가 작고 빈번한 상황에서는 clickhouse-learn-07에서 다룬 것처럼 파트가 과도하게 생겨 'Too Many Parts' 에러나 성능 저하를 유발한다. 전통적인 해법은 클라이언트 쪽에서 데이터를 모아뒀다가 일정량이 차면 한 번에 큰 배치로 INSERT하는 것인데, 이러려면 클라이언트 애플리케이션이 별도의 큐잉 인프라를 직접 구축·운영해야 하는 복잡도가 추가된다.
핵심 포인트
- 수백 개 에이전트가 소량씩 계속 INSERT하는 관측 워크로드는 파트 과다 생성으로 'Too Many Parts'나 성능 저하 유발
- 전통적 해법(클라이언트 배칭)은 클라이언트가 별도 큐잉 인프라를 직접 구축·운영해야 하는 복잡도를 요구
async_insert — 서버가 메모리에서 모아 하나의 배치로 flush
async_insert=1로 설정하면, ClickHouse는 들어오는 INSERT들을 즉시 파트로 만드는 대신 메모리 버퍼에 모아뒀다가 하나의 통합된 배치로 flush한다 — 배칭 책임이 클라이언트에서 서버로 옮겨가는 셈이다. flush는 다음 세 조건 중 먼저 도달하는 것을 기준으로 일어난다 — 데이터 크기가 async_insert_max_data_size(기본 100MiB)에 도달하거나, async_insert_busy_timeout_ms(기본 200ms) 시간이 지나거나, 누적 쿼리 수가 async_insert_max_query_number(기본 450)에 도달하는 경우다.
핵심 포인트
- async_insert=1: INSERT를 즉시 파트화하지 않고 메모리 버퍼에 모아 하나의 배치로 flush — 배칭 책임이 클라이언트에서 서버로 이동
- flush 트리거 3가지(먼저 도달하는 것 적용): 데이터 크기(async_insert_max_data_size 기본 100MiB), 대기시간(async_insert_busy_timeout_ms 기본 200ms), 누적 쿼리 수(async_insert_max_query_number 기본 450)
wait_for_async_insert — 내구성과 지연시간의 트레이드오프
wait_for_async_insert=1(기본값, 권장)로 설정하면 서버는 데이터가 실제로 디스크에 flush되고 나서야 클라이언트에 성공 응답을 돌려준다 — 강한 내구성을 보장하고 에러 처리도 명확해 프로덕션에 권장된다. 반대로 wait_for_async_insert=0(fire-and-forget)은 버퍼에 담기만 하면 즉시 응답을 돌려줘 지연시간은 극도로 낮아지지만, 그 데이터가 실제로 디스크에 영속화될 거라는 보장이 없고 문제가 생겨도 나중에 로그에서나 확인할 수 있다는 신뢰성 손실을 감수해야 한다.
핵심 포인트
- wait_for_async_insert=1(기본, 권장): 디스크 flush 완료 후 응답 — 강한 내구성, 명확한 에러 처리, 프로덕션 권장
- wait_for_async_insert=0(fire-and-forget): 버퍼링 즉시 응답 — 지연시간은 최소화되지만 영속화 보장 없음, 문제는 사후에 로그로만 확인 가능
한계 — flush 전까지는 조회 불가, 고카디널리티 파티션 문제는 그대로
async_insert을 쓰면 클라이언트 쪽 큐잉 복잡도는 사라지지만, 데이터는 실제로 flush되기 전까지는 조회할 수 없다는 점을 감안해야 한다. 또한 이 기능은 '작고 빈번한 INSERT' 문제를 해결하는 것이지, 파티션 키 자체가 고카디널리티라 파티션 수가 과다해지는 문제(clickhouse-learn-07에서 다룬 또 다른 파트 과다 원인)까지 해결해주지는 않는다 — 즉 async_insert은 만능 해법이 아니라 특정 원인(소량 INSERT 빈발)에 대한 대응책이라는 점을 명확히 구분해야 한다.
핵심 포인트
- async_insert 데이터는 실제 flush 전까지는 조회 불가
- 고카디널리티 파티션 키로 인한 파트 과다 문제는 async_insert로 해결 안 됨 — '소량 INSERT 빈발'이라는 특정 원인에만 대응하는 기능