[DE Blog #14] Thiết Kế Hệ Thống Clickstream Analytics & User Behavior Tracking Ở Quy Mô Petabyte
10 views
![[DE Blog #14] Thiết Kế Hệ Thống Clickstream Analytics & User Behavior Tracking Ở Quy Mô Petabyte](/uploads/ai-images/cover-thiet-ke-clickstream-analytics.png)
1. Bối cảnh thực tế (Context & Problem Statement)
Trong các nền tảng thương mại điện tử (Shopee, Amazon, Tiki), mạng xã hội (TikTok, Meta) hoặc ứng dụng gọi xe (Grab, Uber), dữ liệu hành vi người dùng (Clickstream Logs: Click, View, Search, Add to Cart, Checkout) là nguồn tài nguyên quý giá nhất để tối ưu hóa trải nghiệm, xây dựng hệ thống gợi ý (Recommendation) và phân tích phễu chuyển đổi (Funnel Analysis).
Các thách thức kỹ thuật đỉnh cao:
- Lưu lượng khổng lồ và biến động mạnh (Traffic Spikes): Hệ thống phải hấp thụ hàng trăm nghìn sự kiện mỗi giây () trong các dịp Mega Sale mà không bị mất mát dữ liệu.
- Bài toán Sessionization (Gom phiên): Người dùng thực hiện hàng loạt hành động rải rác. Làm thế nào để gom chúng thành các "Phiên làm việc" (Sessions) với điều kiện: Nếu người dùng không hoạt động quá 30 phút, phiên tiếp theo sẽ được tính là một session mới?
- Đếm người dùng duy nhất (Unique Visitors / DAU): Phép toán
COUNT(DISTINCT user_id)trên hàng chục tỷ dòng dữ liệu gây tràn RAM và sập hệ thống nếu không áp dụng thuật toán tối ưu.
2. Các Khái Niệm & Cơ Chế Cốt Lõi
2.1. Cấu Trúc Bản Ghi Clickstream Chuẩn Hóa
Một sự kiện Clickstream chuẩn (theo mô hình Snowplow/Segment) cần bao gồm:
- Event Metadata:
event_id(UUID),event_name(page_view,click_banner,add_to_cart),event_timestamp. - Identity Context:
anonymous_id(Cookie/Device ID),user_id(Account ID nếu đã đăng nhập),ip_address,user_agent. - Page / Device Context:
page_url,referrer_url,app_version,device_os. - Custom Properties (JSON / Struct):
product_id,category_id,price,cart_value.
2.2. Kỹ Thuật Sessionization (Phân Chia Phiên Người Dùng)
- Khái niệm: Session là chuỗi các tương tác liên tục của một người dùng trong một khoảng thời gian nhất định.
- Quy tắc 30-Minute Inactivity Window:
- Nếu khoảng cách thời gian giữa Event và Event của cùng một user , một
session_idmới sẽ được khởi tạo. - Được triển khai thông qua:
- Batch Mode (Spark / SQL): Sử dụng các hàm
LAG()vàSUM() OVER (...)lũy kế. - Stream Mode (Flink): Sử dụng Processing/Event Time Session Windows với gap .
- Batch Mode (Spark / SQL): Sử dụng các hàm
- Nếu khoảng cách thời gian giữa Event và Event của cùng một user , một
2.3. Thuật Toán Đếm Xấp Xỉ HyperLogLog (HLL)
- Vấn đề của
COUNT(DISTINCT)truyền thống: Để đếm chính xác số lượng phần tử duy nhất (Cardinality), Database phải lưu toàn bộ các giá trị đã thấy vào một bảng băm (Hash Set) trong bộ nhớ. Khi số lượng user lên đến hàng trăm triệu, bộ nhớ RAM yêu cầu có thể lên tới hàng chục Gigabytes. - Giải pháp với HyperLogLog:
- HLL là thuật toán xác suất (Probabilistic Algorithm) ước tính số lượng phần tử duy nhất dựa trên việc quan sát số lượng số 0 liên tiếp ở đầu chuỗi băm nhị phân của từng phần tử.
- Hiệu quả vượt trội: Chỉ tốn khoảng bộ nhớ RAM để đếm hàng tỷ phần tử với sai số chuẩn cực nhỏ ().
- Được tích hợp sẵn dưới dạng hàm:
APPROX_COUNT_DISTINCT()trong Spark/BigQuery, hoặc kiểu dữ liệuAggregateFunction(uniq, UInt64)trong ClickHouse.
2.4. Kỹ Thuật User Identity Stitching (Hợp Nhất Danh Tính)
- Người dùng thường duyệt web ẩn danh (gán
anonymous_id = 'anon_123'), thêm hàng vào giỏ, sau đó 20 phút mới tiến hành Đăng nhập (gánuser_id = 'user_888'). - Identity Graph / Graph Stitching: Data Pipeline chạy một tiến trình nối ngược (Backward Stitching) để gán toàn bộ các sự kiện trước đó của
anon_123vào tài khoảnuser_888, giúp báo cáo hành vi không bị đứt đoạn.
3. Các Bảng Markdown So Sánh Chi Tiết
📊 Bảng 1: So Sánh Các Giải Pháp Thu Thập Clickstream
| Giải pháp | Cơ chế hoạt động | Ưu điểm | Nhược điểm | Chi phí |
|---|---|---|---|---|
| Google Analytics (GA4) | SaaS có sẵn | Dễ cài đặt, UI báo cáo mạnh | Dữ liệu bị lấy mẫu (Sampling), khó truy cập dữ liệu thô cấp thấp | Miễn phí hoặc rất đắt (GA360) |
| Segment / RudderStack | Customer Data Platform (CDP) | Định tuyến linh hoạt sang nhiều công cụ marketing | Phụ thuộc bên thứ ba | Tính tiền theo lượng Monthly Tracked Users (MTU) |
| In-House Ingestion Engine (Client SDK + Kafka + S3) | Tự xây dựng toàn bộ | Toàn quyền kiểm soát 100% dữ liệu thô, bảo mật tối đa, dễ scale | Tốn công sức xây dựng và vận hành hạ tầng | Rẻ nhất ở quy mô lớn (chỉ tốn chi phí hạ tầng Cloud) |
📊 Bảng 2: So Sánh COUNT(DISTINCT) vs. APPROX_COUNT_DISTINCT (HyperLogLog)
| Tiêu chí | COUNT(DISTINCT user_id) | APPROX_COUNT_DISTINCT (HyperLogLog) |
|---|---|---|
| Độ chính xác | Chính xác tuyệt đối (100%) | Xấp xỉ (Sai số điển hình ) |
| Tiêu tốn bộ nhớ (RAM) | (Tăng tuyến tính theo số lượng phần tử độc nhất) | (Cố định khoảng ) |
| Tốc độ xử lý | Chậm, dễ gây OOM và Shuffle cực nặng | Nhanh gấp 10x - 50x, dễ dàng cộng dồn (Mergeable) |
| Trường hợp sử dụng | Báo cáo tài chính, quyết toán thanh toán, kiểm toán | Báo cáo DAU/MAU, Phân tích Clickstream, User Tracking (Chuẩn phỏng vấn) |
📊 Bảng 3: So Sánh 2 Chiến Lược Triển Khai Sessionization
| Tiêu chí | Batch Sessionization (Spark / dbt Daily Job) | Stream Sessionization (Apache Flink Real-time) |
|---|---|---|
| Độ trễ (Latency) | Vài giờ đến 24 giờ (chạy qua đêm) | Gần thời gian thực (vài giây sau khi session đóng) |
| Độ phức tạp | Trung bình (viết câu lệnh SQL Window Function) | Cao (quản lý Flink Session Window State và Late Data) |
| Chi phí tính toán | Thấp hơn (chạy theo lịch định kỳ) | Cao hơn (cụm Flink Workers phải chạy liên tục 24/7) |
| Use-case tối ưu | Báo cáo tổng kết tuần/tháng, Phân tích Funnel dài hạn | Phát hiện hành vi bỏ giỏ hàng (Cart Abandonment) để gửi voucher ngay |
4. Kiến Trúc Thiết Kế Toàn Diện (Full System Design Walkthrough)
[Clients: Web / iOS / Android Apps]
|
v (HTTPS POST /events - Batch of 20 events)
[Cloud Load Balancer (ALB) / CDN Edge]
|
v
[Ingestion Microservices (Go/Rust/Java Netty)]
|
+---> (1) Validation & Bot Filtering (GeoIP, User-Agent)
v
[Apache Kafka: Topic "raw-clickstream" (64 Partitions, Key=anonymous_id)]
|
+-------+------------------------------------------+
| (Stream Path) | (Batch Path)
v v
[Apache Flink Stream Job] [Kafka Connect (S3 Sink)]
- Real-Time Sessionization (30m gap) |
- HyperLogLog DAU Aggregation v
- Trigger Cart Abandonment Alerts [Bronze Raw Layer: Parquet on S3]
| |
v v [Spark Batch Jobs]
[Serving: ClickHouse Cluster] [Silver: Deduplicated & Cleaned]
- Real-Time Metrics & Dashboards |
- Funnel Analytics Queries v
| [Gold: Star Schema Data Marts]
v |
[Product Analytics UI / Superset] v
[Trino / Lakehouse BI Queries]
Các bước xử lý dữ liệu chi tiết:
- Client-side Batching: SDK trên điện thoại gom khoảng 10–20 sự kiện (hoặc gửi sau mỗi 5 giây) để giảm tải kết nối HTTP lên API Gateway.
- Ingestion & Buffer: Ingestion Service kiểm tra schema sơ bộ, gắn thêm metadata IP/Timestamp rồi đẩy vào Kafka với
Key = anonymous_idđể bảo toàn thứ tự click của từng thiết bị. - Xử lý Real-time (Speed Layer): Apache Flink đọc từ Kafka, chạy thuật toán tính toán DAU thời gian thực qua HyperLogLog và nạp vào ClickHouse.
- Lưu trữ & Phân tích chuyên sâu (Batch Layer): Dữ liệu được nạp ra S3 Data Lakehouse (Apache Iceberg). Hàng đêm, Spark Job chạy thuật toán User Identity Stitching và tính toán các chỉ số kinh doanh dài hạn.
5. Góc Ôn Luyện Phỏng Vấn (Interview Corner)
❓ Câu hỏi 1: Giải thích cách giải quyết bài toán Sessionization (gom phiên duyệt web với khoảng ngắt 30 phút) bằng SQL trên Apache Spark hoặc Data Warehouse.
- Lời giải & Giải thích truy vấn 3 bước:
WITH EventWithLag AS ( -- Bước 1: Lấy timestamp của sự kiện liền trước của cùng user: SELECT user_id, event_timestamp, event_name, LAG(event_timestamp) OVER ( PARTITION BY user_id ORDER BY event_timestamp ) AS prev_event_time FROM raw_events ), SessionMarkers AS ( -- Bước 2: Đánh dấu 1 nếu khoảng cách > 30 phút (khởi đầu session mới), ngược lại là 0: SELECT *, CASE WHEN prev_event_time IS NULL THEN 1 WHEN DATEDIFF('minute', prev_event_time, event_timestamp) > 30 THEN 1 ELSE 0 END AS is_new_session FROM EventWithLag ) -- Bước 3: Dùng SUM() lũy kế để sinh Session ID tăng dần cho từng user: SELECT user_id, event_timestamp, event_name, CONCAT(user_id, '_', SUM(is_new_session) OVER ( PARTITION BY user_id ORDER BY event_timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW )) AS session_id FROM SessionMarkers;- Giải thích: Phép
SUM(is_new_session)lũy kế sẽ giữ nguyên giá trị khi gặp số0(vẫn trong cùng 1 session) và tự động tăng thêm1mỗi khi phát hiện một khoảng cách thời gian vượt quá 30 phút.
- Giải thích: Phép
❓ Câu hỏi 2: Thuật toán HyperLogLog (HLL) hoạt động dựa trên nguyên lý xác suất nào? Tại sao nó có thể tính toán xấp xỉ số lượng người dùng duy nhất với bộ nhớ cố định cực nhỏ?
- Gợi ý trả lời:
- Nguyên lý cốt lõi:
- Giả sử ta tung một đồng xu nhiều lần. Xác suất để xuất hiện chuỗi liên tiếp mặt ngửa ở những lần tung đầu tiên là . Nếu ta quan sát thấy chuỗi dài nhất có lần ngửa liên tiếp, ta có thể ước tính đã có khoảng lần tung đồng xu.
- Áp dụng vào Big Data:
- Khi một
user_idđi vào, thuật toán băm (hash) nó thành một chuỗi nhị phân 64-bit đồng đều. - Thuật toán đếm số lượng số 0 liên tiếp ở đầu chuỗi băm (). Giá trị ước tính số lượng user duy nhất xấp xỉ bằng .
- Để giảm sai số ngẫu nhiên, HLL chia chuỗi băm thành hàng nghìn "thùng" nhỏ (Buckets), tính giá trị trong từng thùng và lấy trung bình điều hòa (Harmonic Mean) của tất cả các thùng.
- Khi một
- Khả năng cộng gộp (Mergeability): Hai cấu trúc HLL của ngày 1 và ngày 2 có thể được gộp lại với nhau bằng phép toán
BITWISE ORcực nhanh để tính số lượng user độc nhất của cả tuần mà không cần quét lại dữ liệu thô!
- Nguyên lý cốt lõi:
❓ Câu hỏi 3: Làm thế nào để thiết kế một truy vấn phân tích Phễu chuyển đổi (Funnel Analysis) nhiều bước (ví dụ: View Product Add to Cart Checkout) có tính tuần tự về thời gian trên ClickHouse?
- Gợi ý trả lời:
- ClickHouse cung cấp hàm chuyên dụng cực mạnh
windowFunnel()được tối ưu hóa ở tầng C++:
SELECT level, COUNT(1) AS user_count FROM ( SELECT user_id, windowFunnel(1800)( -- Khung thời gian tối đa 1800s (30 phút) event_timestamp, event_name = 'view_product', event_name = 'add_to_cart', event_name = 'checkout_completed' ) AS level FROM clickstream_events WHERE event_date = '2026-08-20' GROUP BY user_id ) GROUP BY level ORDER BY level;- Cơ chế: Hàm
windowFunnelkiểm tra xem người dùng có hoàn thành tuần tự các bước 1, 2, 3 trong khoảng thời gian quy định (1800 giây) hay không và trả về cấp độ cao nhất mà người dùng đạt được (1, 2 hoặc 3), giúp việc vẽ biểu đồ phễu chuyển đổi trở nên vô cùng nhanh chóng.
- ClickHouse cung cấp hàm chuyên dụng cực mạnh
6. Tóm Tắt Ghi Nhớ Nhanh (Key Takeaways)
- Client-side Batching kết hợp Kafka Partitioning theo Device/Anonymous ID là chìa khóa để xử lý an toàn.
- Sessionization trong SQL được giải quyết thanh lịch bằng tổ hợp
LAG()+CASE WHEN+ CumulativeSUM(). - HyperLogLog (HLL) là tiêu chuẩn vàng để tính toán các chỉ số DAU/MAU và Cardinality quy mô lớn với bộ nhớ cố định .
- Tận dụng ClickHouse với hàm
windowFunnel()để đạt hiệu năng phân tích hành vi người dùng thời gian thực với độ trễ dưới 1 giây.
0Claps