Vận hành ClickHouse trong Production: Ingestion, Merge và Chi phí ở 2 tỷ dòng
Kinh nghiệm vận hành ClickHouse trong production: thiết kế schema, tối ưu truy vấn và cách chúng tôi đạt phân tích dưới một giây trên 100M+ sự kiện thiết bị.
Khi bắt đầu xây dựng tầng analytics của tracio.ai, chúng tôi cần một cơ sở dữ liệu có thể xử lý khối lượng công việc đặc thù của mình: ingest 50.000 sự kiện nhận diện thiết bị mỗi giây, lưu trữ hơn 2 tỷ dòng, và trả lời các truy vấn phân tích trong dưới một giây. Chúng tôi đã đánh giá PostgreSQL (quá chậm cho aggregation ở quy mô này), Elasticsearch (quá đắt cho time-series analytics) và ClickHouse. ClickHouse thắng một cách thuyết phục.
Vì sao chọn ClickHouse
ClickHouse là một cơ sở dữ liệu OLAP hướng cột được thiết kế cho analytics thời gian thực. Lợi thế chính của nó với khối lượng công việc của chúng tôi là chỉ đọc những cột cần thiết cho mỗi truy vấn. Khi một chuyên viên phân tích gian lận hỏi "cho tôi xem tỷ lệ gian lận theo quốc gia trong 7 ngày qua," ClickHouse chỉ đọc các cột country, timestamp và risk_score — bỏ qua 40+ cột còn lại trong bảng sự kiện. Trên bảng 2 tỷ dòng, điều này giảm I/O tới 95%.
ClickHouse cũng nén dữ liệu cực kỳ tốt. Bảng sự kiện 2 tỷ dòng của chúng tôi chiếm 340 GB trên đĩa — khoảng 170 byte mỗi dòng sau khi nén, so với 1,2 KB mỗi dòng khi chưa nén. Tỷ lệ nén 7:1 nghĩa là nhiều dữ liệu vừa vặn hơn trong bộ nhớ, và điều đó trực tiếp chuyển hóa thành truy vấn nhanh hơn.
Thiết kế Schema
Bảng chính của chúng tôi lưu một dòng cho mỗi sự kiện nhận diện:
Bảng dùng engine MergeTree, sắp xếp theo (workspace_id, toDate(timestamp), visitor_hash). Thứ tự sắp xếp này rất then chốt — nó có nghĩa là các truy vấn lọc theo workspace và khoảng ngày sẽ đọc lượng dữ liệu tối thiểu. Cột visitor_hash cho phép tra cứu nhanh theo visitor ID mà không cần chỉ mục thứ cấp.
Chúng tôi chọn LowCardinality(String) cho country, device_type, browser_family và os_family vì các cột này có ít hơn 10.000 giá trị phân biệt. ClickHouse lưu các cột LowCardinality dưới dạng số nguyên được mã hóa từ điển, giảm 80% dung lượng lưu trữ so với chuỗi thường và tăng tốc các thao tác GROUP BY.
Chiến lược phân mảnh (Sharding)
Chúng tôi phân mảnh bảng sự kiện trên 6 node bằng hash của workspace_id. Điều này đảm bảo tất cả sự kiện của một khách hàng nhất định nằm trên cùng một shard, nghĩa là hầu hết truy vấn (lọc theo workspace_id) chỉ chạm vào một shard duy nhất. Truy vấn liên shard chỉ cần thiết cho analytics nội bộ.
Mỗi shard có 2 replica để đảm bảo tính sẵn sàng cao. Việc sao chép sử dụng engine ReplicatedMergeTree tích hợp sẵn của ClickHouse với sự điều phối của ZooKeeper. Chuyển đổi dự phòng (failover) là tự động — nếu một shard gặp sự cố, truy vấn được định tuyến sang replica mà không cần thay đổi gì phía client.
Đường ống Ingestion
Sự kiện chảy từ topic Kafka của chúng tôi vào ClickHouse thông qua một dịch vụ Go tùy chỉnh làm nhiệm vụ gom insert thành lô. Chúng tôi insert theo lô 10.000 dòng mỗi 500ms — điều này cân bằng giữa độ trễ ingestion (dưới một giây) và hiệu quả insert (ClickHouse hoạt động tốt nhất với các lô lớn).
Dịch vụ ingestion xử lý back-pressure một cách nhẹ nhàng. Nếu ClickHouse chậm chấp nhận insert (trong lúc merge hoặc tải truy vấn nặng), dịch vụ sẽ đệm tới 1 triệu sự kiện trong bộ nhớ và áp dụng back-pressure lên Kafka consumer. Trong 18 tháng chạy production, chúng tôi chưa từng mất một sự kiện nào.
Tối ưu truy vấn
Materialized View
Với các truy vấn dashboard phổ biến, chúng tôi dùng materialized view để tổng hợp trước dữ liệu. Ví dụ, dashboard tỷ lệ gian lận của chúng tôi đọc từ một materialized view tổng hợp số lượng fraud_detected theo workspace, quốc gia và giờ. View này giảm lượng dữ liệu phải quét cho truy vấn từ 2 tỷ dòng xuống còn 5 triệu dòng.
Thứ tự Projection
Projection của ClickHouse cho phép chúng tôi định nghĩa các thứ tự sắp xếp thay thế cho một bảng mà không nhân đôi dữ liệu. Chúng tôi đã thêm một projection sắp xếp theo (workspace_id, visitor_hash, timestamp) cho các truy vấn dòng thời gian của visitor. Không có projection, các truy vấn này quét toàn bộ khoảng ngày. Có nó, chúng chỉ đọc những block chứa visitor mục tiêu.
Các hàm xấp xỉ
Với những truy vấn dashboard mà số đếm chính xác không quan trọng, chúng tôi dùng các hàm xấp xỉ của ClickHouse: uniqCombined cho số đếm phân biệt (biên sai số 2%, nhanh gấp 10 lần uniqExact) và quantileTDigest cho tính toán phân vị. Dashboard phân tích gian lận dùng hoàn toàn các hàm xấp xỉ, nhờ đó giữ mọi truy vấn dashboard dưới 200ms.
Các con số hiệu năng
Dưới đây là các benchmark truy vấn tiêu biểu trên cụm production 2 tỷ dòng của chúng tôi:
Tỷ lệ gian lận theo quốc gia, 7 ngày qua: 120ms. Dòng thời gian visitor (50 sự kiện): 8ms. Số visitor duy nhất mỗi ngày, 30 ngày qua: 340ms. Phân bố risk score, 24 giờ qua: 95ms. Top 100 thiết bị theo số lượng sự kiện, 30 ngày qua: 210ms.
Những con số này bao gồm cả round-trip mạng từ các máy chủ ứng dụng của chúng tôi đến cụm ClickHouse. Thời gian thực thi truy vấn thuần túy thường thấp hơn 30-50%.
Bài học vận hành
Bài học 1: Theo dõi merge lag
Engine MergeTree của ClickHouse liên tục merge các part dữ liệu nhỏ thành các part lớn hơn. Nếu quá trình merge bị tụt lại (do tốc độ insert cao hoặc tranh chấp I/O đĩa), hiệu năng truy vấn suy giảm vì truy vấn phải quét nhiều part hơn. Chúng tôi theo dõi số part trên mỗi partition và cảnh báo khi vượt quá 300.
Bài học 2: Tránh các thao tác ALTER TABLE lớn
Thêm một cột vào bảng 2 tỷ dòng trong ClickHouse diễn ra tức thì (chỉ là thao tác metadata). Nhưng thay đổi kiểu của một cột đòi hỏi viết lại toàn bộ các part dữ liệu — một quá trình mất 6 giờ trên cụm của chúng tôi. Giờ đây chúng tôi coi schema là chỉ-thêm (append-only): cột mới được thêm thoải mái, nhưng thay đổi kiểu phải đi qua một bảng migration.
Bài học 3: Cẩn trọng với TTL
ClickHouse hỗ trợ tự động hết hạn dữ liệu qua TTL. Chúng tôi đặt TTL 90 ngày cho bảng sự kiện. Điểm bẫy: việc xóa theo TTL diễn ra trong lúc merge, nghĩa là dữ liệu đã xóa có thể vẫn tồn tại hàng giờ hoặc hàng ngày sau khi TTL hết hạn. Với việc xóa quan trọng cho tuân thủ (compliance), chúng tôi chạy các truy vấn ALTER TABLE DELETE tường minh theo lịch.
Chi phí
Cụm ClickHouse 6 node của chúng tôi (mỗi node: 32 vCPU, 128 GB RAM, 2 TB NVMe) tốn khoảng 8.400 USD/tháng trên hosting bare metal. Cụm này lưu 2 tỷ dòng với thời gian giữ 90 ngày và xử lý 50K insert/giây cùng 200 truy vấn dashboard đồng thời. Chi phí cho mỗi sự kiện lưu trữ là 0,0000042 USD — rẻ hơn nhiều bậc so với analytics tương đương trên các cơ sở dữ liệu đám mây được quản lý.