OpenTelemetry — Chuẩn Observability Mở Đang Thống Trị Hệ Thống Phân Tán
Posted on: 4/27/2026 1:11:58 PM
Table of contents
- Mục lục
- 1. OpenTelemetry là gì và tại sao bạn cần quan tâm?
- 2. Ba trụ cột: Traces, Metrics, Logs
- 3. Kiến trúc tổng quan OpenTelemetry
- 4. Declarative Configuration — vừa đạt Stable
- 5. OBI: eBPF Instrumentation — Zero-Code Observability
- 6. Tích hợp OpenTelemetry trong .NET 10 / ASP.NET Core
- 7. OpenTelemetry Collector — Trung tâm xử lý telemetry
- 8. Chiến lược triển khai Production-Grade
- 9. So sánh OTel với các giải pháp khác
- 10. Kết luận
1. OpenTelemetry là gì và tại sao bạn cần quan tâm?
OpenTelemetry (OTel) là một dự án open-source thuộc CNCF (Cloud Native Computing Foundation), cung cấp bộ APIs, SDKs, và công cụ chuẩn hóa để thu thập dữ liệu telemetry — bao gồm traces, metrics, và logs — từ ứng dụng và hạ tầng phân tán.
Trước OTel, mỗi vendor observability (Datadog, New Relic, Dynatrace, Jaeger, Zipkin...) đều có agent và SDK riêng. Điều này tạo ra vendor lock-in nghiêm trọng: muốn đổi backend, bạn phải thay đổi code instrumentation trên toàn bộ service. OTel giải quyết bài toán này bằng cách tạo ra một lớp trung gian vendor-neutral — bạn instrument một lần, export đến bất kỳ backend nào qua giao thức OTLP (OpenTelemetry Protocol).
Tại sao 2026 là thời điểm vàng?
Tháng 4/2026 đánh dấu hai cột mốc lớn: Declarative Configuration chính thức stable (v1.0.0) và OBI (eBPF Instrumentation) ra mắt beta tại KubeCon EU. Cộng thêm .NET 10 với auto-instrumentation bản 1.15.0, OTel đã sẵn sàng cho production ở mọi ngôn ngữ chính.
2. Ba trụ cột: Traces, Metrics, Logs
OTel thống nhất ba loại tín hiệu (signals) quan trọng nhất trong observability:
graph LR
subgraph Signals["Ba Trụ Cột OTel"]
T["🔍 Traces
Theo dõi request
xuyên services"]
M["📊 Metrics
Đo lường hiệu suất
theo thời gian"]
L["📝 Logs
Sự kiện chi tiết
có ngữ cảnh"]
end
T -->|"trace_id"| C["Correlation
Engine"]
M -->|"exemplar"| C
L -->|"trace_id"| C
C --> I["Insight
toàn diện"]
style T fill:#e94560,stroke:#fff,color:#fff
style M fill:#2c3e50,stroke:#fff,color:#fff
style L fill:#4CAF50,stroke:#fff,color:#fff
style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style I fill:#f8f9fa,stroke:#e94560,color:#2c3e50
Ba trụ cột observability của OpenTelemetry, liên kết qua trace_id
Traces (Distributed Tracing)
Một trace ghi lại hành trình hoàn chỉnh của một request khi nó di chuyển qua nhiều service. Mỗi trace chứa nhiều spans — mỗi span đại diện cho một đơn vị công việc (gọi API, truy vấn database, xử lý message queue...). Spans liên kết với nhau qua trace_id và parent_span_id, tạo thành cây gọi (call tree).
Metrics
Metrics là dữ liệu số đo lường theo thời gian: request latency (histogram), error rate (counter), active connections (gauge), CPU usage... OTel hỗ trợ cả push (OTLP export) lẫn pull (Prometheus scrape) model.
Logs
OTel không thay thế logging framework hiện có (Serilog, NLog, log4j...) mà bổ sung context — inject trace_id và span_id vào mỗi log entry. Khi một request lỗi, bạn có thể nhảy thẳng từ trace sang log chi tiết mà không cần grep thủ công.
3. Kiến trúc tổng quan OpenTelemetry
graph TB
subgraph Apps["Ứng dụng"]
A1["Service A
.NET 10"]
A2["Service B
Node.js"]
A3["Service C
Go"]
end
subgraph SDK["OTel SDK / Auto-Instrumentation"]
S1["SDK .NET"]
S2["SDK JS"]
S3["SDK Go"]
end
subgraph OBI_Layer["OBI (eBPF)"]
OBI["Zero-Code
eBPF Probes"]
end
A1 --> S1
A2 --> S2
A3 --> S3
A1 -.->|"kernel hooks"| OBI
A2 -.->|"kernel hooks"| OBI
A3 -.->|"kernel hooks"| OBI
S1 -->|"OTLP"| COL["OTel Collector"]
S2 -->|"OTLP"| COL
S3 -->|"OTLP"| COL
OBI -->|"OTLP"| COL
subgraph Backends["Backends"]
J["Jaeger / Tempo"]
P["Prometheus / Mimir"]
L["Loki / Elasticsearch"]
end
COL --> J
COL --> P
COL --> L
J --> G["Grafana Dashboard"]
P --> G
L --> G
style A1 fill:#e94560,stroke:#fff,color:#fff
style A2 fill:#2c3e50,stroke:#fff,color:#fff
style A3 fill:#4CAF50,stroke:#fff,color:#fff
style OBI fill:#ff9800,stroke:#fff,color:#fff
style COL fill:#16213e,stroke:#fff,color:#fff
style G fill:#e94560,stroke:#fff,color:#fff
Kiến trúc end-to-end: SDK + OBI → Collector → Backends → Visualization
Kiến trúc OTel gồm 4 tầng chính:
- Instrumentation Layer: SDK tích hợp vào code (manual/auto) hoặc OBI hook ở kernel level
- OTLP Protocol: Giao thức truyền tải chuẩn (gRPC hoặc HTTP/protobuf)
- Collector: Nhận, xử lý (filter, enrich, batch), rồi export telemetry
- Backend: Lưu trữ và truy vấn — Jaeger, Tempo, Prometheus, Loki, Elasticsearch...
4. Declarative Configuration — vừa đạt Stable
Tháng 4/2026, OpenTelemetry chính thức đánh dấu Declarative Configuration là stable (v1.0.0). Đây là cách cấu hình OTel bằng file YAML thay vì hàng chục biến môi trường rời rạc.
Lợi ích chính
Một file YAML duy nhất thay thế hàng chục environment variables. Dễ version control, dễ review, dễ replicate giữa các môi trường.
Ví dụ cấu hình YAML
# otel-config.yaml — Declarative Configuration v1.0
file_format: "0.4"
tracer_provider:
processors:
- batch:
schedule_delay: 5000
export_timeout: 30000
max_queue_size: 2048
max_export_batch_size: 512
exporter:
otlp:
protocol: grpc
endpoint: http://otel-collector:4317
compression: gzip
meter_provider:
readers:
- periodic:
interval: 60000
exporter:
otlp:
protocol: grpc
endpoint: http://otel-collector:4317
logger_provider:
processors:
- batch:
exporter:
otlp:
protocol: grpc
endpoint: http://otel-collector:4317
resource:
attributes:
service.name: my-api
service.version: "2.1.0"
deployment.environment: production
Kích hoạt bằng biến môi trường duy nhất:
export OTEL_CONFIG_FILE=/etc/otel/otel-config.yaml
Các thành phần đã stable
| Thành phần | Mô tả | Trạng thái |
|---|---|---|
| JSON Schema (opentelemetry-configuration) | Data model schema version 1.0.0 | ✅ Stable |
| YAML Representation | File-based configuration format | ✅ Stable |
| In-Memory Model | SDK biểu diễn config trong bộ nhớ | ✅ Stable |
| ConfigProperties | Generic YAML mapping node | ✅ Stable |
| PluginComponentProvider | Cơ chế tham chiếu custom plugin | ✅ Stable |
| OTEL_CONFIG_FILE | Biến môi trường kích hoạt | ✅ Stable |
Hỗ trợ theo ngôn ngữ
| Ngôn ngữ | Trạng thái Declarative Config |
|---|---|
| Java | ✅ Đầy đủ (agent + SDK) |
| Go | ✅ Đầy đủ (Collector internal) |
| C++ | ✅ Đầy đủ |
| JavaScript | ✅ Đầy đủ |
| PHP | ✅ Đầy đủ |
| .NET | 🔄 Đang phát triển |
| Python | 🔄 Đang phát triển |
5. OBI: eBPF Instrumentation — Zero-Code Observability
OBI (OpenTelemetry eBPF Instrumentation) là bước nhảy vọt lớn nhất trong observability 2026. Kế thừa từ Grafana Beyla (được donate cho OTel cuối 2025), OBI sử dụng eBPF để hook trực tiếp vào kernel Linux — thu thập traces và metrics mà không cần sửa một dòng code nào.
graph TB
subgraph KernelSpace["Kernel Space"]
UP["uprobes
SSL_read/SSL_write"]
KP["kprobes
tcp_sendmsg/recvmsg"]
TP["tracepoints
scheduling, fs events"]
end
subgraph Maps["eBPF Maps"]
PEA["perf_event_array"]
RB["ring_buffer"]
end
subgraph UserSpace["User Space — OBI Agent (Go)"]
MR["Map Reader"]
SB["Span Builder"]
FE["Filter & Enrich"]
EX["OTLP Exporter"]
end
UP --> PEA
KP --> PEA
TP --> RB
PEA --> MR
RB --> MR
MR --> SB
SB --> FE
FE --> EX
EX -->|"gRPC/HTTP"| COL["OTel Collector"]
style UP fill:#e94560,stroke:#fff,color:#fff
style KP fill:#e94560,stroke:#fff,color:#fff
style TP fill:#e94560,stroke:#fff,color:#fff
style PEA fill:#2c3e50,stroke:#fff,color:#fff
style RB fill:#2c3e50,stroke:#fff,color:#fff
style EX fill:#4CAF50,stroke:#fff,color:#fff
style COL fill:#16213e,stroke:#fff,color:#fff
Kiến trúc hai tầng của OBI: kernel probes → user-space agent → OTLP export
OBI hoạt động như thế nào?
OBI vận hành theo mô hình hai tầng:
- Kernel Space: uprobes chặn SSL_read/SSL_write (đọc traffic TLS), kprobes theo dõi tcp_sendmsg/tcp_recvmsg, tracepoints ghi nhận scheduling và filesystem events
- User Space: Agent Go đọc dữ liệu từ eBPF maps, xây dựng spans, áp dụng filter/enrichment, rồi export qua OTLP
Yêu cầu hệ thống
| Yêu cầu | Chi tiết |
|---|---|
| Kernel | Linux 5.8+ (RHEL/Rocky 4.18+ với backport); BTF bắt buộc |
| Kiến trúc | amd64, arm64 (Graviton, Ampere) |
| Quyền | root hoặc CAP_BPF + CAP_SYS_PTRACE |
| Pod config | hostPID: true |
| Resources (typical) | CPU: 100m–500m, Memory: 256Mi–512Mi |
Giao thức hỗ trợ
Application Layer
HTTP/gRPC với automatic RED metrics, TLS-encrypted traffic (kernel-level SSL hooks), protocol-agnostic span generation
Database Protocols
PostgreSQL (pgx), MySQL, MongoDB, Redis, Couchbase — native server spans không cần ORM
Emerging (planned for 1.0)
GenAI APIs (OpenAI, Anthropic), Message brokers (MQTT, AMQP, NATS, Redis Pub/Sub)
SDK vs. OBI — Khi nào dùng gì?
| Tiêu chí | SDK (truyền thống) | OBI (eBPF) |
|---|---|---|
| Thay đổi code | Cần cho mỗi service | Không — kernel-level hooks |
| Third-party binaries | Không visibility | Tự động visibility |
| Custom business events | ✅ Linh hoạt | ❌ Chỉ protocol-level |
| Payload access | App-defined | Kernel-level SSL/DB capture |
| Deploy workflow | Rebuild + redeploy | Config-driven, DaemonSet |
| Hệ điều hành | Mọi OS | Chỉ Linux (kernel 5.8+) |
Lưu ý quan trọng
OBI bổ sung chứ không thay thế SDK. Trong production, chạy song song cả hai: OBI cho infrastructure visibility tự động, SDK cho business-level events và custom spans.
6. Tích hợp OpenTelemetry trong .NET 10 / ASP.NET Core
.NET là một trong những ecosystem có hỗ trợ OTel tốt nhất nhờ System.Diagnostics — nền tảng native mà OTel .NET SDK xây dựng trên đó. Với auto-instrumentation v1.15.0 (tháng 4/2026), bạn có thể instrument một ASP.NET Core app trong vài phút.
Setup cơ bản
// Program.cs — .NET 10 + OpenTelemetry
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Metrics;
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
var builder = WebApplication.CreateBuilder(args);
// Resource: định danh service
var resource = ResourceBuilder.CreateDefault()
.AddService("my-api", serviceVersion: "2.1.0");
// Traces
builder.Services.AddOpenTelemetry()
.ConfigureResource(r => r.AddService("my-api"))
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSqlClientInstrumentation(o => o.SetDbStatementForText = true)
.AddRedisInstrumentation()
.AddOtlpExporter(o =>
{
o.Endpoint = new Uri("http://otel-collector:4317");
o.Protocol = OpenTelemetry.Exporter.OtlpExportProtocol.Grpc;
}))
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation()
.AddOtlpExporter())
.WithLogging(logging => logging
.AddOtlpExporter());
var app = builder.Build();
app.MapControllers();
app.Run();
Auto-instrumentation không cần code
Nếu không muốn sửa Program.cs, sử dụng zero-code instrumentation qua environment variables:
# Dockerfile hoặc docker-compose.yml
ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER={918728DD-259F-4A6A-AC2B-B85E1B658318}
ENV CORECLR_PROFILER_PATH=/otel-dotnet/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so
ENV DOTNET_ADDITIONAL_DEPS=/otel-dotnet/AdditionalDeps
ENV DOTNET_SHARED_STORE=/otel-dotnet/store
ENV OTEL_DOTNET_AUTO_HOME=/otel-dotnet
ENV OTEL_SERVICE_NAME=my-api
ENV OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
Custom spans cho business logic
using System.Diagnostics;
public class OrderService
{
private static readonly ActivitySource Source = new("MyApp.OrderService");
public async Task<Order> PlaceOrderAsync(OrderRequest request)
{
using var activity = Source.StartActivity("PlaceOrder");
activity?.SetTag("order.customer_id", request.CustomerId);
activity?.SetTag("order.items_count", request.Items.Count);
var order = await _repository.CreateAsync(request);
activity?.SetTag("order.id", order.Id);
activity?.SetTag("order.total", order.Total);
activity?.AddEvent(new ActivityEvent("OrderCreated"));
return order;
}
}
7. OpenTelemetry Collector — Trung tâm xử lý telemetry
OTel Collector là thành phần không thể thiếu trong production. Nó đóng vai trò gateway trung gian — nhận telemetry từ nhiều nguồn, xử lý (filter, transform, batch, sample), rồi export đến nhiều backends.
graph LR
subgraph Receivers["Receivers"]
R1["OTLP
(gRPC/HTTP)"]
R2["Prometheus
scrape"]
R3["Jaeger
thrift"]
end
subgraph Processors["Processors"]
P1["Batch"]
P2["Filter"]
P3["Attributes
Enrich"]
P4["Tail Sampling"]
end
subgraph Exporters["Exporters"]
E1["OTLP → Tempo"]
E2["Prometheus
Remote Write"]
E3["Loki"]
end
R1 --> P1
R2 --> P1
R3 --> P1
P1 --> P2
P2 --> P3
P3 --> P4
P4 --> E1
P4 --> E2
P4 --> E3
style R1 fill:#e94560,stroke:#fff,color:#fff
style R2 fill:#2c3e50,stroke:#fff,color:#fff
style R3 fill:#4CAF50,stroke:#fff,color:#fff
style P4 fill:#ff9800,stroke:#fff,color:#fff
style E1 fill:#16213e,stroke:#fff,color:#fff
style E2 fill:#16213e,stroke:#fff,color:#fff
style E3 fill:#16213e,stroke:#fff,color:#fff
Pipeline Collector: Receivers → Processors → Exporters
Cấu hình Collector cho production
# otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
send_batch_size: 1024
timeout: 5s
filter:
error_mode: ignore
traces:
span:
- 'attributes["http.route"] == "/health"'
- 'attributes["http.route"] == "/ready"'
tail_sampling:
decision_wait: 10s
policies:
- name: error-policy
type: status_code
status_code: {status_codes: [ERROR]}
- name: latency-policy
type: latency
latency: {threshold_ms: 1000}
- name: probabilistic-policy
type: probabilistic
probabilistic: {sampling_percentage: 10}
resource:
attributes:
- key: deployment.environment
value: production
action: upsert
exporters:
otlp/tempo:
endpoint: tempo:4317
tls:
insecure: true
prometheusremotewrite:
endpoint: http://mimir:9009/api/v1/push
loki:
endpoint: http://loki:3100/loki/api/v1/push
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch, filter, tail_sampling, resource]
exporters: [otlp/tempo]
metrics:
receivers: [otlp]
processors: [batch, resource]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp]
processors: [batch, resource]
exporters: [loki]
Tail Sampling — chiến lược tiết kiệm chi phí
Thay vì sample ngẫu nhiên ở SDK (head sampling), tail sampling tại Collector cho phép giữ 100% traces lỗi và 100% traces chậm (>1s), chỉ sample 10% traces bình thường. Giảm đáng kể chi phí storage mà không mất thông tin quan trọng.
8. Chiến lược triển khai Production-Grade
Deployment patterns
graph TB
subgraph Pattern1["Pattern 1: Sidecar"]
P1A["App Container"] --> P1C["Collector Sidecar"]
P1C --> P1B["Backend"]
end
subgraph Pattern2["Pattern 2: DaemonSet"]
P2A1["App Pod 1"] --> P2C["Collector
DaemonSet"]
P2A2["App Pod 2"] --> P2C
P2C --> P2B["Backend"]
end
subgraph Pattern3["Pattern 3: Gateway"]
P3A["Collector
DaemonSet"] --> P3G["Collector
Gateway"]
P3G --> P3B1["Backend 1"]
P3G --> P3B2["Backend 2"]
end
style P1C fill:#e94560,stroke:#fff,color:#fff
style P2C fill:#e94560,stroke:#fff,color:#fff
style P3G fill:#e94560,stroke:#fff,color:#fff
Ba deployment patterns phổ biến cho OTel Collector
| Pattern | Ưu điểm | Nhược điểm | Phù hợp khi |
|---|---|---|---|
| Sidecar | Isolation tốt, config riêng per service | Resource overhead cao | Multi-tenant, compliance strict |
| DaemonSet | Resource hiệu quả, dễ quản lý | Shared config, noisy neighbor | Phần lớn workloads K8s |
| Gateway | Central control, multi-backend routing | Single point of failure | Tổ chức lớn, nhiều backends |
Checklist triển khai production
- Bắt đầu với auto-instrumentation — SDK hoặc zero-code. Không cần custom spans ngay từ đầu
- Triển khai Collector trước backend — luôn đi qua Collector, không export trực tiếp từ SDK đến backend
- Cấu hình tail sampling sớm — giữ 100% error traces, sample traces bình thường để kiểm soát chi phí
- Filter health check spans — /health, /ready, /metrics tạo ra noise khổng lồ
- Thêm resource attributes — service.name, service.version, deployment.environment bắt buộc
- Monitor the monitor — Collector cũng phải được observability (self-telemetry, /healthz endpoint)
- Cân nhắc OBI — chạy song song cho third-party services và baseline visibility
9. So sánh OTel với các giải pháp khác
| Tiêu chí | OpenTelemetry | Datadog Agent | Elastic APM | AWS X-Ray |
|---|---|---|---|---|
| Vendor lock-in | ❌ Không | ✅ Cao | Trung bình | ✅ AWS only |
| Chi phí license | Miễn phí (OSS) | Trả phí | Basic miễn phí | Trả phí theo usage |
| Ngôn ngữ hỗ trợ | 12+ ngôn ngữ | 10+ ngôn ngữ | 7 ngôn ngữ | 5 ngôn ngữ |
| eBPF instrumentation | ✅ OBI | ✅ USM | ❌ | ❌ |
| Declarative config | ✅ Stable | YAML riêng | YAML riêng | JSON riêng |
| Community | CNCF, 1000+ contributors | Proprietary | Elastic community | AWS only |
| Backend flexibility | Bất kỳ OTLP backend | Chỉ Datadog | Chủ yếu Elastic | Chỉ AWS |
10. Kết luận
OpenTelemetry đã chuyển từ "dự án triển vọng" thành tiêu chuẩn không thể bỏ qua cho mọi hệ thống phân tán. Với declarative configuration stable, OBI eBPF instrumentation beta, và ecosystem SDK trưởng thành trên mọi ngôn ngữ chính — chi phí adopt OTel chưa bao giờ thấp đến vậy, trong khi giá trị mang lại ngày càng rõ ràng.
Nếu bạn đang xây dựng hệ thống trên .NET, Node.js, Go, hay bất kỳ stack nào — hãy bắt đầu với auto-instrumentation + Collector. Khi đã có baseline visibility, thêm custom spans cho business events và cân nhắc OBI cho infrastructure layer. Observability không phải luxury — nó là nền tảng để vận hành hệ thống phân tán hiệu quả.
Tóm tắt hành động
- Bước 1: Cài đặt OTel SDK / auto-instrumentation cho stack hiện tại
- Bước 2: Triển khai OTel Collector (DaemonSet hoặc sidecar)
- Bước 3: Cấu hình tail sampling + filter health checks
- Bước 4: Kết nối với backend (Grafana LGTM stack miễn phí cho self-host)
- Bước 5: Thử nghiệm OBI trên một cluster Linux cho zero-code visibility
Nguồn tham khảo
- OpenTelemetry — Declarative Configuration is Stable!
- OpenTelemetry eBPF Instrumentation (OBI) Documentation
- InfoQ — OpenTelemetry Declarative Configuration Reaches Stability Milestone
- DEV Community — OBI Complete Guide: KubeCon EU 2026 Beta Launch
- Microsoft Learn — .NET Observability with OpenTelemetry
- Grafana Labs — OpenTelemetry: What's New and Next in 2026
- OpenTelemetry — eBPF Instrumentation 2026 Goals
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.