ClickHouse 8 — Use case ngân hàng & chọn công cụ
ClickHouse 8 — Use case ngân hàng & chọn công cụ
Bảy bài trước đi từ tổng quan, kiến trúc lưu trữ cột, họ MergeTree, nạp dữ liệu & schema, truy vấn & Materialized View, tới triển khai phân tán và hiệu năng & vận hành. Bài này là bài tổng kết ứng dụng: gom mọi thứ lại để trả lời hai câu hỏi mà một team dữ liệu ngân hàng luôn phải đối mặt trước khi ký duyệt một hệ thống mới — ClickHouse hợp với bài toán nào? và khi nào KHÔNG nên dùng nó?
ClickHouse không phải là "cơ sở dữ liệu vạn năng". Nó là một OLAP column-store tối ưu cho một dạng tải rất cụ thể: quét khối lượng lớn, tổng hợp (GROUP BY, count, sum, quantile, uniq) trên bảng append-only, trả kết quả trong mili-giây tới vài giây. Đặt đúng chỗ, nó thay được cụm Elasticsearch nặng nề hay giảm hoá đơn data warehouse xuống nhiều lần. Đặt sai chỗ — làm OLTP, làm store cập nhật từng dòng — nó sẽ khiến bạn khổ sở. Bài này vẽ ra đúng "chỗ" đó qua bốn use case ngân hàng và một bảng quyết định.
Bốn use case ngân hàng điển hình
1. Dashboard giám sát giao dịch & gian lận (fraud) độ trễ giây
Đây là use case "chân ái" của ClickHouse trong ngân hàng. Bộ phận rủi ro giao dịch cần một màn hình cập nhật gần thời gian thực (near-real-time): tổng số giao dịch/phút theo kênh, tỷ lệ giao dịch bị từ chối, số thẻ/tài khoản phân biệt (distinct) đang hoạt động, phân vị độ trễ xử lý (p95, p99), và các luật cảnh báo dạng "số giao dịch của một tài khoản vượt ngưỡng trong 5 phút".
Vì sao ClickHouse hợp:
- Đếm distinct trên khối lượng lớn:
uniq()(HyperLogLog) đếm số tài khoản/thẻ phân biệt trong cửa sổ trượt gần như miễn phí về RAM — thao tác cực đắt trên CSDL dòng. - Phân vị (quantile) xấp xỉ:
quantile(0.99)(latency_ms)cho p99 độ trễ authorization trong mili-giây, thứ mà một aggregate trên Postgres phải sort toàn bộ. - Materialized View đẩy rollup lúc INSERT: dashboard đọc bảng rollup theo phút đã tính sẵn (xem bài 5), không quét lại dữ liệu thô.
Lưu ý ranh giới nghiệp vụ: ClickHouse ở đây làm analytics/monitoring (phát hiện xu hướng, cảnh báo tổng hợp), KHÔNG phải hệ thống chấm điểm gian lận real-time trong luồng authorization — luồng đó cần độ trễ mili-giây theo từng giao dịch và thường nằm ở tầng stream processing riêng. Việc lập báo cáo giao dịch đáng ngờ tuân thủ pháp lý là quy trình khác, xem STR reporting.
2. Observability: log, metrics & audit log
ClickHouse ngày càng được dùng thay Elasticsearch cho một phần tải quan sát hệ thống (observability): log ứng dụng, dữ liệu APM (application performance monitoring), và audit log (nhật ký truy cập hệ thống lõi, ai xem hồ sơ khách hàng nào lúc nào — yêu cầu bắt buộc trong ngân hàng).
Lý do:
- Log là dữ liệu append-only, không cập nhật — đúng mô hình MergeTree.
- Nén cột rất cao (log lặp lại nhiều), tiết kiệm lưu trữ đáng kể so với Elasticsearch vốn phải giữ inverted index đầy đủ.
- Truy vấn phân tích trên log (đếm lỗi theo service theo phút, p99 latency) nhanh và rẻ hơn.
Nhưng cần thẳng thắn: ClickHouse không thay hoàn toàn Elasticsearch. Nếu nhu cầu chính là full-text search (tìm chuỗi tự do trong log, fuzzy, relevance ranking, highlight), Elasticsearch vẫn vượt trội. ClickHouse có hasToken, ngrambf_v1/tokenbf_v1 (bloom filter index cho token) nhưng đó là tìm kiếm token thô, không phải công cụ search đầy đủ. Quy tắc thực tế: log để phân tích/tổng hợp → ClickHouse; log để tra cứu full-text ad-hoc → Elasticsearch.
3. Clickstream & phân tích hành vi khách hàng
Ứng dụng mobile banking và web banking sinh ra dòng sự kiện khổng lồ: mở màn hình, chạm nút, xem sản phẩm, bắt đầu/bỏ dở luồng đăng ký khoản vay. Đây là clickstream — mỗi sự kiện một dòng, chỉ ghi thêm.
ClickHouse xử lý tốt vì:
- Phân tích funnel (phễu chuyển đổi): dùng
windowFunnel()để đo tỷ lệ khách đi hết luồng "xem sản phẩm vay → điền form → nộp hồ sơ". - Retention/cohort: khách quay lại app sau N ngày, gom theo tuần đăng ký.
- Đếm distinct người dùng hoạt động (DAU/MAU) bằng
uniq()cực rẻ.
Kết quả nuôi cả dashboard sản phẩm lẫn feature cho mô hình đề xuất sản phẩm.
4. Phân tích near-real-time cho vận hành
Nhóm vận hành cần trả lời câu hỏi "đang xảy ra gì lúc này": số dư ròng theo chi nhánh trong ngày, tồn ATM, hàng đợi xử lý hồ sơ, tải hệ thống theo múi giờ. Dữ liệu đổ về liên tục và câu hỏi thường là tổng hợp theo khung giờ/kênh/chi nhánh. ClickHouse cho phép dựng các bảng operational metrics cập nhật theo phút mà không cần chạy batch nặng ban đêm.
Minh hoạ kiểu truy vấn phân tích (chạy trên sandbox Postgres)
Các use case trên xoay quanh cùng một dạng truy vấn: tổng hợp theo khung thời gian và theo chiều phân loại. Sandbox của app là PostgreSQL read-only, nên dưới đây là hai ví dụ chạy được để bạn hình dung hình dạng truy vấn — trên ClickHouse cú pháp gần như tương tự nhưng nhanh hơn nhiều bậc ở quy mô hàng tỷ dòng.
Ví dụ 1 — số giao dịch và tổng amount theo loại giao dịch (kind) và khung giờ trong ngày (đúng dạng "phân bố tải theo giờ" mà dashboard vận hành cần):
-- ▶ Chạy được
SELECT
kind,
EXTRACT(HOUR FROM created_at) AS gio,
COUNT(*) AS so_giao_dich,
SUM(amount) AS tong_amount
FROM transactions
GROUP BY kind, EXTRACT(HOUR FROM created_at)
ORDER BY gio, kind;
Ví dụ 2 — top tài khoản theo số giao dịch (dạng "phát hiện tài khoản bất thường có tần suất cao"):
-- ▶ Chạy được
SELECT account_id, COUNT(*) AS so_giao_dich, SUM(amount) AS tong_amount
FROM transactions
GROUP BY account_id
ORDER BY so_giao_dich DESC
LIMIT 10;
Trên ClickHouse, ví dụ 1 sẽ viết toHour(created_at) (hoặc toStartOfHour nếu gom theo mốc thời gian tuyệt đối) thay cho EXTRACT(HOUR ...), và count() không đối số; phần còn lại giống hệt. Điểm khác nằm ở hiệu năng: cùng câu này trên 2 tỷ dòng, ClickHouse quét cột theo lô vector hoá và trả trong vài trăm mili-giây, còn một CSDL dòng phải đọc toàn bộ hàng.
Kiến trúc tham chiếu: nguồn → Kafka → ClickHouse → dashboard
Mẫu triển khai phổ biến nhất cho các use case trên là đường ống streaming: các hệ thống nguồn phát sự kiện vào Kafka, ClickHouse tiêu thụ trực tiếp bằng Kafka table engine kết hợp Materialized View để đẩy dữ liệu vào bảng MergeTree đích, và các công cụ BI (Grafana, Metabase) đọc từ đó.
Vài điểm cần nhớ về mẫu này:
- Kafka engine trong ClickHouse là "consumer": bảng Kafka engine không lưu dữ liệu, nó đọc message; Materialized View gắn trên nó mới là phần biến đổi và ghi xuống MergeTree (xem chi tiết cơ chế MV ở bài 5).
- Lambda vs Kappa (bản nhẹ): kiến trúc lambda cổ điển chạy song song một nhánh batch (tính lại chính xác) và một nhánh speed (near-real-time), rồi hợp nhất — phức tạp vì phải bảo trì hai codebase logic. Kiến trúc kappa đơn giản hoá: chỉ một luồng stream, khi cần tính lại thì replay dữ liệu từ Kafka retention qua lại ClickHouse. Với ClickHouse + Kafka, kappa thường đủ và gọn hơn: sai lệch nhỏ thì chấp nhận, cần tính lại thì replay topic.
- Idempotency & đúng-một-lần: Kafka engine của ClickHouse mặc định là at-least-once — có thể trùng message khi rebalance. Muốn chống trùng, dùng
ReplacingMergeTreetheo khoá sự kiện, hoặc chốt deduplication ở tầng rollup. Đừng giả định exactly-once mặc định. - Nếu không dùng Kafka engine trực tiếp, một lựa chọn phổ biến khác là ingest bằng batch insert qua HTTP/native protocol từ một consumer riêng — dễ kiểm soát backpressure và retry hơn.
Chọn công cụ: ClickHouse vs Snowflake/BigQuery vs PostgreSQL vs Elasticsearch
Câu hỏi đúng không phải "công cụ nào tốt nhất" mà "bài toán này thuộc loại nào". Bốn công cụ dưới đây phục vụ bốn loại tải khác nhau, và trong một ngân hàng thực tế thường cùng tồn tại, mỗi cái một vai.
| Tiêu chí | ClickHouse | Snowflake / BigQuery | PostgreSQL | Elasticsearch |
|---|---|---|---|---|
| Loại tải | OLAP real-time, dashboard độ trễ giây | Batch DW, ad-hoc analytics, báo cáo | OLTP, giao dịch dòng | Full-text search, log tra cứu |
| Mô hình dữ liệu | Column-store, append-only | Column-store, managed | Row-store | Inverted index (document) |
| Độ trễ truy vấn tổng hợp | ms → vài giây | vài giây → phút | chậm nếu quét lớn | nhanh cho search, kém cho aggregate lớn |
| Cập nhật/xoá từng dòng | Yếu (async, ReplacingMergeTree) | Có nhưng không phải sở trường | Rất tốt (ACID) | Được nhưng tốn |
| Ràng buộc/giao dịch ACID | Không | Hạn chế | Đầy đủ | Không |
| Vận hành | Tự quản (hoặc ClickHouse Cloud) | Fully managed, serverless | Đơn giản, phổ biến | Cụm nặng, tốn RAM |
| Mô hình chi phí | Rẻ theo hạ tầng (nếu tự quản) | Trả theo compute/lưu trữ — dễ đắt nếu quét nhiều | Rẻ, license mở | Tốn hạ tầng (RAM/đĩa cho index) |
| Điểm mạnh nhất | Tổng hợp nhanh trên stream lớn | Tách compute/storage, đàn hồi, chia sẻ dữ liệu | Nhất quán, đa năng, hệ sinh thái | Tìm kiếm văn bản, relevance |
Vài nguyên tắc chọn nhanh cho môi trường ngân hàng:
- Cần độ trễ giây, tổng hợp/đếm distinct/quantile trên stream lớn, đọc nhiều hơn ghi-đơn-lẻ → ClickHouse. Dashboard giám sát, observability, clickstream.
- Cần kho dữ liệu tập trung cho báo cáo định kỳ, ad-hoc SQL đa dạng, dữ liệu về theo lô hằng ngày, ưu tiên fully-managed → Snowflake/BigQuery. Ví dụ data warehouse rủi ro tín dụng, báo cáo quản trị. Cảnh báo chi phí: mô hình trả theo lượng quét dễ tăng phi mã nếu người dùng chạy
SELECT *vô tội vạ. - Cần giao dịch ACID, cập nhật/xoá chính xác từng bản ghi, ràng buộc khoá ngoại → PostgreSQL (hoặc CSDL OLTP tương đương). ClickHouse KHÔNG thay thế được đây; xem nền tảng ở kiến trúc Postgres.
- Cần tìm kiếm toàn văn, fuzzy, relevance, highlight → Elasticsearch. Tra cứu log tự do, tìm kiếm hồ sơ theo văn bản.
Thực tế thường là kết hợp: Postgres/core banking là hệ nguồn (system of record), dữ liệu chảy qua Kafka vào ClickHouse cho real-time và vào Snowflake/BigQuery cho DW; Elasticsearch phục vụ riêng nhu cầu search.
Cạm bẫy khi áp dụng ClickHouse
- Dùng làm OLTP: cập nhật/xoá từng dòng trong ClickHouse là thao tác nặng (mutation viết lại phần lớn part) và không đồng bộ. Nếu nghiệp vụ cần sửa bản ghi thường xuyên, ClickHouse là sai công cụ.
- JOIN bảng lớn với bảng lớn: ClickHouse mạnh khi bảng phải "phát tán" trong JOIN đủ nhỏ để nằm gọn trong RAM (thường là dimension nhỏ). JOIN hai bảng fact khổng lồ dễ tràn bộ nhớ — cân nhắc denormalize (nhồi sẵn cột) hoặc dictionary.
- Kỳ vọng nhất quán mạnh & giao dịch: không có ACID, không khoá ngoại, ràng buộc do ứng dụng đảm bảo. Đừng đặt tiền/sổ cái ở đây làm nguồn sự thật.
- Quá nhiều part nhỏ (too many parts): insert từng dòng hoặc lô quá nhỏ tạo hàng loạt part, làm merge quá tải và truy vấn chậm. Luôn insert theo lô lớn (hàng nghìn tới hàng chục nghìn dòng) hoặc dùng buffer.
- Cardinality cột sắp xếp (ORDER BY) sai: chọn khoá sắp xếp không khớp với mẫu truy vấn khiến ClickHouse phải quét thừa nhiều granule. Thiết kế
ORDER BYtheo cột lọc/nhóm phổ biến nhất (nhắc lại từ bài 3). - Coi Kafka engine là exactly-once: như đã nói, mặc định at-least-once — phải chủ động chống trùng.
- Dồn full-text search vào ClickHouse: bloom filter token không thay được inverted index. Đúng việc của Elasticsearch thì để Elasticsearch làm.
Use case thực tế
Bối cảnh. Trung tâm giám sát giao dịch của NCB cần một màn hình near-real-time cho ~2.500 giao dịch/giây giờ cao điểm (khoảng 180 triệu giao dịch/ngày), tổng hợp trên dữ liệu 90 ngày. Trước đây họ chạy truy vấn tổng hợp trực tiếp trên replica Postgres của core banking, mỗi lần refresh dashboard mất 20–40 giây và làm nặng replica.
Giải pháp triển khai.
- Core banking switch phát sự kiện giao dịch (đã ẩn danh trường nhạy cảm) vào một Kafka topic, retention 7 ngày để có khả năng replay.
- ClickHouse dùng Kafka engine tiêu thụ topic; một Materialized View parse message và ghi vào bảng
transactions_raw(MergeTree),ORDER BY (toDate(created_at), kind, account_id). - MV thứ hai đẩy rollup theo phút vào
txn_rollup_1m(AggregatingMergeTree) với các trạng tháicount,sum(amount),uniqState(account_id),quantileState(0.99)(latency_ms). - Grafana đọc từ
txn_rollup_1m, merge state khi truy vấn.
Kết quả (minh hoạ theo cấu hình tham chiếu). Dashboard refresh mỗi 5 giây, độ trễ truy vấn tụt từ 20–40 giây xuống dưới 1 giây; replica Postgres hết bị treo vì tải phân tích được tách hẳn sang ClickHouse; nhờ nén cột, 90 ngày dữ liệu thô chiếm ít đĩa hơn nhiều lần so với lưu ở dạng dòng. Khi phát hiện lỗi parse ở tuần trước, team chỉ cần replay lại topic từ Kafka (kiến trúc kappa) thay vì khôi phục backup. Cảnh báo tần suất bất thường theo tài khoản (đúng dạng "top account" ở ví dụ SQL trên) chạy trực tiếp trên rollup.
Ghi nhớ
- ClickHouse là OLAP real-time cho tải append-only, tổng hợp lớn, độ trễ giây — KHÔNG phải OLTP, KHÔNG phải store cập nhật từng dòng.
- Bốn use case ngân hàng mạnh: giám sát giao dịch/gian lận, observability (log/metrics/audit), clickstream hành vi khách, phân tích vận hành near-real-time.
- Kiến trúc tham chiếu: nguồn → Kafka → ClickHouse (Kafka engine + Materialized View) → MergeTree/AggregatingMergeTree → dashboard. Kappa (replay từ Kafka) thường gọn hơn lambda.
- Kafka engine mặc định at-least-once — chủ động chống trùng bằng ReplacingMergeTree hoặc dedup ở rollup.
- Chọn công cụ theo loại tải: ClickHouse (real-time OLAP) · Snowflake/BigQuery (batch DW, ad-hoc — coi chừng chi phí quét) · PostgreSQL (OLTP, ACID) · Elasticsearch (full-text search).
- Trong ngân hàng, bốn công cụ thường cùng tồn tại, mỗi cái một vai; đừng ép một công cụ làm hết.
- Cạm bẫy hàng đầu: dùng làm OLTP, JOIN fact-fact tràn RAM, quá nhiều part nhỏ, chọn
ORDER BYsai, và nhồi full-text search vào ClickHouse.
Bài viết liên quan
Cách index hoạt động (B-Tree), đọc EXPLAIN, seq scan vs index scan và mẫu tối ưu truy vấn.
Khoá, ràng buộc, quan hệ và chuẩn hoá 1NF/2NF/3NF — thiết kế lược đồ đúng từ đầu.
Kết nhiều bảng đúng cách: các loại JOIN, bẫy thường gặp và phép hợp tập.
Truy vấn lồng, CTE (WITH), CTE đệ quy và hàm cửa sổ — vũ khí cho phân tích nâng cao.