Giám sát Elasticsearch và OpenSearch Cluster với Prometheus Exporter và Grafana: Theo dõi Sức Khỏe Index, Query Latency và Tài Nguyên Hệ Thống

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

Sau 6 tháng chạy Elasticsearch cluster trên production với khoảng 50 triệu document, mình học được một điều đắt giá: monitoring CPU và RAM thôi là chưa đủ. Cluster có thể “xanh đèn” trên Grafana nhưng query latency lại tăng âm thầm. Hoặc tệ hơn: JVM heap leo lên 90% mà không ai hay — cho đến khi node bị OOM kill.

Prometheus + Grafana của mình đang track 15 server, và setup này đã catch được nhiều sự cố trước khi user phàn nàn. Nhưng khi thêm Elasticsearch vào stack, mình mất gần 2 tuần mò mẫm. Bài này là thứ mình muốn được đọc ngay từ đầu.

Tại sao Elasticsearch cần được giám sát theo cách riêng

System metrics như CPU, RAM, disk I/O chỉ là tầng ngoài. Cái phức tạp nằm bên trong cluster:

  • Shard allocation: cluster vẫn hoạt động nhưng có unassigned shards — dữ liệu đang ở trạng thái nguy hiểm
  • Query latency: search p99 tăng từ 50ms lên 2s là dấu hiệu index cần được optimize ngay
  • JVM GC pressure: GC pause dài hơn 1 giây làm freeze toàn bộ request trong thời gian đó
  • Bulk queue rejection: khi indexing queue đầy, request bị từ chối mà không có error log rõ ràng
  • Disk watermark: Elasticsearch tự block write khi disk free < 5% — nếu không phát hiện sớm thì mất data

Không có application-level monitoring thì debug sự cố chỉ là mò kim đáy bể.

So sánh 3 cách tiếp cận phổ biến

1. X-Pack Stack Monitoring (native)

Elasticsearch tích hợp sẵn monitoring qua Kibana Stack Monitoring. Metrics được lưu vào chính cluster hoặc một monitoring cluster riêng.

  • Setup đơn giản: bật vài dòng trong elasticsearch.yml là xong
  • Giao diện Kibana đẹp, có cluster health overview sẵn
  • Nhưng: tốn resource của chính cluster để lưu metrics, và với OpenSearch (fork sau khi Elastic đổi license) thì tính năng này không available theo cách tương đương

2. Metricbeat

Agent của Elastic chạy trên từng node, scrape metrics rồi đẩy vào Elasticsearch hoặc Logstash.

  • Nhiều module sẵn, config đơn giản
  • Tight coupling với Elastic stack — không tích hợp được nếu đã dùng Prometheus
  • Phải deploy và maintain agent trên từng node — chi phí vận hành không nhỏ khi cluster có 10+ node

3. Prometheus Exporter (elasticsearch_exporter)

Exporter chạy như một service độc lập, expose metrics theo format Prometheus, Prometheus scrape định kỳ.

  • Tích hợp hoàn toàn với stack Prometheus + Grafana đã có sẵn
  • Một exporter duy nhất monitor được cả cluster — không cần cài per-node
  • Hỗ trợ cả Elasticsearch và OpenSearch
  • Community dashboard sẵn có trên Grafana Labs

Phân tích ưu nhược — và lý do mình chọn Prometheus Exporter

2 tuần test cả 3 phương án trên staging, kết quả khá rõ:

X-Pack Monitoring phù hợp nếu team all-in vào Elastic stack có license. Nhưng codebase mình đang chạy OpenSearch vì license permissive hơn, nên option này bị loại sớm.

Metricbeat hợp lý nếu đã dùng Beats cho log shipping. Nhưng thêm agent deployment pipeline cho mỗi node mới là overhead mà team nhỏ không muốn gánh.

Prometheus Exporter thắng vì lý do đơn giản: Prometheus + Grafana đã chạy sẵn cho 15 server kia, mình chỉ cần thêm một exporter là xong, không đụng gì đến kiến trúc hiện tại. Với OpenSearch thì exporter cũng hoạt động tốt — chỉ thay URI là chạy được.

Triển khai step-by-step

Bước 1: Cài đặt elasticsearch_exporter

Project prometheus-community/elasticsearch_exporter hỗ trợ cả Docker và binary. Cách nhanh nhất:

docker run -d \
  --name elasticsearch-exporter \
  -p 9114:9114 \
  --restart unless-stopped \
  quay.io/prometheuscommunity/elasticsearch-exporter:latest \
  --es.uri=http://elasticsearch:9200 \
  --es.all \
  --es.indices \
  --es.shards

Nếu cluster có authentication (OpenSearch Security plugin hoặc Elasticsearch xACL):

docker run -d \
  --name elasticsearch-exporter \
  -p 9114:9114 \
  --restart unless-stopped \
  -e ES_USERNAME=monitoring_user \
  -e ES_PASSWORD=your_password \
  quay.io/prometheuscommunity/elasticsearch-exporter:latest \
  --es.uri=https://elasticsearch:9200 \
  --es.all \
  --es.indices \
  --es.clusterinfo.interval=5m

Kiểm tra exporter đang chạy và expose metrics:

curl http://localhost:9114/metrics | grep elasticsearch_cluster_health

Nếu thấy output dạng elasticsearch_cluster_health_status{color="green"} 1 là exporter đã kết nối được với cluster.

Bước 2: Cấu hình Prometheus scrape job

Thêm job vào prometheus.yml:

scrape_configs:
  - job_name: 'elasticsearch'
    scrape_interval: 30s
    scrape_timeout: 25s
    static_configs:
      - targets:
          - 'elasticsearch-exporter:9114'
        labels:
          cluster: 'prod-es-cluster'
          env: 'production'

Reload Prometheus không cần restart:

curl -X POST http://localhost:9090/-/reload

Vào Prometheus UI, query elasticsearch_cluster_health_status để xác nhận data đang vào đúng.

Bước 3: Import Grafana Dashboard

Dashboard ID 14191 trên Grafana Labs là bản được cộng đồng dùng nhiều nhất cho elasticsearch_exporter:

  1. Grafana → Dashboards → Import
  2. Nhập ID 14191 → Load
  3. Chọn Prometheus data source → Import

Dashboard có sẵn: cluster health status, node count, JVM heap usage, indexing rate, search rate, GC collection time, disk usage per node.

Bước 4: Thiết lập Alert cho các metrics quan trọng

Đây là bộ alert rules mình dùng trực tiếp trên production, thêm vào Prometheus rules file:

groups:
  - name: elasticsearch_alerts
    rules:
      # Cluster status không phải green
      - alert: ElasticsearchClusterRed
        expr: elasticsearch_cluster_health_status{color="red"} == 1
        for: 1m
        labels:
          severity: critical

      - alert: ElasticsearchClusterYellow
        expr: elasticsearch_cluster_health_status{color="yellow"} == 1
        for: 5m
        labels:
          severity: warning

      # Unassigned shards
      - alert: ElasticsearchUnassignedShards
        expr: elasticsearch_cluster_health_unassigned_shards > 0
        for: 5m
        labels:
          severity: warning

      # JVM Heap > 85%
      - alert: ElasticsearchHighJVMHeap
        expr: |
          elasticsearch_jvm_memory_used_bytes{area="heap"} /
          elasticsearch_jvm_memory_max_bytes{area="heap"} > 0.85
        for: 3m
        labels:
          severity: critical

      # Disk sắp đầy (< 20% free)
      - alert: ElasticsearchLowDiskSpace
        expr: |
          elasticsearch_filesystem_data_available_bytes /
          elasticsearch_filesystem_data_size_bytes < 0.20
        for: 5m
        labels:
          severity: warning

Bước 5: Tạo user monitoring với quyền tối thiểu

Không dùng admin account cho exporter — tạo user riêng:

# Elasticsearch - tạo role và user qua API
curl -X PUT "http://localhost:9200/_security/role/monitoring_role" \
  -H 'Content-Type: application/json' \
  -u elastic:password \
  -d '{
    "cluster": ["monitor"],
    "indices": [{"names": ["*"], "privileges": ["monitor", "view_index_metadata"]}]
  }'

curl -X PUT "http://localhost:9200/_security/user/monitoring_user" \
  -H 'Content-Type: application/json' \
  -u elastic:password \
  -d '{"password": "strong_password", "roles": ["monitoring_role"]}'

Với OpenSearch thì làm tương tự qua OpenSearch Security REST API hoặc Dashboard UI.

Những điều học được sau 6 tháng chạy production

scrape_interval 30s là đủ cho hầu hết use case. Giảm xuống 15s nếu cần granularity cao hơn cho debug, nhưng exporter sẽ call nhiều ES API hơn, tốn thêm resource của cluster.

Flag --es.shards có thể gây timeout với cluster lớn. Lần đầu mình bật flag này trên cluster 800 shards, exporter timeout liên tục. Giải pháp: thêm --es.timeout=30s hoặc tắt flag nếu không cần monitor shard-level detail.

Dashboard 14191 không cover OpenSearch-specific metrics như security audit log, anomaly detection job status. Nếu dùng OpenSearch với các tính năng mở rộng, cần tự build thêm panels từ raw metrics.

Cái thực sự thuyết phục mình là khoảng 3 giờ sáng có tin nhắn Telegram từ Alertmanager: JVM heap đang ở 88% trên node 2. Team có đúng 30 phút để restart node và tăng heap config trước khi user Nhật Bản vào morning shift. Không có cái alert đó, hậu quả chắc chắn là downtime — và cuộc gọi khó chịu lúc 6 giờ sáng.

Điểm mình thích nhất của cách này: không phải học tool mới. Nếu team đã biết Prometheus và Grafana, 1-2 tiếng là đủ để có monitoring Elasticsearch hoàn chỉnh — shard allocation, JVM heap, disk watermark, và cả alert.

Share: