尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从监控到可观测性:三大支柱实战指南与LGTM栈部署详解

从监控到可观测性:三大支柱实战指南与LGTM栈部署详解 这次我们来看一个在运维和开发领域越来越重要的概念可观测性。如果你负责过线上系统肯定对监控不陌生比如用 Zabbix 看服务器负载用 Prometheus 收集指标用 Grafana 做仪表盘。但你是否遇到过这种情况监控一切正常但用户就是报错或者系统性能莫名其妙下降你却找不到根因这就是传统监控的盲区也是可观测性要解决的问题。简单来说可观测性是一套更高级的系统“体检”和“诊断”能力。它不再满足于告诉你“系统发烧了”监控告警而是要能回答“为什么发烧是哪里发炎该怎么治”。它的核心是让你能从系统外部输出的数据指标、日志、链路主动、高效地洞察系统内部的状态和问题尤其是在复杂的微服务、云原生环境下。本文会带你彻底搞懂可观测性与监控的区别并通过一个实际的场景演示如何从仅有监控的被动响应升级到具备可观测性的主动洞察。我们会重点关注可观测性的三大支柱指标、日志、链路如何落地需要哪些工具栈以及如何将它们整合起来真正解决“监控正常但业务异常”的经典难题。无论你是运维工程师、SRE 还是后端开发者这篇文章都能帮你构建更强大的系统保障体系。1. 核心能力速览监控 vs. 可观测性在深入细节前我们先通过一个表格快速对比两者的核心差异这能帮你快速判断当前团队处于哪个阶段以及是否需要向可观测性演进。维度传统监控 (Monitoring)可观测性 (Observability)核心目标已知故障的检测与告警未知问题的探索与根因定位数据视角基于预定义的指标已知的未知基于任意维度的数据关联与查询未知的未知工作模式被动、反应式告警驱动主动、探索式问题驱动典型问题CPU使用率80%服务宕机为什么订单提交变慢为什么这个用户的请求失败了数据支柱以指标(Metrics)为主指标(Metrics)、日志(Logs)、链路(Traces)三位一体工具举例Zabbix, Nagios, Prometheus(基础)Prometheus Loki Tempo, Elastic Stack, SkyWalking, Jaeger适合场景基础设施、服务状态等确定性监控微服务、云原生等复杂、动态、交互频繁的系统从上表可以看出监控是可观测性的子集和基础。监控告诉你“系统是否健康”而可观测性告诉你“系统为什么生病病灶在哪里”。在云原生时代服务调用链错综复杂一个用户请求可能穿越几十个服务仅靠监控指标就像只检查体温而可观测性则提供了X光、CT和血液化验的全套诊断能力。2. 适用场景与使用边界2.1 谁需要可观测性微服务架构团队服务间依赖复杂故障传播路径不透明急需链路追踪来理清关系。云原生/Kubernetes 使用者动态伸缩、服务发现等特性使得传统基于固定IP的监控失效需要更动态的观测手段。追求高可用与快速故障恢复的SRE团队需要将平均故障恢复时间MTTR从小时级降到分钟级深度诊断能力是关键。面对“黑盒”第三方服务或API的开发者需要了解自身调用第三方服务时的性能瓶颈和错误详情。2.2 它能解决什么问题根因定位快速定位导致性能下降或错误的具体服务、代码行甚至数据库查询。用户体验分析追踪单个用户请求的全链路复现用户遇到的问题。性能优化通过链路追踪和指标关联找到系统的性能瓶颈如慢SQL、不合理的远程调用。降低告警噪音通过关联分析将多个相关告警合并成一个根本原因事件避免“告警风暴”。2.3 使用边界与注意事项不是银弹可观测性不能替代良好的系统架构、代码质量和容量规划。它是在问题发生后提供洞察的工具。数据成本全量采集链路和日志会产生巨大的数据量和存储成本需要合理的采样策略和存储方案。隐私与安全链路和日志中可能包含敏感信息如用户ID、请求参数必须实施脱敏和访问控制。复杂度引入完整的可观测性栈如OpenTelemetry会带来一定的开发和运维复杂度需要权衡收益。3. 环境准备与前置条件为了演示如何从监控升级到可观测性我们将搭建一个简单的微服务 demo 环境并逐步引入可观测性工具。以下是实验环境建议操作系统Linux (Ubuntu 20.04/22.04 或 CentOS 7/8) macOS 或 Windows WSL2 也可用于开发测试。容器环境Docker 与 Docker Compose。这是快速部署观测工具栈最方便的方式。资源要求建议至少 4核 CPU 8GB 内存 20GB 磁盘空间。运行完整的工具栈Prometheus, Grafana, Loki, Tempo会占用一定资源。网络需要从宿主机访问容器内服务的端口如3000, 9090, 3100等。示例应用一个包含前端Frontend、后端服务Service A和数据库的模拟应用。我们将使用 Go 或 Python 编写的简单 HTTP 服务。4. 从监控到可观测性部署与配置实战我们以最流行的开源可观测性栈——Grafana Labs 的“LGTM”栈Loki for logs, Grafana for visualization, Tempo for traces, M3DB/Prometheus for metrics为例演示如何搭建环境。4.1 第一步基础监控部署仅有指标首先我们部署最基础的监控部分Prometheus指标收集和 Grafana可视化。创建一个docker-compose-monitor.yml文件version: 3.8 services: prometheus: image: prom/prometheus:latest container_name: prometheus volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prom_data:/prometheus command: - --config.file/etc/prometheus/prometheus.yml - --storage.tsdb.path/prometheus - --web.console.libraries/etc/prometheus/console_libraries - --web.console.templates/etc/prometheus/console_templates - --storage.tsdb.retention.time200h - --web.enable-lifecycle ports: - 9090:9090 networks: - observability-net grafana: image: grafana/grafana:latest container_name: grafana ports: - 3000:3000 volumes: - grafana_data:/var/lib/grafana - ./grafana/provisioning:/etc/grafana/provisioning environment: - GF_SECURITY_ADMIN_PASSWORDadmin - GF_INSTALL_PLUGINSgrafana-piechart-panel networks: - observability-net depends_on: - prometheus volumes: prom_data: grafana_data: networks: observability-net: driver: bridge配置 Prometheus 的基础抓取目标 (prometheus.yml)global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: prometheus static_configs: - targets: [localhost:9090] - job_name: demo-app static_configs: - targets: [host.docker.internal:8080] # 假设你的应用运行在宿主机的8080端口启动服务docker-compose -f docker-compose-monitor.yml up -d访问http://localhost:3000登录 Grafana (admin/admin)添加 Prometheus 数据源就能看到基础的 CPU、内存、请求率等指标仪表盘。此时你只有监控。如果应用接口返回错误你只能看到一个错误计数上升但不知道是哪个用户、什么请求参数、在哪个服务环节出的错。4.2 第二步引入可观测性三大支柱接下来我们引入日志Loki和链路Tempo升级到完整的可观测性栈。创建完整的docker-compose-observability.ymlversion: 3.8 services: # 原有监控组件 prometheus: ... # 同上 grafana: ... # 同上但需要安装Loki和Tempo的数据源插件 # 可观测性新组件日志 loki: image: grafana/loki:latest container_name: loki ports: - 3100:3100 command: -config.file/etc/loki/local-config.yaml networks: - observability-net # 可观测性新组件链路 tempo: image: grafana/tempo:latest container_name: tempo command: [ -config.file/etc/tempo.yaml ] volumes: - ./tempo.yaml:/etc/tempo.yaml - ./tempo-data:/tmp/tempo ports: - 3200:3200 # Tempo 查询端口 - 4317:4317 # OTLP gRPC 接收端口 - 4318:4318 # OTLP HTTP 接收端口 networks: - observability-net # 演示应用需要被观测 demo-frontend: build: ./demo-app # 你的应用Dockerfile路径 container_name: demo-frontend ports: - 8080:8080 environment: - JAEGER_AGENT_HOSTtempo - JAEGER_AGENT_PORT6831 - OTEL_EXPORTER_OTLP_ENDPOINThttp://tempo:4318 networks: - observability-net depends_on: - tempo - loki volumes: prom_data: grafana_data: tempo-data: networks: observability-net: driver: bridgeTempo 基础配置 (tempo.yaml)server: http_listen_port: 3200 distributor: receivers: otlp: protocols: grpc: http: ingester: trace_idle_period: 10s max_block_bytes: 1_000_000 max_block_duration: 5m compactor: compaction: compaction_window: 1h max_block_bytes: 100_000_000 block_retention: 1h storage: trace: backend: local local: path: /tmp/tempo/blocks4.3 第三步改造应用以产生可观测性数据要让工具栈发挥作用应用必须能发出指标、日志和链路数据。这通常通过埋点 SDK 实现。以 Go 语言应用为例使用 OpenTelemetry SDK 进行埋点添加依赖(go.mod)go get go.opentelemetry.io/otel go get go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc go get go.opentelemetry.io/otel/sdk/trace go get go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp初始化 Trace Provider(main.go 初始化部分)import ( context go.opentelemetry.io/otel go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc go.opentelemetry.io/otel/sdk/resource sdktrace go.opentelemetry.io/otel/sdk/trace semconv go.opentelemetry.io/otel/semconv/v1.17.0 ) func initTracer() func(context.Context) error { ctx : context.Background() // 指向我们部署的 Tempo 服务 exporter, err : otlptracegrpc.New(ctx, otlptracegrpc.WithEndpoint(tempo:4317), otlptracegrpc.WithInsecure(), ) if err ! nil { log.Fatal(err) } tp : sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceName(demo-frontend), semconv.ServiceVersion(v1.0.0), )), ) otel.SetTracerProvider(tp) return tp.Shutdown }在 HTTP 处理器中创建 Spanfunc helloHandler(w http.ResponseWriter, r *http.Request) { tracer : otel.Tracer(demo-handler) ctx, span : tracer.Start(r.Context(), helloHandler) defer span.End() // 你的业务逻辑 userId : r.URL.Query().Get(user_id) span.SetAttributes(attribute.String(user.id, userId)) // 记录业务属性 // 模拟调用下游服务 if err : callServiceA(ctx, userId); err ! nil { span.RecordError(err) // 记录错误 http.Error(w, service call failed, http.StatusInternalServerError) return } fmt.Fprintf(w, Hello, %s!, userId) } // 使用 otelhttp 自动包装 HTTP 客户端 func callServiceA(ctx context.Context, userId string) error { client : http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)} req, _ : http.NewRequestWithContext(ctx, GET, http://service-a:8081/api?useruserId, nil) resp, err : client.Do(req) // ... 处理响应 return err }结构化日志使用如logrus、zap等支持 JSON 输出的日志库并在日志中输出 TraceID。log.WithFields(log.Fields{ trace_id: trace.SpanContextFromContext(ctx).TraceID().String(), user_id: userId, service: frontend, }).Info(Processing user request)应用配置日志输出到标准输出由 Docker 收集再通过loki-docker-driver或promtail发送到 Loki。完成以上改造后重启完整的可观测性栈和你的应用。5. 功能测试与效果验证从“看到现象”到“找到根因”现在我们模拟一个线上问题对比仅有监控和具备可观测性时的排查效率。5.1 场景设定用户反馈“我的订单页面加载非常慢有时还报错。”5.2 仅有监控PrometheusGrafana的排查查看仪表盘你发现http_request_duration_seconds指标 p99 延迟升高http_requests_total{status500}错误计数在增长。问题你知道系统变慢且报错增多但是哪个接口慢/order还是/cart是哪个用户遇到的他的请求参数是什么慢在哪一步是网络延迟、数据库查询慢还是调用的某个下游服务超时错误的具体原因是什么是数据库连接失败还是参数校验不通过结论监控给了你警报发烧了但没给你诊断报告。你需要登录服务器查日志手动拼接不同服务的日志时间线过程繁琐且低效。5.3 具备可观测性LGTM全栈的排查在 Grafana Explore 界面切换到 Loki 数据源。查询日志输入查询{servicedemo-frontend} | error快速找到错误日志。在日志详情中你看到了关键的trace_idabc123。关联追踪复制这个trace_id切换到 Tempo 数据源直接粘贴查询。可视化链路Grafana 立刻展示出这次失败请求的完整调用链路图。你清晰地看到请求从demo-frontend的/order接口进入。它调用了service-a的/api接口。service-a又执行了一次数据库查询。链路显示数据库查询耗时高达 2 秒并且最终失败。下钻分析点击链路中数据库查询的 Span查看其详细属性。你发现执行的 SQL 语句是一个没有索引的复杂查询并且user_id是一个特定的值。关联指标在同一个 Grafana 面板中你还可以关联查看这个数据库实例在当时的 QPS、连接数、慢查询等 Prometheus 指标确认是资源瓶颈还是查询问题。结论在几分钟内你不仅确认了问题慢查询还精准定位到了有问题的代码具体的 SQL 语句、影响的用户特定的 user_id和发生的时间点。接下来优化这条 SQL 或添加索引即可。6. 接口 API 与批量任务可观测性数据的消费可观测性数据不仅用于人工排查也可以通过 API 集成到自动化运维流程中。6.1 查询 API 示例Prometheus Query API获取特定时间范围的指标。curl -G http://localhost:9090/api/v1/query \ --data-urlencode queryrate(http_requests_total{status500}[5m]) \ --data-urlencode time$(date %s)Loki Query API检索包含特定关键词的日志流。curl -G http://localhost:3100/loki/api/v1/query_range \ --data-urlencode query{servicedemo-frontend} | timeout \ --data-urlencode limit10 \ --data-urlencode start$(date -d 1 hour ago %s)000000000Tempo Query API通过 TraceID 获取链路详情。curl -G http://localhost:3200/api/traces/abc1236.2 批量任务与自动化你可以编写脚本定期通过上述 API 拉取数据实现自动化报表每日/每周生成服务健康度、错误趋势、慢接口 TopN 报告。智能告警结合多个数据源。例如当错误日志中频繁出现“连接池耗尽”且同时数据库连接数指标告警时触发更高级别的告警。混沌工程实验分析在注入故障后自动分析全链路的故障影响范围和恢复情况。容量规划基于历史指标和链路数据如调用频率、依赖关系预测服务扩容需求。7. 资源占用与性能观察部署完整的可观测性栈会消耗额外资源需要合理规划。存储成本指标Prometheus相对较小取决于采集频率和指标数量。可通过降采样和长期存储到对象存储如 Thanos, Cortex来管理。日志Loki占用最大。务必启用日志采样和保留策略。Loki 使用索引块存储对重复内容压缩率高比传统 ELK 节省成本。链路Tempo取决于请求量和采样率。生产环境通常采用动态采样如根错误采样、低流量全采样。计算与内存Prometheus、Loki、Tempo 每个服务在中等负载下可能需要 500MB - 2GB 内存。采集代理如 OpenTelemetry Collector, Promtail运行在每个节点上会增加少量 CPU 和内存开销。网络流量应用将观测数据发送到收集器会产生内网流量。确保网络带宽充足。性能影响在应用代码中埋点特别是全量采集链路会带来性能损耗通常5%。应在测试环境评估影响并对高频、内部接口考虑采用采样策略。启动后观察使用docker stats或宿主机的监控工具观察各容器的 CPU、内存占用。访问 Grafana 内置的仪表盘如 Prometheus 的Targets和Status页面 Loki 的Stats页面来了解数据抓取和摄入的健康状态。8. 常见问题与排查方法问题现象可能原因排查方式解决方案Grafana 无法连接 Prometheus/Loki/Tempo 数据源1. 网络不通或端口未暴露2. 容器服务未启动3. 数据源 URL 配置错误1.docker ps检查容器状态2.docker logs container_name查看服务日志3. 在 Grafana 容器内curl目标服务地址1. 检查docker-compose网络配置和端口映射2. 确保数据源 URL 使用 Docker 服务名如http://prometheus:9090应用日志没有收集到 Loki1. Promtail 或 Docker Driver 未配置2. 日志标签 (labels) 不匹配查询条件3. Loki 服务异常1. 检查 Promtail 配置文件的scrape_configs2. 在 Loki 的Explore界面使用{}空查询看是否有任何日志流3. 查看 Loki 日志1. 确保 Promtail 能访问应用日志文件或 Docker 套接字2. 在应用日志输出中确保包含service等关键标签链路数据没有发送到 Tempo1. 应用 SDK 配置的 OTLP 端点错误2. Tempo 接收器配置错误或未启动3. 采样率设置为01. 检查应用环境变量如OTEL_EXPORTER_OTLP_ENDPOINT2. 检查 Tempo 日志确认 OTLP 接收器已启动3. 检查 SDK 中的采样配置1. 确保端点地址和端口正确2. 在开发环境可先设置为AlwaysOn采样器查询链路时 TraceID 找不到1. 链路数据尚未被索引和存储有延迟2. TraceID 复制错误或来自不同环境3. 查询时间范围不对1. 等待几秒到几分钟后重试2. 确认 TraceID 格式正确并来自当前 Tempo 实例3. 在 Tempo 查询界面扩大时间范围1. 了解 Tempo 的摄入、索引延迟2. 确保从产生该链路的同一环境查询高负载下观测系统自身成为瓶颈1. 存储或计算资源不足2. 采集数据量过大无采样3. 查询过于复杂1. 监控观测系统自身的资源指标2. 分析数据摄入速率和查询负载1. 扩容资源2.实施采样策略尤其是链路3. 优化查询建立常用查询的预计算仪表盘9. 最佳实践与使用建议从“为什么”开始而不是“做什么”不要为了上可观测性而上。先明确你想解决的具体问题如定位慢查询、理解服务依赖再设计需要采集哪些数据。标准化与一致性为所有服务定义统一的日志格式、指标命名规范如 Prometheus 的命名约定和链路属性如service.name,http.method。这是后续关联分析的基础。采用 OpenTelemetry 标准作为 CNCF 项目OpenTelemetry 提供了与厂商无关的 API、SDK 和收集器避免了未来被某个特定工具锁定的风险。实施智能采样全量采集所有链路数据成本极高。根据业务重要性、错误率、延迟等因素实施动态采样如所有错误链路、慢链路、或随机 1% 的正常链路。关注“黄金信号”Google SRE 提出的四大黄金信号——流量、错误、延迟、饱和度是监控和可观测性的核心。确保你的仪表盘能清晰展示这些信号。建立“服务地图”和“依赖关系图”利用链路数据自动生成服务拓扑图这是理解复杂系统、进行影响面分析的神器。安全与合规日志脱敏在采集侧或存储前对密码、令牌、身份证号等敏感信息进行脱敏。访问控制Grafana、日志和链路数据应设置严格的 RBAC 权限避免敏感信息泄露。数据保留策略根据合规要求设定数据的保留周期并自动清理过期数据。10. 总结与下一步可观测性不是对监控的替代而是一次全面的升级。它从被动告警走向主动探索从孤立指标走向数据关联最终目标是实现系统的“白盒化”让任何异常都能被快速、准确地理解和解决。对于刚开始实践的团队建议按以下路径推进巩固监控基础确保核心业务和基础设施的指标监控是健全的Prometheus。引入集中式日志解决日志散落各处、查询困难的问题Loki/ELK。试点链路追踪选择一两个核心业务链路接入 OpenTelemetry 并发送到 Tempo/Jaeger体验其威力。实现数据关联在 Grafana 中将指标、日志、链路的仪表盘关联起来并训练团队使用Explore功能进行问题排查。推动开发规范将可观测性埋点如添加 TraceID 到日志、记录关键业务属性纳入开发标准和代码审查。这个演进过程可能会遇到阻力比如开发人员觉得埋点麻烦或者运维担心存储成本。最好的破局方式是用一个具体的、棘手的生产问题来展示可观测性方案是如何在几分钟内解决之前需要数小时甚至跨部门协作才能搞定的难题。一次成功的“降维打击”比任何技术布道都更有说服力。
返回列表