Khi MySQL hay PostgreSQL “gục ngã” trước hàng tỷ bản ghi
Hai năm trước, mình từng “ăn hành” với một dự án Tracking cho sàn TMĐT lớn. Đề bài rất gắt: Hệ thống phải xử lý 500 triệu event mỗi ngày. Bộ phận Business yêu cầu xem báo cáo trên Dashboard gần như tức thì với độ trễ dưới 1 giây.
Lúc đầu, team vẫn tin dùng PostgreSQL. Khi dữ liệu dưới 100 triệu dòng, mọi thứ vẫn ổn. Nhưng khi bảng log chạm mốc 1 tỷ bản ghi, các câu lệnh COUNT(DISTINCT user_id) bắt đầu trở thành ác mộng. Dù đã đánh index và chia Partition, mỗi lần load Dashboard, anh em vẫn phải đi pha cafe đợi 30-40 giây mới thấy số nhảy. Khách hàng phàn nàn, sếp thì đứng ngồi không yên.
Tại sao các database truyền thống lại chậm?
Sau nhiều đêm thức trắng debug, mình nhận ra các database OLTP (như MySQL, Postgres) gặp ba rào cản lớn khi xử lý Big Data:
- Lưu trữ theo dòng (Row-based): Để tính tổng doanh thu của 1 cột, nó phải đọc toàn bộ các cột khác từ ổ cứng. Việc này gây lãng phí I/O khủng khiếp.
- Index quá tải: Với hàng tỷ dòng, index phình to vượt quá dung lượng RAM. Tốc độ ghi (ingestion) bị kéo tụt do phải cập nhật index liên tục.
- Xử lý đơn luồng: Các query phức tạp thường không tận dụng được sức mạnh của toàn bộ nhân CPU trong cụm server.
Những phương án team mình từng cân nhắc
Trước khi “chốt” Druid, team mình đã thử qua vài hướng nhưng đều có kẽ hở:
- Pre-aggregation: Dùng Cronjob tổng hợp dữ liệu mỗi giờ. Cách này nhanh nhưng mất tính real-time. Sếp muốn xem số liệu của 5 phút trước thì chịu chết.
- Elasticsearch: Tìm kiếm text rất nhanh. Tuy nhiên, khi tính toán (aggregation) trên tập dữ liệu lớn, nó ngốn RAM kinh hoàng và đôi khi trả về kết quả không chính xác 100%.
- ClickHouse: Hiệu năng cực tốt. Nhưng tại thời điểm đó, khả năng tích hợp trực tiếp với Kafka của ClickHouse chưa mượt và ổn định bằng Druid.
Apache Druid – “Vũ khí” cho Real-time Analytics
Apache Druid không chỉ là database. Nó là sự kết hợp giữa Data Warehouse, Time-series database và Search Index. Druid lưu trữ dạng cột (Columnar) và tự động đánh index ngay khi nạp dữ liệu. Khả năng “nuốt” hàng triệu event mỗi giây từ Kafka là điểm ăn tiền nhất của nó.
Cơ chế thông minh của Druid nằm ở việc chia dữ liệu thành các Segments theo thời gian. Khi bạn query dữ liệu hôm nay, nó chỉ quét đúng các segment liên quan. Nó bỏ qua hoàn toàn dữ liệu cũ, giúp tốc độ đạt mức sub-second dễ dàng.
Hướng dẫn cài đặt nhanh (Micro-Quickstart)
Nếu muốn chạy thử trên máy cá nhân hoặc VPS tầm 4GB RAM, bản Micro-Quickstart là lựa chọn hợp lý nhất.
Bước 1: Chuẩn bị môi trường
Druid chạy tốt nhất trên Java 11. Bạn kiểm tra môi trường bằng lệnh:
java -version
Bước 2: Tải và giải nén
Tải bản phân phối mới nhất (ví dụ bản 28.0.1) từ mirror của Apache:
wget https://dlcdn.apache.org/druid/28.0.1/apache-druid-28.0.1-bin.tar.gz
tar -xzf apache-druid-28.0.1-bin.tar.gz
cd apache-druid-28.0.1
Bước 3: Khởi chạy
Trong thư mục gốc, hãy chạy script có sẵn để kích hoạt các service:
./bin/start-micro-quickstart
Đợi tầm 1 phút để các thành phần như Coordinator và Broker khởi động xong. Sau đó, bạn truy cập UI tại: http://localhost:8888.
Ingest dữ liệu và truy vấn thực tế
Druid không dùng INSERT INTO thông thường mà dùng “Ingestion Spec” bằng JSON. Đừng quá lo lắng, giao diện console sẽ hỗ trợ bạn tận răng.
Nạp dữ liệu mẫu
Giả sử bạn có file events.json với cấu trúc đơn giản:
{"time": "2023-10-27T10:00:00Z", "user_id": "u1", "event_type": "click", "value": 10}
Trên giao diện Druid Console:
- Vào Load data -> Local disk và nhập đường dẫn file.
- Tại bước Parse data, hãy chọn cột
timelàm Primary Timestamp. Đây là cột sống còn để Druid phân mảnh dữ liệu hiệu quả. - Nhấn Submit. Khi Task báo
SUCCESSlà dữ liệu đã sẵn sàng.
Truy vấn bằng SQL
Druid hỗ trợ SQL chuẩn, rất dễ làm quen. Bạn có thể thử ngay câu lệnh này:
SELECT
event_type,
COUNT(*) as total_events
FROM "your_datasource"
WHERE __time >= CURRENT_TIMESTAMP - INTERVAL '1' DAY
GROUP BY 1
Kết quả sẽ trả về trong tích tắc nhờ công nghệ Bitmap index trên từng cột.
Kinh nghiệm “xương máu” khi vận hành
Sau một thời gian vận hành Druid ở môi trường production, mình rút ra 3 lưu ý quan trọng:
- Rollup là cứu cánh: Nếu không cần soi chi tiết từng user, hãy bật Rollup. Nó tự động gộp các dòng trùng timestamp và dimension. Trong dự án của mình, Rollup giúp giảm dung lượng lưu trữ từ 100GB xuống còn 15GB.
- Tránh High Cardinality: Đừng đưa các cột có quá nhiều giá trị duy nhất (như
session_id) vào làm dimension. Nó sẽ làm hỏng khả năng Rollup và khiến query chậm đi đáng kể. - Cấu hình RAM: Druid cực kỳ “vã” RAM cho
Direct Memory. Hãy nhớ set tham số-XX:MaxDirectMemorySizecẩn thận, nếu không hệ thống sẽ crash khi gặp query nặng.
Kết quả cuối cùng? Dashboard của team mình giảm từ 40 giây xuống còn chưa tới 500ms. Sếp hài lòng, anh em DevOps cũng thở phào vì không phải thức đêm tối ưu index nữa. Nếu bạn đang đối mặt với bài toán dữ liệu khổng lồ cần tốc độ real-time, Apache Druid là cái tên rất đáng để đầu tư.

