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

资讯详情

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

Envoy可观测性完整落地:日志、指标与链路追踪实战指南

Envoy可观测性完整落地:日志、指标与链路追踪实战指南 Envoy可观测性这个题目我前前后后摸了快一年才敢说真正落地过一遍。日志、指标、链路追踪看起来是三件事实际是一件事让系统出问题时你能在十分钟内定位到是哪个上游节点慢、哪个请求失败、哪条链路断掉。这篇文章不是概念科普是我在真实服务网格环境里踩过的坑、调过的参、排过的障全公开出来希望对正在折腾Envoy的人有帮助。适合人群很明确平台工程师、SRE、微服务架构师还有刚接手服务网格团队的同学。你至少接触过Envoy或类似代理否则建议先过一遍官方文档基础再来读。文中的配置片段和命令我尽量按生产环境的标准来写但有意识地隐去了真实域名和基础设施细节你拿到手可以直接改改参数试。另外标题里写的“完整落地”指的是你从零把日志、指标、追踪三样全部跑通而不是只装个Prometheus就完事。我会把我踩过的坑、调整过的参数、排障的思路都讲一遍保证不是从文档里抄来的。1. 可观测性落地的整体设计思路1.1 Envoy在系统中的地位与可观测性的价值Envoy是数据平面。你的业务流量首先经过它然后才到业务容器。这意味着它天然是整个分布式链路中最靠近请求的地方。所有的入站出站请求、连接、协议解析、负载均衡决策都会在这里产生数据。如果你不在这一层做可观测性那么即使业务代码里加了再多的log和metric也无法覆盖那些发生在代理层的问题比如上游线程阻塞、连接池耗尽、路由规则错误、异常重试导致的雪崩等。我遇到过一种典型情况业务服务本身健康检查正常但流量就是大量报错最后定位到是Envoy的cluster节点配置里健康检查频率过高导致后端被频繁摘除。这种情况下业务侧日志什么都没有只有Envoy的stats里面连接数在抖动当你看到upstream_cx_active这个指标飙升时才反应过来。可观测性的价值在于能够快速缩小问题范围。日志告诉你发生了什么指标告诉你什么趋势追踪告诉你哪条链路上哪一环节延迟高。三者配合起来才能形成一个完整的因果链。比如你看到全局延迟上涨首先看指标图确认上涨时间点然后看追踪找到是哪个服务之间的调用变慢最后看日志确认具体报错内容。这一套下来排障效率能提升一个量级。1.2 日志、指标、链路追踪三者如何分工和协同日志是本地的持久化记录事件的完整上下文。指标是聚合后的数值反映系统的健康和趋势。追踪是请求的原子轨迹记录单个请求在整张链路中的完整路径。它们关注的时间维度不同日志是离散事件指标是连续采样追踪是每个请求的span。实际落地时我用日志来排查业务错误和配置问题用指标来做集群级监控和告警用追踪来做分布式性能分析。三者不是替代关系而是互补关系。正确做法是在Envoy配置里同时开启访问日志、指标暴露端口和链路追踪provider通过请求ID把三者的数据关联起来。比如在日志里带上trace_id和request_id在追踪的span里带上上游集群和host信息在指标上通过标签区分集群、路由、虚拟主机。这样三套数据才能串起来用。如果你的配置里只有日志或只有指标你依然能日常监控但遇到跨服务问题就会抓瞎。我建议团队里先把“统一请求ID”这个概念定下来。Envoy支持通过%REQ(X-REQUEST-ID)%取header里的请求ID同时你可以让服务端透传这个header这样浏览器→Envoy→业务→上游都能拿到同一个ID。然后再把这个ID写入访问日志和trace的标签排障时按ID一搜整个链路全出来了。2. 日志采集与管理的完整实践2.1 访问日志的字段设计与格式化配置访问日志是Envoy最基础的数据来源。但默认的格式太简单只有method、path、protocol、code之类完全不够用。我强烈建议你自定义log_format把要的字段全写上免得排障时缺字段抓瞎。我在生产环境中用的访问日志格式大概长这样log_format: detail: %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %UPSTREAM_CLUSTER% %UPSTREAM_HOST% %REQ(X-FORWARDED-FOR)% %REQ(USER-AGENT)%拆开来看%REQ(:METHOD)%请求方法用于区分读写操作。%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%完整的路径包括query string。注意这里用?:的写法是Envoy的格式fallback建议记住。%RESPONSE_CODE%响应状态码最基础的值用于快速定位错误。%RESPONSE_FLAGS%这个是关键Envoy在处理失败时会设置一个flag比如UH表示上游无健康节点UF表示连接失败UO表示熔断打开。看到这个flag基本就能判定是代理层问题而不是业务问题。我把RESPONSE_FLAGS看成是排障的第一步。%DURATION%整个请求处理时长单位毫秒用于延迟分析。%UPSTREAM_CLUSTER%和%UPSTREAM_HOST%真正转发给哪个后端集群和具体节点用于定位具体的后端实例。字段多了日志会变大但值得。我把这行格式配到bootstrap的access_log里然后指定输出到文件。你可以把它输出到标准输出或文件两种方式各有取舍输出到stdout是容器时代的主流做法直接在Pod的日志里看输出到文件则是为了配合日志采集agent做筛选和归档。关于字段命令Envoy还有%REQ(X-ANY-HEADER)%取任意请求头%RESP(X-ANY-HEADER)%取响应头%START_TIME%记录请求开始时间。我建议把%START_TIME%也加进去方便和trace的时间戳做对齐。2.2 日志采集、存储与查询方案的选型日志一旦有了就得考虑怎么收集。我见过有团队直接在Envoy的文件日志上写脚本抓但生产环境上千个实例脚本根本管不过来。常规路线是Filebeat或Fluentd从文件读然后发到Elasticsearch或Loki再用Kibana或Grafana查。我在团队里选的是Filebeat加Elasticsearch主要是团队已有的技术栈兼容。Filebeat的配置很简单指定日志路径解析multiline然后写到ES。但有几个坑值得提Filebeat默认会把收集状态存在内存中如果Filebeat自身重启可能丢日志。建议把数据持久化到data/registry目录。Envoy的访问日志默认是每条一行但如果log_format里的字段值里带了换行符或特殊字符Filebeat会切错。我用的是ndjson格式就是每行一个JSON对象这样解析起来最稳。输出到ES时建议按天建索引比如envoy-access-log-2025.05.17配合ILM策略自动过期别让日志无限制增长。日志存储规划上我的经验是访问日志保留14天指标数据保留90天追踪数据保留7天。因为日志消耗的磁盘最多追踪的原始span体积也不小及时清理很重要。如果你用的是Loki可以直接用retention参数配置保留周期。无论用哪套存储都要提前评估单条日志的平均大小和每秒日志条数才能规划磁盘容量。我粗略估算过一条详细访问日志大约在500字节到1KB在每秒几百请求的规模下一天日志量就是几十GB。别不当回事。2.3 日志排查中的关键技巧与易坑点日志落地之后实际排查时有很多坑。我把最常见的列一下日志时间不对齐Envoy所在宿主机和业务容器的时间如果同步不准日志时间会和trace时间、指标时间错开。建议在所有集群节点上统一部署NTP同步最好在bootstrap配置里把时间格式也统一成UTC或CST别混着写。日志丢行Filebeat采集时如果文件被rotate了可能会漏掉最后几行。我建议用clean_removed: true配合close_removed: true来控制filebeat的read行为。日志权限问题Envoy进程如果以非root用户运行可能没法写宿主机的日志文件或者权限太小导致k8s日志收集不了。这个我踩过两次建议指定access_log路径后手动chown对应的挂载目录。日志与trace的request_id对不上当你用%REQ(X-REQUEST-ID)%在日志里记录request ID但trace的样例会带上上游生成的另一个ID时两边就对不上了。解决办法是让Envoy在转发请求时同时透传同一个headers或者在日志格式里同时记录两个ID。日志面板上搜索慢对于高频查询建议给message字段设置keyword类型否则ES会把整行当成text分词搜起来很慢。这些坑都不是文档里的知识是排过障才记得住的我全写下来供你参考。3. 指标监控与阈值告警的落地3.1 Envoy指标体系与Prometheus集成指标是比日志高一级的信息。Envoy自带一套完整的stats架构默认暴露在/stats端点格式是文本Prometheus可以直接抓取。但你会发现/stats默认输出的是所有线程的统计值字段名长且乱比如cluster.upstream_rq_timeout这种。建议用虚拟集群或enable--stats-flush-interval还可以加--stats-tags。生产环境我建议使用虚拟集群来区分服务维度。我实际用Prometheus的方案是这样子的在Envoy的bootstrap配置里打开stats_config设置stats_tags来自动把cluster、listener、virtualhost这些维度变成Prometheus标签然后设置stats_flush_interval: 1s让指标数据尽快输出。然后通过prometheus暴露到9090端口。Prometheus的scrape配置里目标地址写Envoy pod的IP加上9090/metrics。抓到的指标里我最关心的是这几种cluster.upstream_cx_active活跃连接数如果这个持续升高可能是后端响应变慢或连接池设置偏小。cluster.upstream_rq_time请求平均延迟配合histogram看分布。cluster.upstream_rq_retry重试次数重试率过高说明上游问题反复出现。cluster.membership_healthy健康节点数如果这个值小于配置的预期说明有节点被剔除。listener.downstream_cx_total新建连接总数用于判断流量起伏。rate(envoy_http_downstream_rq_time_bucket[5m])这个是我自己封装的延迟分位数计算方式PromQL里用histogram_quantile(0.99)得到p99延迟。3.2 关键业务指标的选择与阈值标定选指标是写Prometheus告警时最纠结的部分。不是所有指标都要设告警告警项太多会噪音太多。我的经验是围绕三个维度选延迟、错误、饱和。延迟使用histogram_quantile(0.99, sum(rate(envoy_http_downstream_rq_time_bucket[5m])) by (le))作为p99延迟。当p99超过你设的SLO比如500毫秒就触发告警。错误使用rate(envoy_http_downstream_rq_xx[5m])分别统计5xx和4xx。5xx代表服务端错误4xx可能大部分是客户端问题但也要看情况。我的阈值是5xx超过2%就告警。饱和度看cluster.upstream_cx_active和listener.downstream_cx_active。这两个值表示当前连接数如果超过整体配置的80%说明快要到上限了。阈值标定不能拍脑袋。保险做法是先用一两个星期跑监控看历史的基线然后取基线值的1.5~2倍作为阈值。比如某个集群正常情况下p99延迟在200毫秒左右那阈值设到300毫秒就不会太敏感也不会太迟钝。你也可以用Prometheus的for参数比如连续5分钟超过阈值才触发告警避免抖动。3.3 从指标到告警的全链路配置告警不只是一个PrometheusAlert。它要结合Alertmanager做分组、抑制和去重要机制。我在团队里的做法是把Envoy相关的告警都打上envoy标签在Alertmanager中配置路由规则当同一个cluster出现连续告警时只通知一次后面配合repeat_interval控制重复通知频率。Alertmanager里我还会区分severitycritical服务不可用、warning即将超限。critical就触发PagerDuty和电话warning只推企业微信或钉钉群。实操上suppress规则也要配置。比如如果cluster.membership_healthy为0了那么所有上游请求告警都先抑制住因为根因已经确定再告一堆冗余噪音没有意义。这类抑制条件我维护在一个yaml文件里每次上线前会review一遍。4. 链路追踪的接入与调试4.1 基于Zipkin/Jaeger的追踪集成配置链路追踪相较前面两个难度会大一点原因在于需要各业务服务配合注入trace context。Envoy本身支持作为追踪的reporter把span发到zipkin或jaeger。我在生产环境里用Jaeger因为和内部日志平台集成得更顺。配置大致的操作是在bootstrap的tracing字段里指定provider为jaeger并配置sampling为5%。你需要为jaeger自己建一个upstream cluster指向Jaeger collector。然后在每个路由的route_config里设置start_child_span和decorator。这里的关键是透传。Envoy发出的span里会带x-request-id、x-b3-traceid、x-b3-spanid等header传给上游服务后服务端需要用对应的OpenTracing或OpenTelemetry SDK来接收并续写。我发现很多团队卡在“Envoy自己的日志里能看到trace但服务端没有span”这一环原因就是业务没接SDK或者接错了版本。你在接入Jaeger的SDK时记得把B3或w3c传播格式设成和Envoy一致的不然两边对不上。4.2 采样策略的权衡与调优全量采样很耗资源我一般不会全量。建议是对高流量集群用5%~10%的采样率对错误请求强制采样这样既能抓到关键故障又能控制面板压力。Jaeger支持基于权重的采样和基于延迟的采样Envoy侧则通过sampling参数控制。我还保留了一个“按header触发全采样”的机制比如当tracking id以DEBUG开头的请求全部采样方便线上验证新版本。采样率过低会丢trace导致排障时找不到问题链路。采样率过高会带来额外的CPU和内存开销沙盒测试时可以全量线上要克制。追踪数据可以配合%REQ(X-REQUEST-ID)%来定位当你在日志里看到一个慢请求可以用请求ID去Jaeger里搜span这样日志和trace两套数据就对上了。4.3 追踪数据与日志、指标的联动分析联动是三个模块是否真正落地的标志。平时的直观用法是在Jaeger里查看某个span的耗时然后去对应的日志里面看那一分钟的Envoy访问日志再配合Prometheus的指标趋势就能拼出完整时间线。举个例子我在一次排障中指标显示p50和p99延迟同时上升但错误率没有变化Jaeger里的火焰图显示大部分延迟集中在某一个外部调用调用那个服务用的是一个envoy cluster查日志发现这个cluster的upstream host列表只有一个另一个节点因为健康检查失败被摘除了。整体来看是这个外部服务只留了一个健康节点导致流量全压到那一个节点上延迟自然上升。这是日志、指标、trace三方关联定位的最佳示例。如果你只开了一角大概率会绕圈子。5. 全链路排障与性能问题的排查实录5.1 常见问题速查表日志、指标、追踪的三类典型故障我把在实战中遇到的问题整理成速查表方便大家直接对号入座。类别现象很可能的原因解决步骤日志访问日志里没有部分请求采样被无关插件过滤或请求走了异步路径检查filter_factory配置确保日志filter放在最前面日志日志里有大量重复行Filebeat的二次采集或重复挂载检查文件挂载方式避免两个agent读同一路径指标Prometheus里指标为0没有开启/metrics端点或scrape的超时时间太短确认/metrics能访问scrape_timeout设成10s指标p99指标突然异常高阈值标定不清或慢调用过多用histogram_quantile配上le标签确认不是配置错误追踪Jaeger里没有span但日志有trace_id业务没用SDK接入或版本不兼容检查bootstrap的tracing provider和服务的reporter是否一致追踪span断链只有前半段上游服务没有透传trace header检查业务网关能否正确读取和转发B3/w3c header5.2 日志与指标对不上的排查思路我经常看到有人问为什么日志里看到的错误率和Prometheus里的error_rate对不上。这个问题很常见原因通常是两边统计口径不同。比如Envoy的%RESPONSE_CODE%是它自己收到客户端请求后的状态码而Prometheus里如果抓的是envoy_http_downstream_rq_xx那它统计的是Envoy返回给客户端的xx和业务自己生成的code不一定相同。举个例子某上游业务返回400的时候Envoy可能原样转发400但如果你配了错误响应转化Envoy可能会把它变成502发给客户端。这一来日志里的%RESPONSE_CODE%是400指标里的5xx却上升看起来就对不上了。解决思路是统一口径。把日志里记录的%RESPONSE_CODE%和%UPSTREAM_RESPONSE_CODE%都写进去指标用同样两个标签去记录。我的做法是日志格式里加上%UPSTREAM_RESPONSE_CODE%Prometheus查询时按envoy_http_downstream_rq_xx分组再关联upstream_rq_xx来确认到底是谁的错。你只要在配置层保持同一种分类逻辑就不会出现两套数据对不上的问题。5.3 一次完整排障实战的推演我再模拟一次真实排障流程完整走一遍思路帮你把前面提到的工具用起来。当时现象某服务在高峰期接口超时率突然变高用户反馈页面加载变慢。我先打开Prometheus仪表盘看envoy_http_downstream_rq_time的p99发现它在10:15左右从200毫秒涨到1.5秒。再查envoy_cluster_upstream_rq_retry发现重试次数同步上涨说明上游有问题。紧接着去Jaeger里看该时间段的trace发现大量span的耗时集中在某个上游服务的connect阶段说明不是业务执行慢而是连接建立慢。再去Envoy的日志里按%DURATION%排序找出最慢的几条请求看它们的%RESPONSE_FLAGS%发现是UH上游无健康节点。最后结合cluster的membership_healthy指标确认是该服务的后端节点被健康检查摘除了大半。整个过程大概20分钟比之前全靠猜多了不知多少倍。6. 写在最后我的可观测性落地体会踩得坑越多越明白一件事Envoy只是数据平面可观测性真正落地的好坏取决于你对自身流量模型的了解程度。日志、指标、追踪三样没有银弹一定要先有指标看面、用日志看点、用trace穿线。另外无论如何先把统一request_id做起来没有这个ID三个模块都只是各自孤岛。最后建议团队里搭一套简单的“一键检索”页面或者文档把日志查询、指标面板、trace检索的入口和语法说明贴在wiki上团队协作时会省很多事。我自己也习惯在每台Envoy上留一个日志格式注释方便同事上来就能看懂。这个项目后续还可以继续扩展的方向是把Envoy的访问日志格式换成NDJSON配合OpenTelemetry的Exporter直接发到统一平台或者把Envoy接入OpenTelemetry Collector实现更多维度的自动关联。这些都是下一步可以玩的高阶玩法了。
返回列表