
思否首发 | 作者:某互联网公司 SRE 团队负责人
我们去年将核心业务迁移至 Kubernetes(腾讯云 TKE),微服务数量从 20 个膨胀到 80+。随之而来的是故障定位从“看日志”变成了“大海捞针”。可观测性不是锦上添花,而是云原生时代的生存刚需。
本文将分享我们基于 Prometheus + Grafana + Loki + Tempo 构建统一可观测性平台的完整历程,包括技术选型、部署配置、数据模型设计、以及三个典型故障的排查实录。全部代码均已脱敏,但核心逻辑可直接复用。
支柱 | 技术栈 | 选型理由 |
|---|---|---|
指标(Metrics) | Prometheus + Thanos | 原生支持 K8s 服务发现,Thanos 提供长期存储和全局查询 |
日志(Logging) | Loki + Promtail | 与 Prometheus 同生态,标签索引代替全文索引,存储成本低 30% |
链路追踪(Tracing) | Tempo + Grafana | 无需外部依赖(如 Elasticsearch),对象存储即可,与 Grafana 深度集成 |
可视化 | Grafana(统一面板) | 三支柱数据源一体化,告警规则统一管理 |
采集器 | OpenTelemetry Collector | 统一 Agent,支持 Trace/Metrics/Logs 的 Pipeline 处理 |
注:若您的团队已有 ELK 或 Jaeger 经验,也可平滑迁移,但 Loki+Tempo 的组合在成本上更具优势。
业务Pod (注入OTel Agent)
↓ (gRPC)
OpenTelemetry Collector (DaemonSet)
├── Metrics → Prometheus (通过Remote Write)
├── Logs → Loki (通过Push API)
└── Traces → Tempo (通过gRPC)
↓
Grafana (统一查询)
↓
AlertManager → 钉钉/企业微信我们使用 Prometheus Operator 部署,开启 remoteWrite 到 Thanos Receiver:
# prometheus-operator 配置片段
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml: |
remote_write:
- url: http://thanos-receiver:19291/api/v1/receive
queue_config:
capacity: 5000
max_shards: 20
write_relabel_configs:
- source_labels: [__name__]
regex: 'container_.*|kube_.*|apiserver_.*'
action: keepThanos 使用对象存储(腾讯云 COS)作为长期存储,保留 2 年数据,每月成本仅数百元。
Loki 的核心思想是使用标签而非全文索引。我们自定义 Promtail 的 pipeline_stages 提取业务字段:
# promtail-config.yaml
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs: ...
pipeline_stages:
- cri: {} # 解析容器日志格式
- regex:
expression: '^(?P<timestamp>\d{4}-\d{2}-\d{2}T.*?)\s+(?P<level>\w+)\s+(?P<trace_id>[a-f0-9]{32})\s+(?P<message>.*)$'
- labels:
level:
trace_id:
namespace: kubernetes_namespace
pod: kubernetes_pod_name
- drop:
source: level
expression: 'debug' # 丢弃 debug 日志以减少存储关键经验:标签基数不能太高(如 user_id 会导致高基数爆炸),我们只保留 namespace、pod、level 等低基数标签,业务查询用 trace_id 关联。
我们使用 OpenTelemetry Collector 自动注入 Trace,并配置采样策略:
# otel-collector-config.yaml
processors:
probabilistic_sampler:
sampling_percentage: 10 # 10% 采样,减少数据量
tail_sampling:
policies:
- name: errors-policy
type: status_code
status_code: {status_codes: [ERROR]} # 错误请求全量采集
- name: slow-policy
type: latency
latency: {threshold_ms: 500} # 慢请求全量采集
exporters:
otlp:
endpoint: tempo:4317
tls: { insecure: true }这样既能控制成本,又能抓住关键异常。
现象:Grafana 面板显示 container_memory_working_set_bytes 持续上升,每 2 小时重启一次。
排查过程:
kube_pod_container_status_restarts_total 指标,确认重启频繁。{pod="payment-service-xxx"} |= "OutOfMemoryError" 找到错误堆栈。trace_id 关联到 Tempo,查看该请求的调用链,发现调用了一个大文件处理接口,未释放资源。关键点:Grafana 的 Explore 功能打通三支柱,从指标→日志→链路无缝跳转,大大缩短了定位时间(从 2 小时缩短到 15 分钟)。
现象:客服反馈偶发超时,但业务接口响应时间 P99 正常,无法复现。
排查过程:
node_network_receive_packets_dropped_total 指标,发现某节点在特定时间点有丢包。/var/log/messages),发现网卡 rx_csum_errors 增加。经验:可观测性要覆盖基础设施层,不能只看应用。
现象:订单查询接口在晚高峰(20:00-21:00)响应时间从 50ms 飙升到 2s。
排查过程:
mysql_slow_queries_total 确认慢查询数量激增。实践:我们为业务日志增加了 trace_id 和 span_id 字段,通过 OTel 的 Context 传递,确保日志和链路可关联。
--storage.tsdb.wal-compressionchunk_target_size 提高压缩比retention_period 为 7 天,热数据保存 3 天(Loki 支持多阶段保留)debug 级别日志进行 drop 或 sample(如仅保留 1%)max_traces_per_second 限制 Tempo 写入速率probabilistic_sampler 结合 tail_sampling 实现动态策略我们基于 Prometheus AlertManager 构建分级告警:
级别 | 条件 | 通知方式 | 接收人 |
|---|---|---|---|
P0(紧急) | 服务不可用(错误率 > 5% 持续 1min) | 电话 + 钉钉 | 值班 SRE + 业务负责人 |
P1(严重) | 错误率 > 1% 持续 5min 或 P99 > 1s | 钉钉 | 业务团队 |
P2(警告) | 内存使用 > 80% 或 磁盘满 | 钉钉 | 开发负责人 |
告警规则示例(PromQL):
groups:
- name: service_alerts
rules:
- alert: HighErrorRate
expr: sum(rate(http_requests_total{status=~"5.."}[1m])) / sum(rate(http_requests_total[1m])) > 0.05
for: 1m
labels:
severity: P0
annotations:
summary: "{{ $labels.service }} 错误率超过5%"同时结合 Grafana 的 Alerting 能力,支持在面板内直接配置告警,降低学习门槛。
Collector 如果内存不足会被 OOMKilled,需设置 memory_limiter 处理器:
processors:
memory_limiter:
check_interval: 5s
limit_mib: 512
spike_limit_mib: 128当标签数量多且范围大时,Loki 查询会超时。解决:
filter 表达式(如 |= "error")在标签筛选后再进行全文过滤querier 副本数我们使用 Thanos Querier 聚合多个 Prometheus 实例(按环境或地域),实现全局视图。但要注意 --query.replica-label 去重。
为 Grafana 启用 OAuth(LDAP),不同团队仅能查看自己的 Namespace 数据,使用 grafana 的 DataSource 的 allowedCookies 进行隔离。
指标 | 建设前 | 建设后 |
|---|---|---|
平均故障发现时间(MTTD) | 15min | 2min |
平均故障恢复时间(MTTR) | 40min | 12min |
日志存储成本(月度) | ¥8000 | ¥3200 |
跨团队协作效率 | 需拉群逐层询问 | 直接分享 Grafana 链接 |
核心心得:
后续我们将引入 eBPF 采集更细粒度的内核指标,并探索 智能根因分析(基于 AI 关联变更事件和异常指标)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。