Cơn đau đầu khi phải instrument từng ứng dụng một
Hệ thống monitoring của mình gồm Prometheus + Grafana đang theo dõi 15 server, và setup đó đã giúp phát hiện sự cố trước khi user báo nhiều lần rồi. Nhưng có một điểm mù mà mình mãi không giải quyết được: giám sát bên trong từng ứng dụng — latency theo từng endpoint, error rate, số request đang xử lý.
Mỗi lần team thêm một service mới, quy trình cũ là: mở code ra, cài thư viện prometheus_client hoặc OpenTelemetry SDK, viết middleware để đo latency, expose /metrics, rồi cấu hình Prometheus scrape. Service Go thì một kiểu, Python thì khác, Node.js lại khác nữa. Với team nhỏ, việc này ngốn 2-3 giờ mỗi service — và thường bị gác lại khi deadline gấp.
Sau 3 tháng chạy như vậy, mình nhận ra có đến 40% số service không có metrics gì cả — toàn là những service được viết nhanh và không ai có thời gian quay lại instrument.
Tại sao cách truyền thống lại khó duy trì
Công cụ không thiếu. OpenTelemetry rất capable, Prometheus client library đầy đủ tính năng. Nhưng instrumentation thủ công tạo ra technical debt theo kiểu rất khó thấy:
- Developer phải học API của từng SDK cho từng ngôn ngữ
- Code bị pha trộn giữa business logic và monitoring logic
- Service mới không tự nhiên có metrics — ai đó phải nhớ thêm vào
- Khi refactor, metrics cũ có thể không còn chính xác nhưng vẫn chạy, gây nhầm lẫn
APM thương mại như Datadog hay New Relic có auto-instrumentation agent khá tốt. Nhưng với 15 host, Datadog Pro tính ra khoảng $300-400/tháng — chưa kể custom metrics. Không phù hợp với ngân sách team nhỏ.
Các hướng giải quyết đã thử
Hướng 1: Instrumentation tập trung tại API Gateway
Cài Nginx hoặc Envoy làm gateway, đo latency và request count tại đó. Cách này nhanh nhưng chỉ thấy được tầng ngoài cùng — không biết service nào bên trong đang chậm, không có trace xuyên suốt qua nhiều service.
Hướng 2: OpenTelemetry Collector + auto-instrumentation agent
Java có -javaagent rất trưởng thành. Python có opentelemetry-instrument. Node.js có @opentelemetry/auto-instrumentations-node. Nhưng Go thì không — Go compile ra binary tĩnh, không có cơ chế inject agent lúc runtime theo kiểu JVM.
Mình đã dùng cách này cho Python và Node.js, nhưng vẫn phải sửa entrypoint của từng service, và Go vẫn bị bỏ trống.
Hướng 3 — cách mình đang dùng: Grafana Beyla với eBPF
Beyla là open-source tool của Grafana Labs, dùng eBPF (extended Berkeley Packet Filter) để hook vào kernel Linux. Nó tự động quan sát các ứng dụng đang chạy — không cần chỉnh sửa một dòng code nào. Beyla hoạt động ở tầng kernel, intercept các syscall liên quan đến HTTP/gRPC, rồi tổng hợp thành metrics RED (Rate, Errors, Duration) và traces.
Sau 6 tháng chạy trên production, đây là cách mình thấy hiệu quả nhất cho môi trường mixed-language.
Cài đặt Grafana Beyla từng bước
Yêu cầu
- Linux kernel 5.8 trở lên (kiểm tra:
uname -r) - Quyền root hoặc
CAP_BPF,CAP_PERFMON,CAP_SYS_PTRACE - Prometheus đang chạy để nhận metrics (hoặc dùng Grafana Cloud)
Cài Beyla bằng Docker
Cách nhanh nhất để thử là chạy Beyla như một container song song với ứng dụng cần giám sát:
# Giám sát ứng dụng đang chạy trên host port 8080
docker run --rm \
--pid=host \
--privileged \
-e BEYLA_OPEN_PORT=8080 \
-e BEYLA_PROMETHEUS_PORT=9400 \
-p 9400:9400 \
grafana/beyla:latest
Truy cập http://localhost:9400/metrics — metric http_server_request_duration_seconds sẽ xuất hiện ngay, không cần sửa gì trong ứng dụng.
Cài Beyla bằng binary trực tiếp
# Tải binary mới nhất (kiểm tra trang releases để lấy version mới nhất)
wget https://github.com/grafana/beyla/releases/download/v1.8.0/beyla-linux-amd64
chmod +x beyla-linux-amd64
sudo mv beyla-linux-amd64 /usr/local/bin/beyla
# Chạy và tự tìm process đang lắng nghe port 8080
sudo BEYLA_OPEN_PORT=8080 BEYLA_PROMETHEUS_PORT=9400 beyla
Cấu hình file YAML cho production
Biến môi trường chỉ hợp lý khi thử nghiệm. Trên production, file cấu hình YAML dễ quản lý hơn nhiều:
# /etc/beyla/config.yaml
open_port: 8080 # Port ứng dụng đang lắng nghe
service_name: my-api # Tên hiển thị trong Grafana
prometheus_export:
port: 9400
path: /metrics
# Tùy chọn: export traces sang Grafana Tempo
otel_traces_export:
endpoint: http://tempo:4317
# Lọc path không cần theo dõi (health check, static files)
filters:
application:
- path_pattern: '/health'
method: GET
# Chạy với file config
sudo beyla --config /etc/beyla/config.yaml
Tích hợp với Prometheus
Thêm job vào prometheus.yml:
scrape_configs:
- job_name: 'beyla-my-api'
static_configs:
- targets: ['localhost:9400']
relabel_configs:
- source_labels: [__address__]
target_label: instance
Chạy Beyla như systemd service
Để Beyla tự khởi động cùng server:
# /etc/systemd/system/beyla.service
[Unit]
Description=Grafana Beyla eBPF Auto-instrumentation
After=network.target
[Service]
ExecStart=/usr/local/bin/beyla --config /etc/beyla/config.yaml
Restart=on-failure
User=root
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now beyla
sudo systemctl status beyla
Beyla hoạt động thế nào với từng ngôn ngữ
Cơ chế bên dưới khác nhau tùy ngôn ngữ, nhưng đầu ra metrics thì đồng nhất:
- Go: Beyla dùng uprobes để hook vào các hàm net/http và gRPC trong binary đã compile. Đây là thứ mà không có agent nào khác làm được với Go.
- Python: Hook vào WSGI/ASGI middleware layer (Django, Flask, FastAPI đều được).
- Node.js: Hook vào V8 runtime và http/https module.
Metrics sinh ra đều theo chuẩn OpenTelemetry semantic conventions, nên dashboard Grafana dùng được ngay mà không cần tùy chỉnh.
Kết quả sau 6 tháng dùng thực tế
Thứ làm mình bất ngờ không phải là Beyla chạy được — mà là nó chạy tốt ngay cả trên những service cũ không ai dám đụng tới. Mình có một service Go viết từ 2021, không có unit test, không ai trong team hiểu rõ hoàn toàn — giờ nó đã có đầy đủ latency histogram, error rate, và request throughput mà không cần chạm vào một dòng code nào.
Coverage metrics trong team tăng từ 60% lên 100% trong vòng một buổi chiều, đơn giản là deploy Beyla lên từng host.
Về overhead: mình đo được khoảng 1-2% CPU và ~50MB RAM cho một host đang xử lý ~500 req/s. Chấp nhận được hoàn toàn.
Một điểm cần lưu ý: Beyla cần kernel 5.8+ và quyền privileged. Nếu bạn chạy trong môi trường containerized với security policies nghiêm ngặt (như GKE Autopilot), cần kiểm tra khả năng tương thích trước.
Dashboard Grafana cho Beyla
Grafana Labs cung cấp sẵn dashboard tại Grafana.com với ID 19419 (RED Metrics) và 19420 (Service Map). Import vào Grafana:
- Vào Grafana → Dashboards → Import
- Nhập ID
19419→ Load - Chọn Prometheus datasource → Import
Sau khi import xong, Service Map hiện ra ngay — tất cả service, traffic giữa chúng, và request flow đều hiển thị mà không cần config thêm gì. Request Rate, Error Rate, P99 latency theo từng endpoint đều có sẵn. Không cần viết một dòng PromQL nào.

