可观测性:不只是监控的升级
传统的网站监控关注的是指标(CPU、内存、QPS)和告警,但当故障发生时,仅凭仪表盘上的红线闪烁往往无法定位根因。可观测性(Observability)的核心理念是:通过系统外部输出(日志、指标、追踪)来理解系统内部状态。2024年以后,OpenTelemetry已成为可观测性领域的事实标准,统一的采集SDK和标准化的数据格式让三大支柱(Logs、Metrics、Traces)真正实现了融合。
三大支柱的定位与选型
指标(Metrics):宏观感知
指标是聚合后的数值数据,适合用于告警和趋势分析。关键指标包括:
- RED指标:Rate(请求速率)、Errors(错误率)、Duration(延迟分布)——面向请求的黄金指标
- USE指标:Utilization(使用率)、Saturation(饱和度)、Errors(错误)——面向资源的指标
# Prometheus中定义RED指标示例
http_requests_total{method="GET", path="/api/users", status="200"}
http_request_duration_seconds_bucket{method="GET", path="/api/users", le="0.1"}
日志(Logs):细节还原
日志记录离散事件,是排查问题时最直接的依据。结构化日志是现代运维的基础:
# 传统非结构化日志
2026-07-15 10:30:15 ERROR - User login failed for user_id=12345
# 结构化日志(JSON)
{
"timestamp": "2026-07-15T10:30:15.123Z",
"level": "ERROR",
"service": "auth-service",
"trace_id": "abc123def456",
"span_id": "789ghi",
"message": "User login failed",
"attributes": {
"user_id": "12345",
"ip": "192.168.1.100",
"reason": "invalid_password"
}
}
关键在于日志中嵌入trace_id和span_id,实现日志与链路追踪的联动。
链路追踪(Traces):链路串联
分布式追踪是理解请求在微服务间流转过程的利器。一个Trace包含多个Span,每个Span代表一次操作:
Trace: order-checkout-12345
├── Span: API Gateway (12ms)
│ ├── Span: Auth Service (3ms)
│ ├── Span: Order Service (45ms)
│ │ ├── Span: Inventory Check (8ms)
│ │ ├── Span: Price Calculate (5ms)
│ │ └── Span: Payment Service (30ms)
│ │ └── Span: Bank API Call (25ms)
│ └── Span: Notification Service (2ms)
OpenTelemetry实战集成
Java应用集成
对于Spring Boot应用,OpenTelemetry提供了Java Agent方式零代码侵入接入:
# 下载 OpenTelemetry Java Agent
curl -L -o otel-agent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
# 启动应用时挂载Agent
java -javaagent:otel-agent.jar \
-Dotel.service.name=order-service \
-Dotel.exporter.otlp.endpoint=http://otel-collector:4317 \
-Dotel.resource.attributes=service.namespace=production,deployment.environment=prod \
-jar app.jar
Agent自动采集HTTP请求、数据库调用、消息队列等常见组件的链路数据,对业务代码零侵入。
Python应用集成
Python应用使用SDK手动埋点更灵活:
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
from opentelemetry.instrumentation.requests import RequestsInstrumentor
# 配置Tracer
provider = TracerProvider()
processor = BatchSpanProcessor(OTLPSpanExporter(
endpoint="http://otel-collector:4317",
insecure=True
))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
# 自动埋点
from flask import Flask
app = Flask(__name__)
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
@app.route('/api/users/<user_id>')
def get_user(user_id):
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("fetch_user_profile") as span:
span.set_attribute("user.id", user_id)
# 业务逻辑...
return {"id": user_id, "name": "test"}
Collector部署架构
OpenTelemetry Collector是数据管道的核心,推荐使用DaemonSet模式部署:
# 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
memory_limiter:
check_interval: 1s
limit_mib: 512
filter:
error_mode: ignore
traces:
span:
- 'attributes["http.route"] == "/healthz"'
exporters:
otlp/jaeger:
endpoint: jaeger-collector:4317
tls:
insecure: true
prometheusremotewrite:
endpoint: http://prometheus:9090/api/v1/write
elasticsearch:
endpoints:
- http://elasticsearch:9200
logs_index: otel-logs
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, filter]
exporters: [otlp/jaeger]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheusremotewrite]
logs:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [elasticsearch]
告警体系设计
可观测性的最终目的是快速发现和定位问题。告警设计要遵循以下原则:
- 对症状告警,不对原因告警:告警高错误率而不是CPU高,前者是用户可以直接感知的
- 分级处理:P0(5分钟响应)-P1(30分钟响应)-P2(工作时间处理)
- 消除噪声:如果一条告警从未触发过行动,就该删除
# Prometheus告警规则示例
groups:
- name: service-alerts
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
> 0.01
for: 2m
labels:
severity: P0
annotations:
summary: "服务 {{ $labels.service }} 错误率超过1%"
runbook: "https://wiki/runbook/high-error-rate"
- alert: HighLatencyP99
expr: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket[5m]))
by (le, service)
) > 1.0
for: 5m
labels:
severity: P1
annotations:
summary: "服务 {{ $labels.service }} P99延迟超过1秒"
常见踩坑与最佳实践
- 采样策略:全量采集在流量大时成本极高,推荐尾部采样(Tail-based Sampling)——只保留错误和慢请求的完整链路
- 标签***:高基数标签(如user_id)会使Prometheus存储暴涨,指标标签应只保留低基数值
- 上下文传播:跨服务调用时需确保Trace Context通过HTTP header(gRPC通过metadata)传播
- 成本控制:日志是最花钱的部分,设置合理的日志级别,生产环境不要DEBUG全开
总结
可观测性不是简单地把三个系统(日志、监控、追踪)堆在一起,而是通过统一的数据模型和关联方式,让运维和开发人员能够在故障发生时快速定位、在故障发生前提前感知。OpenTelemetry作为开放标准,大大降低了建设可观测性体系的门槛和成本。建议从追踪入手,逐步补齐日志和指标,最终实现三者的联动分析。