0

Elasticsearch Bài học 49: Log Management - Đưa log từ các Microservices vào Elastic bằng Logstash/Filebeat.

Khi chia nhỏ hệ thống soát vé AFC hay nền tảng e-commerce thành các microservices (viết bằng Golang, Node.js hay PHP) và triển khai qua Docker, các file log sẽ nằm rải rác ở hàng chục container khác nhau. Nếu một lỗi thanh toán xảy ra, việc ssh vào từng server dùng lệnh tail -f để truy vết (trace) là nhiệm vụ bất khả thi.

Để giải quyết bài toán Centralized Logging (Quản lý log tập trung), kiến trúc chuẩn mực nhất cho hệ thống phân tán là sự kết hợp của bộ tứ: Filebeat -> Kafka -> Logstash -> Elasticsearch.

1. Filebeat: "Kẻ giao hàng" siêu nhẹ (Lightweight Shipper)

Rất nhiều lập trình viên có thói quen dùng các thư viện (như Winston trong Node.js hoặc Logrus trong Golang) để gọi API bắn log thẳng vào Elasticsearch. Đây là một Anti-pattern (thực hành tồi) vì hai lý do:

  1. Làm chậm ứng dụng: Mỗi dòng log in ra bắt luồng xử lý chính (Main thread) phải tốn thêm thời gian đợi phản hồi mạng (Network I/O) từ Elasticsearch.

  2. Mất dữ liệu khi đứt mạng: Nếu cụm Elasticsearch nâng cấp hoặc sập, toàn bộ log sinh ra trong thời điểm đó sẽ bốc hơi.

Giải pháp chuẩn: Hãy để microservices ghi log ra một file .txt thuần túy trên ổ cứng cục bộ (hoặc bắn ra stdout trong Docker). Filebeat (viết bằng Golang) được cài đặt song song trên cùng server. Nhiệm vụ của nó là liên tục đọc nhép (tail) sự thay đổi của file log. Filebeat cực kỳ nhẹ, ngốn rất ít RAM/CPU, và có cơ chế nhớ vị trí (Registry). Nếu mất mạng, nó sẽ dừng đọc và chờ đến khi mạng kết nối lại mới gửi tiếp log, đảm bảo không rớt một dòng nào.

2. Kafka: Vùng đệm chống sập (Buffer)

Vào giờ cao điểm của tuyến Metro, hàng vạn log được sinh ra mỗi giây. Nếu Filebeat đẩy thẳng khối lượng này vào Logstash, Logstash (vốn cồng kềnh vì chạy trên Java) sẽ lập tức quá tải, dẫn đến hiện tượng nghẽn cổ chai (Bottleneck).

Với kinh nghiệm sử dụng message broker, bạn hãy đặt Apache Kafka vào giữa.

  • Filebeat chỉ làm nhiệm vụ duy nhất là nén log và ném vào một Topic của Kafka (ví dụ: afc-microservices-logs).

  • Kafka sẽ lưu trữ an toàn lượng log khổng lồ này trên đĩa cứng. Hệ thống của bạn chính thức được an toàn trước mọi đợt bùng nổ traffic.

3. Logstash: Cỗ máy xào nấu dữ liệu (Data Processor)

Đứng ở đầu ra của Kafka là Logstash. Nó đóng vai trò là một Consumer, từ từ "hút" dữ liệu từ Kafka Topic theo đúng tốc độ mà CPU của nó và Elasticsearch có thể chịu đựng.

Dòng log ứng dụng in ra thường là một chuỗi text vô định dạng, ví dụ: [2026-10-17 10:32:00] ERROR [PaymentService] Card 999 failed to deduct: Insufficient balance

Nếu đẩy thẳng chuỗi này vào Elasticsearch, nó sẽ thành một cục text vô dụng, bạn không thể vẽ biểu đồ "Đếm số lỗi theo từng Service". Logstash giải quyết bài toán này bằng bộ lọc Grok Filter (xây dựng dựa trên Regex). Nó bóc tách chuỗi text trên thành một khối JSON có cấu trúc rành mạch:

JSON

{
  "@timestamp": "2026-10-17T10:32:00Z",
  "level": "ERROR",
  "service": "PaymentService",
  "card_id": 999,
  "message": "failed to deduct: Insufficient balance"
}

4. Bóc tách một Pipeline Logstash thực tế

Một cấu hình Logstash (logstash.conf) được chia làm 3 khối rạch ròi: Input, Filter và Output. Dưới đây là template chuẩn để bạn áp dụng cho hệ thống:

Ruby

input {
  kafka {
    bootstrap_servers => "kafka-broker:9092"
    topics => ["afc-microservices-logs"]
    consumer_threads => 3
    codec => "json"
  }
}

filter {
  # 1. Dùng Grok để dùng Regex chẻ chuỗi log thành các field JSON
  grok {
    match => { "message" => "\[%{TIMESTAMP_ISO8601:log_time}\] %{LOGLEVEL:level} \[%{DATA:service}\] %{GREEDYDATA:log_content}" }
  }
  
  # 2. Xóa các log rác (Ví dụ mức DEBUG không cần đưa vào ES cho đỡ tốn ổ cứng)
  if [level] == "DEBUG" {
    drop { }
  }

  # 3. Ghi đè thời gian của Elastic bằng đúng thời gian lỗi sinh ra trong file log
  date {
    match => [ "log_time", "yyyy-MM-dd HH:mm:ss" ]
    target => "@timestamp"
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch-node1:9200", "http://elasticsearch-node2:9200"]
    # Bắn vào ILM Alias (Học ở Bài 41) để hệ thống tự động xoay vòng file
    index => "microservices-logs-write" 
  }
}

Với kiến trúc này, việc truy vết lỗi trên môi trường Production chỉ còn là thao tác kéo thả, filter trên giao diện Kibana trong vài mili-giây, giúp team Backend tăng tốc độ gỡ lỗi (debug) lên hàng trăm lần.

Chúng ta chỉ còn đúng 1 mảnh ghép cuối cùng để biến trải nghiệm tìm kiếm trở nên hoàn hảo: Tính năng Gợi ý tự động ngay khi user vừa gõ chữ.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí