1. Giới thiệu
Hãy tưởng tượng bạn là admin của một trang web, và mỗi ngày có ngàn người dùng truy cập. Trong logs bạn thấy mọi thứ hoạt động, gần như không có lỗi (chỉ thỉnh thoảng ai đó quên mật khẩu hoặc nhầm captcha). "Mọi thứ tốt!" — bạn nghĩ.
Rồi bỗng ai đó báo support: trang web chậm kinh khủng, trang mở mất 10 giây. Bạn vào logs — không có lỗi! Vui mừng? Không, vì logs cho biết cái gì đã xảy ra (hoặc không), nhưng không cho biết nó xảy ra nhanh hay chậm tới mức nào, bao nhiêu tài nguyên đã tiêu thụ, và hành vi đó thay đổi thế nào khi tải tăng.
Lúc này metric lên sân khấu — những chỉ số có thể đo được của ứng dụng. Không chỉ số lỗi, mà còn thời gian phản hồi trung bình, dung lượng bộ nhớ tiêu thụ, số request trên giây và các chỉ số khác để đánh giá sức khỏe hệ thống.
So sánh:
Logs — là "cái gì đã xảy ra".
Metrics — là "hệ thống hoạt động tốt/xấu thế nào".
Trace — là "tại sao hệ thống hoạt động thế (chi tiết)".
Có những loại metric nào và nên thu thập gì?
Các loại metric chính:
| Loại metric | Ví dụ | Mục đích |
|---|---|---|
| Counters (Bộ đếm) | Số request, lỗi, thất bại | Xu hướng, alert, tải |
| Histograms | Thời gian phản hồi, kích thước gói | Phân bố giá trị, percentiles |
| Gauges (Gauge) | Mức sử dụng bộ nhớ, CPU | Trạng thái hiện tại của tài nguyên |
| Sum (Tổng hợp) | Tổng dung lượng data, byte | Tổng khối lượng thao tác trong khoảng thời gian |
Ví dụ:
- Thời gian phản hồi trung bình và percentil 95 của request GET.
- Số người dùng đang online ngay lúc này.
- Tiêu thụ bộ nhớ (Private Bytes, Working Set).
- Tỷ lệ lỗi loại 500/503.
- Số truy vấn DB mỗi phút.
Những chỉ số này không chỉ giúp tìm lỗi mà còn phòng ngừa — vì tải tăng hoặc thời gian phản hồi tăng dần có thể báo hiệu sự cố sắp tới.
2. Cách hoạt động của việc thu thập metric trong .NET và hệ sinh thái OpenTelemetry
Kiến trúc tổng quát
Trong .NET hiện đại (bắt đầu từ .NET 6, đặc biệt ở .NET 8/9) có hệ thống chuẩn để thu thập metric, dựa trên OpenTelemetry.
Hoạt động theo sơ đồ sau:
- Mã ứng dụng gọi các phương thức để tăng counters, đăng ký gauges, ghi histograms.
- SDK OpenTelemetry Metrics thu thập các metric này (trong bộ nhớ) và định kỳ gửi chúng đi.
- Exporter của metric chuyển chúng đến hệ thống monitoring đã chọn (Prometheus, Application Insights, Grafana Cloud, Datadog, ...).
- Backend monitoring tổng hợp, lưu trữ, hiển thị, tạo alert và dashboard.
Sơ đồ khái quát:
[Ứng dụng của bạn]
⬇
[Thu thập metric (OpenTelemetry SDK)]
⬇
[Exporter metric (Prometheus, AI, Datadog, ...)]
⬇
[Hệ thống monitoring/dashboard/alert]
3. Thực hành: Cơ bản làm việc với metric trong C#
Metric nội bộ đơn giản: System.Diagnostics.Metrics
.NET cung cấp cơ chế metric tích hợp — System.Diagnostics.Metrics.
Các thành phần chính: Meter, Counter<T>, Histogram<T>, ObservableGauge<T>.
Ví dụ: bộ đếm lượt truy cập trang
// Tạo Meter (thường 1 cái cho toàn app)
using System.Diagnostics.Metrics;
static Meter meter = new Meter("MyCompany.MyApp", "1.0");
// Đăng ký counter
static Counter<long> homePageVisits = meter.CreateCounter<long>("HomePageVisits");
// Ở đâu đó trong controller hoặc service...
public void HomePageRequested()
{
homePageVisits.Add(1);
// Phần còn lại của xử lý trang
}
Ghi chú:
- Meter — là "factory" cho metric, có tên duy nhất (namespace app/company).
- CreateCounter<long> — tạo counter; tăng bằng Add(1).
Ví dụ: đo thời gian phản hồi
static Histogram<double> pageLoadTime = meter.CreateHistogram<double>("PageLoadTimeMs");
// Trong handler request:
public void OnRequest()
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
// ...phần xử lý request...
stopwatch.Stop();
pageLoadTime.Record(stopwatch.Elapsed.TotalMilliseconds);
}
Thu thập gauges cho giá trị động
Gauge — chỉ số thay đổi theo thời gian: số user kết nối, dung lượng bộ nhớ hiện tại, v.v.
static ObservableGauge<int> onlineUserGauge = meter.CreateObservableGauge(
"OnlineUsers",
() => GetOnlineUserCount());
// GetOnlineUserCount - phương thức trả về giá trị hiện tại
static int GetOnlineUserCount()
{
// Đây phải là logic thực tế của bạn!
return ActiveUserList.Count;
}
Trong thực tế mọi thứ chạy bất đồng bộ: app báo giá trị metric, exporter lấy chúng và xuất ra ngoài (ví dụ Prometheus scrapes endpoint "/metrics").
Thêm metric vào ứng dụng ASP.NET Core hiện đại
Với ASP.NET Core nhiều thứ sẵn sàng dùng. Thêm package OpenTelemetry.Instrumentation.AspNetCore, bạn sẽ có metric HTTP requests, thời gian phản hồi, số lỗi, v.v.
Ví dụ cấu hình trong Program.cs:
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics =>
{
metrics
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MyApp"))
.AddAspNetCoreInstrumentation() // metric HTTP
.AddRuntimeInstrumentation() // metric runtime .NET CLR
.AddProcessInstrumentation() // CPU/memory của process
.AddMeter("MyCompany.MyApp") // metric của bạn
.AddPrometheusExporter(); // xuất sang Prometheus
});
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Giờ app của bạn sẽ expose metric tại đường dẫn /metrics, có thể bị scrape bởi Prometheus hoặc hệ thống khác.
4. Ví dụ thực tế sử dụng metric
Giám sát hiệu năng trong dự án thực tế
Kết nối metric để biết:
- RPS trung bình và peak (requests per second) API chịu được là bao nhiêu?
- Chỗ "nút cổ chai": endpoint nào trả 300 ms, endpoint khác — 2000 ms?
- Bao nhiêu thời gian cho call DB? (thêm histogram riêng)
Ví dụ: giám sát thời gian query DB
static Histogram<double> dbQueryDuration = meter.CreateHistogram<double>("DbQueryDurationMs");
public async Task<List<Product>> GetProductsAsync()
{
var sw = Stopwatch.StartNew();
var result = await _db.Products.ToListAsync();
sw.Stop();
dbQueryDuration.Record(sw.Elapsed.TotalMilliseconds);
return result;
}
Ví dụ: đếm số lỗi
static Counter<long> apiErrors = meter.CreateCounter<long>("ApiErrors");
public IActionResult SomeEndpoint()
{
try
{
// một hành động nào đó
return Ok();
}
catch (Exception)
{
apiErrors.Add(1);
throw;
}
}
Làm việc với labels (tags) cho metric
Quan trọng là gom dữ liệu theo các thuộc tính hữu ích: endpoint, loại lỗi, loại user, v.v.
homePageVisits.Add(
1,
KeyValuePair.Create<string, object>("UserType", "Admin"));
Hoặc cho histogram:
dbQueryDuration.Record(
sw.Elapsed.TotalMilliseconds,
KeyValuePair.Create<string, object>("QueryType", "GetProducts"));
Nhờ tags bạn có thể vẽ chart trong Grafana không chỉ theo toàn app mà theo từng phân đoạn cụ thể.
5. Tích hợp với Prometheus, Application Insights, Datadog, Grafana
Exporters và tích hợp
- Prometheus — monitoring open-source phổ biến, gần như là standard cho cloud và Kubernetes.
- Application Insights — tích hợp cloud cho Azure.
- Datadog, Grafana Cloud — cho infra chuyên nghiệp.
Tất cả hệ thống này có thể lấy metric từ .NET qua exporters của OpenTelemetry. Tài liệu về exporters OTel
Prometheus (các bước):
- Thêm NuGet package: OpenTelemetry.Exporter.Prometheus.
- Thêm .AddPrometheusExporter() khi đăng ký metric.
- Cấu hình datasource trong Grafana trỏ tới Prometheus và build dashboard.
Links hữu ích:
6. Những điểm cần lưu ý, bẫy và lỗi thường gặp
Một mistake thường gặp — chi tiết hóa tags quá mức. Nếu gán tags quá nhiều giá trị duy nhất (ví dụ ID user/order), số series sẽ bùng nổ — dẫn tới overload lưu trữ metric và chi phí tăng (gọi là cardinality explosion). Giữ tags ở mức "thô" hơn.
Dev đôi khi bỏ qua System.Diagnostics.Metrics và tự làm "xe đạp" qua logs và timer. Kết quả monitoring khó tích hợp và khó bảo trì. Dùng công cụ chuẩn và instrumentation tự động.
Một sai lầm khác — metric được thu thập nhưng không được export. Cấu hình exporter là bắt buộc: thêm ví dụ .AddPrometheusExporter() và kiểm tra endpoint /metrics có thể scrape được.
Và cuối cùng, nhầm lẫn giữa các loại metric: tính thời gian trung bình qua Counter trong khi cần Histogram — vậy bạn sẽ không thấy peak và phân bố. Counters — cho đếm; Histograms — cho thời gian/kích thước/phân bố; Gauges — cho trạng thái hiện tại.
GO TO FULL VERSION