Hướng dẫn cài đặt và cấu hình OpenObserve: Giải pháp Logs, Metrics và Traces thế hệ mới thay thế ELK Stack với chi phí lưu trữ thấp hơn 140 lần

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

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 AlertsCreate 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 AlertsDestinations.

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.

Share: