Vấn đề thực tế: ELK Stack đang ngốn ngân sách của team
Năm ngoái, team mình đụng vào một bài toán khó chịu với stack monitoring. Chúng mình đang chạy ELK Stack (Elasticsearch + Logstash + Kibana) để thu thập logs từ khoảng 20 server — và mỗi tháng chi phí lưu trữ cứ tăng mà không có điểm dừng. Elasticsearch lưu data theo kiểu Lucene index, dẫn đến disk usage thường cao gấp 3–5 lần so với raw log thực tế.
Còn RAM thì khỏi nói. Elasticsearch cần tối thiểu 4GB heap để hoạt động ổn ở production. Với cluster 3 node là 12GB RAM chỉ riêng Elasticsearch — chưa tính Logstash và Kibana. VPS tháng nào cũng đội thêm chi phí, trong khi ngân sách team không nhúc nhích.
Tại sao ELK lại đắt cho bài toán observability?
Elasticsearch được thiết kế ban đầu để làm search engine. Đưa vào bài toán observability, nó kéo theo rất nhiều overhead không cần thiết:
- Lucene inverted index tối ưu cho full-text search, nhưng với time-series logs thì đây là gánh nặng thừa
- Schema-on-write nghĩa là phải define mapping trước — dynamic mapping dễ sinh ra field explosion nếu log format không nhất quán
- Replication factor mặc định yêu cầu ít nhất 2 node để có HA, tức là dữ liệu bị nhân đôi trên disk
- JVM overhead — heap phải warm up, GC pause là nỗi ám ảnh mỗi khi query nặng
ELK Stack mạnh, nhưng nó được sinh ra để làm search engine, không phải log aggregator. Dùng nó cho observability giống như thuê xe tải 10 tấn để chở một thùng hàng — nó làm được, nhưng chi phí vận hành không tương xứng chút nào.
Các lựa chọn thay thế đã thử qua
Trước khi chốt phương án, mình đã benchmark một vài giải pháp:
- Grafana Loki: Nhẹ hơn nhiều vì chỉ index metadata thay vì full content. Nhưng LogQL học tốn thời gian, và search performance bắt đầu đuối khi data lên đến vài chục GB mà không có index đầy đủ.
- Graylog: Vẫn dùng Elasticsearch ở backend — chỉ thêm một lớp UI đẹp hơn, bài toán storage chưa giải quyết được gì.
- VictoriaMetrics: Rất tốt cho metrics, nhưng tại thời điểm đó logs native chưa đủ chín để dùng production.
- OpenObserve: Xử lý được cả logs, metrics, traces trong một binary duy nhất — với chi phí lưu trữ thấp hơn ELK đến 140 lần theo benchmark chính thức của họ.
OpenObserve — Giải pháp mình đang dùng thực tế
OpenObserve (trước đây gọi là ZincObserve) được viết bằng Rust và lưu data dưới dạng Parquet format với compression cao. Khác biệt so với ELK ở mấy điểm chính:
- Một binary duy nhất dưới 10MB, không cần JVM, không cần Elasticsearch
- Hỗ trợ S3-compatible storage — lưu logs lên Cloudflare R2 hoặc MinIO rẻ hơn nhiều so với block storage truyền thống
- UI tích hợp sẵn để query logs bằng SQL, metrics bằng PromQL, traces theo chuẩn OpenTelemetry
- RAM footprint thực tế chỉ khoảng 100–150MB khi idle — mình đo trực tiếp trên server production
Cài đặt OpenObserve với Docker
Nhanh nhất để test trên một server mới:
# Tạo thư mục lưu data
mkdir -p /opt/openobserve/data
# Chạy OpenObserve
docker run -d \
--name openobserve \
--restart unless-stopped \
-p 5080:5080 \
-e [email protected] \
-e ZO_ROOT_USER_PASSWORD=StrongPass123! \
-e ZO_DATA_DIR=/data \
-v /opt/openobserve/data:/data \
public.ecr.aws/zinclabs/openobserve:latest
Xong là mở browser tại http://your-server-ip:5080, đăng nhập bằng credentials vừa set là vào được ngay.
Docker Compose cho môi trường production
version: '3.8'
services:
openobserve:
image: public.ecr.aws/zinclabs/openobserve:latest
container_name: openobserve
restart: unless-stopped
ports:
- "5080:5080"
environment:
ZO_ROOT_USER_EMAIL: "[email protected]"
ZO_ROOT_USER_PASSWORD: "ChangeThisToSomethingStrong!"
ZO_DATA_DIR: /data
ZO_TELEMETRY: "false"
volumes:
- openobserve_data:/data
volumes:
openobserve_data:
Chạy bằng lệnh:
docker compose up -d
# Kiểm tra logs khởi động
docker compose logs -f openobserve
Gửi logs từ server lên OpenObserve với Fluent Bit
Fluent Bit là agent thu thập logs nhẹ nhất mình từng dùng — footprint chỉ khoảng 5MB RAM, so với Logstash đòi 500MB trở lên. Cài trên Ubuntu/Debian:
curl https://raw.githubusercontent.com/fluent/fluent-bit/master/install.sh | sh
systemctl enable fluent-bit --now
Tạo file config để đẩy logs lên OpenObserve:
# /etc/fluent-bit/fluent-bit.conf
[SERVICE]
Flush 5
Log_Level info
[INPUT]
Name tail
Path /var/log/syslog
Tag server.syslog
Read_from_Head False
[INPUT]
Name tail
Path /var/log/nginx/access.log
Tag nginx.access
Read_from_Head False
[OUTPUT]
Name http
Match *
Host your-openobserve-server
Port 5080
URI /api/default/server_logs/_json
Format json
Http_User [email protected]
Http_Passwd ChangeThisToSomethingStrong!
compress gzip
tls Off
systemctl restart fluent-bit
# Verify logs đang được gửi đi
journalctl -u fluent-bit -f
Query logs bằng SQL trong UI
Không cần học LogQL hay KQL — OpenObserve dùng SQL syntax, ai đã quen với database quan hệ là làm được ngay. Vào menu Logs, chọn stream và chạy:
-- Tìm tất cả ERROR trong 1 giờ qua
SELECT * FROM "server_logs"
WHERE log LIKE '%ERROR%'
ORDER BY _timestamp DESC
LIMIT 100
-- Đếm số lỗi theo từng giờ để xem trend
SELECT
date_trunc('hour', _timestamp) AS hour,
count(*) AS error_count
FROM "server_logs"
WHERE log LIKE '%ERROR%'
GROUP BY 1
ORDER BY 1 DESC
Cấu hình Alert — tránh bẫy alert fatigue
Phần này mình tốn nhiều thời gian nhất khi mới setup. Hồi đầu set threshold quá thấp — cứ 2–3 phút lại nhận ping, đến mức cả team mute nhóm chat DevOps luôn. Bài học đau: threshold phải dựa trên baseline thực tế từ log lịch sử ít nhất 1–2 tuần, không phải con số cảm tính.
Trong OpenObserve, vào Alerts → Create Alert. Cấu hình mẫu:
{
"name": "High Error Rate",
"stream_name": "server_logs",
"query": "SELECT count(*) as error_count FROM server_logs WHERE log LIKE '%ERROR%'",
"condition": {
"column": "error_count",
"operator": ">",
"value": 50
},
"duration": 5,
"frequency": 1,
"time_between_alerts": 30
}
Hai tham số quan trọng nhất: time_between_alerts set tối thiểu 30 phút để tránh spam. Còn duration: 5 nghĩa là điều kiện phải đúng liên tục trong 5 phút mới trigger — lọc hiệu quả các spike nhất thời gây false positive.
Alert có thể gửi qua Slack, Webhook, hoặc email. Cấu hình destination tại Alerts → Destinations.
Kết quả thực tế sau 3 tháng chuyển sang OpenObserve
Cùng lượng logs từ 20 server, đây là con số mình đo được:
- Disk usage: Từ 180GB/tháng (ELK) xuống còn 13GB/tháng (OpenObserve) — giảm gần 14 lần
- RAM tiêu thụ: Từ 12GB (ELK cluster 3 node) xuống 256MB (OpenObserve single node)
- Chi phí VPS: Từ $80/tháng xuống $12/tháng cho cùng workload
- Thời gian setup: 10 phút với Docker, so với nửa ngày để setup ELK đúng cách
OpenObserve không thay thế Elasticsearch trong mọi bài toán. Nếu cần full-text search phức tạp cho application data, Elasticsearch vẫn là lựa chọn đúng. Nhưng cho observability — thu thập, lưu trữ và phân tích logs, metrics, traces của infrastructure — đây là thứ mình ước biết sớm hơn hai năm.
