ClickHouse — 열 지향 분석 DB 를 속까지 · 파트와 병합 · 实验
파트를 쌓고, 합치고, 막히게 한다
목표
INSERT 가 파트를 몇 개 만드는지, 병합이 그것을 어떻게 줄이는지, 파트가 너무 많으면 무엇이 막히는지를 system.parts·system.part_log·system.query_log 로 확인한다. 비동기 INSERT 로 여러 INSERT 를 파트 하나로 모은다.
왜 중요한가
ClickHouse 운영 장애의 단골은 "Too many parts" 이고, 원인은 넣는 방식이다. 넣는 쪽 코드를 고치려면 "이 INSERT 가 파트를 몇 개 만들었나" 를 셀 줄 알아야 한다. 병합은 백그라운드에서 제멋대로 일어나므로 이 실습은 병합을 멈추고 시작한다. 채점기는 여러분이 적은 숫자를 믿지 않는다 — part_log 의 사건을 지금 있는 표의 uuid 로 걸러 세고, TOO_MANY_PARTS 는 query_log 의 오류 코드로 확인한다.
단계
1. 데이터베이스 parts 와 표 parts.events 를 만드세요 — 열 id UInt64, grp UInt8, v UInt32, 엔진 MergeTree, ORDER BY id. 그리고 SYSTEM STOP MERGES parts.events 로 이 표의 병합을 멈추세요.
2. /opt/lab/fixtures/parts/batches.sql(INSERT 문 10개)을 한 번 실행한 뒤, 활성 파트 수와 이름을 /root/ch/parts/parts.json 에 active_parts·names 로 적으세요.
3. 같은 열의 표 parts.big 을 새로 만들어 numbers(1000000) 에서 100만 행을 INSERT 한 번으로 넣되 SETTINGS min_insert_block_size_rows = 250000 을 붙이세요. part_log 에서 그 INSERT 가 만든 새 파트들의 query_id·개수·행 수 목록을 /root/ch/parts/blocks.json 에 query_id·parts·rows 로 적으세요.
4. SYSTEM START MERGES parts.events 뒤 OPTIMIZE TABLE parts.events FINAL 로 파트를 하나로 합치고, 그 파트의 이름·수준과 part_log 의 이 표 MergeParts 사건 수를 /root/ch/parts/merge.json 에 part·level·merge_events 로 적으세요.
5. 같은 열에 SETTINGS parts_to_throw_insert = 5 인 표 parts.guarded 를 만들고 병합을 멈춘 뒤, id 1–6 을 한 행씩 INSERT 여섯 번으로 넣으세요. 나온 오류(stderr)를 /root/ch/parts/toomany.txt 에 모으세요.
6. parts.guarded 의 병합을 다시 켜고 OPTIMIZE ... FINAL 로 합친 뒤, 거절됐던 id 6 을 다시 넣어 표가 id 1–6 여섯 행이 되게 하세요.
7. 같은 열의 표 parts.async_ev 를 새로 만들고, 두 행짜리 INSERT ... VALUES 를 5번 따로 보내되 SETTINGS async_insert = 1, wait_for_async_insert = 0, async_insert_use_adaptive_busy_timeout = 0, async_insert_busy_timeout_max_ms = 600000 을 붙이세요. SYSTEM FLUSH ASYNC INSERT QUEUE 로 버퍼를 비운 뒤, query_log 에서 표를 만든 뒤의 INSERT 수·part_log 의 새 파트 수·그 파트를 만든 query_id 를 /root/ch/parts/async.json 에 insert_queries·new_parts·flush_query_id 로 적으세요.
8. parts 데이터베이스의 지금 있는 표마다 part_log 의 NewPart 사건 수를 세어 /root/ch/parts/summary.json 에 {"표이름": 수, ...} 로 적으세요(events·big·guarded·async_ev 포함).
참고
- 파트 보기:
SELECT name, rows, level FROM system.parts WHERE database = 'parts' AND table = '...' AND active. - part_log 는 1초마다 비워집니다. 방금 일이 안 보이면
SYSTEM FLUSH LOGS. 지금 표의 기록만 보려면table_uuid = (SELECT uuid FROM system.tables WHERE database = 'parts' AND name = '...'). SYSTEM STOP MERGES는 서버를 다시 켜면 풀립니다. 병합이 멈춘 표에 OPTIMIZE 를 치면Cancelled merging parts로 거절됩니다 — 먼저SYSTEM START MERGES.- 흔한 실수: 2단계를 두 번 돌리는 것. TRUNCATE 해도 part_log 기록은 남으므로, 다시 하려면
DROP TABLE parts.events뒤 1단계부터. 7단계에서 한 문장에 10행을 넣거나, 기다리는 모드(기본)로 하나씩 보내면 파트가 하나로 모이지 않습니다. - 7단계의 기다리지 않는 모드는 오류가 클라이언트에 돌아오지 않아 운영에서는 권하지 않습니다(문서 권장:
wait_for_async_insert = 1). 여기서는 시간에 기대지 않고 모으려고 씁니다. - 공식 문서: [Table parts](https://clickhouse.com/docs/concepts/core-concepts/parts) · [Part merges](https://clickhouse.com/docs/concepts/core-concepts/merges) · [system.part_log](https://clickhouse.com/docs/reference/system-tables/part_log) · [parts_to_* settings](https://clickhouse.com/docs/reference/settings/merge-tree-settings/parts-to) · [Asynchronous inserts](https://clickhouse.com/docs/concepts/features/operations/insert/asyncinserts) · [Selecting an insert strategy](https://clickhouse.com/docs/concepts/best-practices/selecting-an-insert-strategy) · [OPTIMIZE](https://clickhouse.com/docs/reference/statements/optimize)
8个步骤
- 표를 만들고 병합을 멈춘다
- INSERT 10번 → 파트 10개
- INSERT 한 번이 파트 여러 개가 될 때
- 병합을 켜고 하나로 합친다
- 문턱을 낮춰 TOO_MANY_PARTS 를 부른다
- 파트를 줄여 풀어 준다
- 비동기 INSERT 5번 → 파트 하나
- 넣는 방식별 파트 수를 한 표로