
1. 指标体系整体设计思路1.1 SkyWalking监控指标的定位与分层接手SkyWalking这个开源APM系统也快三年了从最初只是搭个环境看看链路到后来真刀真枪地用它撑起几十个微服务的监控最大的感触是很多人把SkyWalking当成链路追踪工具用但它真正值钱的地方其实是那套精心设计的指标体系。链路追踪解决的是“某个请求走了哪些节点”指标解决的却是“整个系统现在到底健不健康、瓶颈卡在哪”这两个完全不同的问题。在讲各项指标之前有必要先搞清楚SkyWalking的指标是怎么分层的。官方文档的术语比较多我按自己的理解重新整理了一下大致可以分成四层第一层是实体维度包括Service服务、Service Instance服务实例、Endpoint端点所有指标最终都要绑定到这三级实体上。比如你看到一条“响应时间”指标心里一定要先问一句这是哪个服务的哪个实例的哪个接口的不先搞清楚维度归属指标再精确也是白搭。第二层是观测对象SkyWalking把指标分为几大类别CURL调用链路相关的通用指标、JVMJava虚拟机指标、Database数据库访问指标、MQ消息队列指标、HTTPHTTP调用指标等等。每类观测对象有自己专属的指标集合。第三层是聚合方式SkyWalking的指标在存储层会按照不同的时间维度聚合比如分钟级、小时级、天级这里面最常用的是分钟级因为绝大多数告警和排障看分钟级就够了。聚合又会区分平均值、百分位值p50、p75、p90、p95、p99、总和、计数等统计口径。第四层是表达式计算也就是基于基础指标用表达式算出来的派生指标比如可用性Availability、Apdex分数这些。这类指标在UI上可以直接看到但它们的计算逻辑才是真正需要理解的。把这四层弄清楚之后再看SkyWalking界面上的那一堆图表基本上就不会被绕晕了。接下来我按实际使用频率把这套指标体系逐个拆开讲。1.2 指标数据是怎么从探针流到看板的理解指标要从数据的流动路径入手。SkyWalking的Java Agent探针通过字节码增强技术在目标应用启动时挂载到JVM里自动拦截HTTP入口、RPC调用、JDBC访问、消息队列发送消费等关键节点。每拦截到一个请求探针会记录它的开始时间、结束时间、调用关系同时通过定时任务周期性采集JVM的CPU、内存、GC情况。这些数据会先存在探针的内存缓冲区里然后通过gRPC协议异步上报到OAP ServerObservability Analysis Platform。OAP Server收到数据后不会直接存库而是先做一次聚合计算——把同一时间窗口内、同一实体、同一指标的原始数据合并成一条统计记录。比如1分钟内某个接口被调用了2000次OAP不会存2000条请求记录而是算出一分钟内的调用次数、平均响应时间、p99、最大耗时、错误次数这一组数字再写入存储层。这个设计是我觉得SkyWalking做得最漂亮的地方。聚合发生在内存里所以存储压力很小。一套默认配置跑几十个服务ES集群三五个节点就能扛住每天上亿条指标的写入。明白了这个机制你就能理解为什么指标界面上看到的数据会有一两分钟的延迟——那是因为聚合窗口是分钟级的OAP要等一个窗口的数据到齐才能计算并落库。存储层面SkyWalking支持H2默认单机演示用、MySQL、Elasticsearch最常用、TiDB等。生产环境基本清一色选ES因为指标数据天然适合倒排索引加聚合查询ES的聚合能力直接支撑了UI上的各种趋势图和TopN排行。指标相关的索引在ES里的命名前缀是sw_metric点开Kibana看这些索引会发现每个doc的字段结构就是“实体维度 时间戳 一组指标值”理解了这个结构后面想自己写脚本批量导出指标做分析就很容易了。2. 核心指标详解2.1 服务级指标cpm、响应时间与Apdex进入SkyWalking的UI选一个服务默认跳到的就是“Service”面板这个面板的核心指标有四个第一个是CPM每分钟调用次数英文全称是Calls Per Minute。这个指标衡量的是服务的吞吐量折线图上一条一条往上走的曲线代表每分钟处理了多少个请求。注意它与QPS的区别QPS通常是秒级的CPM是分钟级的。如果CPM从800突然跌到200最简单直接的判断就是入口流量出了问题要么是上游限流了要么是网关断连了要么是消费者不再调用了。第二个是响应时间Response TimeUI上通常会给出一条平均响应时间的曲线但在SLA里真正有用的是百分位值。p50代表一半请求比它快p99代表99%的请求都在这个耗时以内。用p99来判断线上体验比较接近真实感受因为平均响应时间很容易被少量极快请求拉低。举例来说一个接口平均耗时150ms看起来很健康但p99飙到2秒以上说明存在少量长尾请求严重拖慢了体验这种情况排查线程池阻塞或者Full GC往往就能发现问题。第三个是Apdex应用性能指数。SkyWalking的Apdex计算有一个配置化的阈值T默认T500ms。计算规则很简单请求耗时小于等于T的判为满意1分耗时在T到4T之间的判为可容忍0.5分大于4T的判为不满意0分。Apdex 满意请求数 可容忍请求数×0.5/ 总请求数取值在0到1之间。业界通常认为0.9以上算健康0.85到0.9需要关注低于0.85就该认真排查了。你可以针对不同的服务设置不同的T值核心交易服务的T设小一些比如200ms非核心服务可以放宽到1秒这样Apdex才能反映真实的业务体验。第四个是SLA服务可用性SkyWalking计算的是“成功请求数 / 总请求数”。需要注意这里的成功指的是HTTP状态码小于400或者RPC调用没有抛出异常。SLA和Apdex是一对孪生指标看服务健康状态时两个要一起看SLA往下掉说明有错误发生Apdex往下掉说明没有错误但响应变慢了两者的排查方向完全不同。服务端点的指标其实就是在服务级指标的基础上多了一个endpoint维度。线上排查时我的习惯是先看Service面板锁定大致方向再进Endpoint面板找到具体的慢接口或报错接口最后点进去看对应的调用链明细这个从上到下的下钻路径效率很高。2.2 实例级指标JVM与系统资源服务跑得好不好最终还是要落在进程上。SkyWalking的Instance面板里能看到每个服务实例的主机名、IP、当前状态以及一组JVM指标。先说JVM内存UI上会分成堆内存Heap和非堆内存Non-Heap两张趋势图。堆内存又分Eden、Survivor、Old三个区G1垃圾回收器下还会显示Region的分布情况。看堆内存曲线我总结了一个非常实用的经验如果Eden区周期性出现锯齿状波动说明对象分配和回收是正常的真正需要担心的是Old区曲线持续向上、几乎不回落这通常预示老年代在不断累积对象离Full GC不远了。然后是GC次数和GC耗时。SkyWalking会分别统计Young GC和Full GC的次数与耗时。Young GC频繁未必是坏事说明短期对象多、回收得快Full GC一旦出现且耗时长必然有对象长期堆积。我在一台压力比较大的服务上遇到过Full GC一次耗时3秒多的情况而那次服务SLA跌到92%就是因为GC停顿导致线程阻塞、大量请求超时。通过SkyWalking的GC指标曲线结合响应时间曲线一对比问题定位起来非常直观。线程指标包括活跃线程数、峰值线程数、守护线程数等。活跃线程数持续逼近server.tomcat.threads.max配置值的时候说明线程池接近满载再往后就是请求排队和拒绝。看这个指标还能发现线程泄漏有一个项目里活跃线程数每天涨一点十多天之后触顶服务彻底假死最后通过SkyWalking的线程历史曲线配合线程dump才定位到是数据库连接池没释放导致线程阻塞。CPU和内存这几项系统指标也归属于实例级。理论上SkyWalking支持通过探针采集JVM所在宿主机的CPU、内存、磁盘IO但在容器化部署下它采集到的是Pod视角的数据和Kubernetes的Metrics Server数据口径会不一致。所以容器环境里我一般不太依赖SkyWalking看系统资源而是用Prometheus那套SkyWalking的CPU和内存指标看JVM进程本身更准确。2.3 数据库与跨进程调用指标微服务链路里的瓶颈十有八九在数据库。SkyWalking通过JDBC拦截器自动捕获数据库访问信息在“Database”面板能看到每条SQL对应哪个服务、调用哪个数据库实例、平均耗时、每分钟执行次数。有一个指标在日常巡检中特别好用数据库访问响应时间。它精确到每个数据库实例、每个SQL模板的耗时。SQL模板指的是探针会将参数化后的SQL作为维度比如SELECT * FROM orders WHERE user_id ?就是一个模板同一条模板的所有执行记录会聚合在一起。这样就能看到哪条SQL是真正的慢查询再配合DBA的慢查询日志一起分析定位效率非常高。数据库指标的p99尤其重要。很多系统的平均SQL耗时看着不高但p99相当吓人几百毫秒甚至上秒级。每当看到这种曲线我第一反应就是索引失效或者数据量涨了之后执行计划变了。顺带说一句如果你用了MyBatis探针拦截到的SQL模板会带上_mb后缀的mapper方法名定位代码位置会方便很多缺点是SQL会显得很长一开始看可能不太适应。跨进程调用指标也归在这一类里。当你用微服务架构时一个请求要穿过网关、用户服务、订单服务、积分服务每个环节的耗时都需要测出来。SkyWalking在拓扑图上会用粗线条和颜色标出服务之间的调用关系线的粗细代表调用量颜色深浅代表响应时间。点开调用关系连线能看到这条调用链路的CPM、平均耗时、成功率一眼找出跨服务调用的瓶颈是哪一个。3. 链路追踪与拓扑分析3.1 基于指标的Trace查询与排障思路指标能告诉我们哪里出了问题但无法告诉我们为什么出问题。这时候需要从指标下钻到链路追踪数据。SkyWalking中指标和Trace是强关联的进入Trace查询页可以通过服务名、端点名、响应时间范围、HTTP状态码、Trace ID等条件筛选链路记录。我最常用的查询方式是先在Endpoint面板找到p99飙高的接口把它最近5分钟的平均耗时和错误率截图然后切到Trace页面用同样的时间段过滤条件找到几条耗时超过平均耗时的Trace点进去看Span列表。Span列表是整个调用链的骨架。一段完整的Trace由多个Span组成每个Span对应一次方法调用或一次跨进程访问Span之间有父子关系。在Trace详情页里每个Span会显示所属服务、调用的类与方法、开始时间、耗时、是否有异常。看这个列表有个技巧正常情况下每个Span的耗时分布是相对均匀的如果某个Span独占了大头问题基本就锁定在它身上——要么是某个第三方服务变慢要么是自己业务代码里有耗时的同步调用要么是数据库查询慢了。SkyWalking的Trace视图还支持展示日志信息。如果探针配置了日志采集你可以把业务日志和Trace关联起来最直接的做法是保持logback配置里的traceId通过SkyWalking的日志组件把日志写入到对应Trace的Span中。这样排查问题的时候能同时看到调用链信息和日志输出不用在两套系统之间来回切换。这个配置虽然要花一点时间但做完之后的排查效率提升是看得见的。3.2 拓扑图的指标解读拓扑图是SkyWalking最直观的一张图不少团队给领导汇报时都直接投屏这张拓扑图。但作为技术人员看拓扑图不能光看连线的漂亮程度要能读出隐藏信息。每条连线上展示的指标主要有三个调用量CPM、平均响应时间Latency、成功率Success Rate。当一个服务的成功率从99.9%掉到95%拓扑图上这个服务节点的颜色会从绿色变成黄色或者红色这个视觉变化很直观但真正要定位原因还得点进去看细节。读拓扑图有一个很容易忽略的点注意连线的方向。SkyWalking会区分客户端视角和服务端视角一个调用关系在两端各有一组指标。举例来说订单服务调用库存服务订单服务视角的指标反映的是它发起调用的耗时和成功率库存服务视角的指标反映的是它接收并处理请求的耗时和成功率。两者通常很接近但如果客户端视角的耗时远大于服务端视角的耗时说明耗时消耗在网络上或者序列化反序列化上而不是业务处理上这在高并发下并不罕见。跨进程调用的指标采集还会带上传输协议相关的信息比如HTTP方法、RPC方法名、消息Topic等。如果你给项目接入过HTTP调用会发现SkyWalking能自动识别HTTP方法并归类排查特定类型的请求时会很方便。3.3 多路径效应与关键链路识别在复杂的微服务架构里一个入口请求往往会拆分成多条并行路径SkyWalking在追踪链路时能清晰展示这种并行关系。这个现象我们内部叫“多路径效应”它反映的是服务间依赖的真实复杂度。比如一个下单请求网关转发给订单服务订单服务同时调用了用户服务、商品服务、优惠券服务其中优惠券服务还会回调营销服务。在拓扑图和Trace列表里这些调用会以平行加嵌套的Span结构展现出来。这时候最需要关注的指标是关键路径耗时——也就是整条Trace从根节点到最终叶节点的最大耗时链路。SkyWalking的Trace详情会标记出最慢的那个Span顺着这条关键路径排查往往就能找到影响整体响应时间的主要因素。并行调用的场景下指标有一个特别值得注意的点哪怕每条并行路径的平均耗时都不高整条Trace的耗时依然可能被最慢的一条拖垮。比如用户服务和商品服务都只要100ms但优惠券服务需要2秒整个下单请求就得等2秒多。这种问题从平均指标上看不出来必须看Trace级的极值或p99才能暴露。我建议在大促前对每个核心链路的p99做一个专项评估找出那些“自身不怎么起眼但就是慢”的第三方依赖提前优化或者降级能避免很多线上事故。4. 告警规则配置与实践4.1 基于指标的告警规则设计SkyWalking自带的告警引擎可以基于各类指标配置阈值触发。它的告警机制不复杂OAP Server每隔一定周期默认每分钟评估一次告警规则把当前聚合出的指标值和阈值做对比满足条件就生成一条告警推送到配置好的Webhook接口。告警规则的配置文件在OAP Server的alarm-settings.yml里。最基础的一条规则长这样rules: service_resp_time_rule: metrics-name: service_resp_time op: threshold: 1000 period: 10 count: 3 message: 服务响应时间超过1000ms tags: level: critical这段配置的意思是针对service_resp_time这个指标如果连续10分钟里有3次取值大于1000ms就触发告警。注意两个关键参数——period是评估窗口的分钟数count是触发阈值需要的次数。这两个值组合在一起的意义是防止抖动误报某一次响应慢不严重持续慢才严重。再看另一个维度的示例针对端点成功率rules: endpoint_success_rate_rule: metrics-name: endpoint_success_rate op: threshold: 95 period: 5 count: 3 message: 端点成功率低于95%告警引擎支持的指标非常多service_cpm、service_sla、service_apdex、endpoint_avg、jvm_gc_time这类都在可配置范围内。一个比较实用的组合是对核心结算服务配置响应时间告警、成功率告警、GC耗时告警三个级别高级别阈值触发走电话通知低级别阈值触发只需要在企业微信群里发个消息提醒即可。4.2 常见告警参数的计算口径配置告警有个常见的坑threshold的数值与你看到的UI曲线不一定完全对得上。原因在于同一指标在UI和告警引擎里可能用了不同的聚合口径。拿service_resp_time来说UI默认展示的是p99或者平均值但告警指标的定义是“窗口内所有请求的平均响应时间”。如果你的服务响应时间分布很散就会出现一种尴尬场景UI上p99已经2秒多了告警阈值1000ms却没触发因为平均值还不到600ms。解决方案是使用SkyWalking提供的百分位指标。在OAP中百分位指标通常在原始指标名后加后缀比如service_resp_time对应的p99指标可能是service_resp_time_p99。配置规则时把metrics-name写成service_resp_time_p99阈值才能真正反映长尾情况。具体指标后缀和名称可以从OAP控制台或者Prometheus暴露的Metric列表里查到跑一次该指标对应的HTTP查询接口就能清晰地看到。GC告警同理jvm_gc_time的默认数据是累计GC毫秒数需要看两次采集的差值才能算出窗口内GC耗时。直接在告警规则里配jvm_gc_time 1000往往不准更好的做法是配置jvm_gc_time的波动率increase表达式或者在探针端调整采集口径。总之在配置告警前先到UI上把指标45天的原始数据拉出来看一眼理解它的量纲和分布再定阈值可以省去很多后面调整规则的时间。4.3 告警消息模板与接收渠道告警触发之后发送到什么渠道决定了告警能不能真正到达负责人手里。SkyWalking默认支持Webhook也就是把告警消息以POST方式发送到你指定的HTTP接口上。你可以在接口里做二次转发推送到钉钉、企业微信、飞书或者自研的告警平台。我当时用得最多的是企业微信机器人。接入方式很简单在企业微信群里添加一个机器人拿到Webhook地址再写一个轻量的Spring Boot接口接收SkyWalking的告警推送将消息格式转换成企业微信要求的JSON结构POST到机器人的Webhook地址就算完成了。SkyWalking的告警推送JSON里包含以下几个关键字段scopeId/scope告警所属的实体类型比如服务、实例、端点。name规则名对应配置文件里的规则ID。id0/id1实体维度的ID比如服务ID和实例ID。startTime和period触发时间和窗口期。alarmMessage这是核心字段展示指标名、当前值、阈值等关键信息。拿到alarmMessage在Webhook接口里可以直接解析出“哪个服务、哪个指标、当前多少、触发条件是什么”。我踩过的一个坑是不解析直接转发原始JSON群里看到的消息会带一堆ID数字可读性非常差。后来写了一个解析函数把ID映射成服务名加上TopN接口的当前响应时间列表一起推送排障效率高出好几个档次。告警规则还需要注意避免消息风暴。某个核心服务抖动时可能同时触发五六个指标的告警每个周期刷一遍微信群一秒能弹七八条消息。处理办法有两个一是把相关联的规则归组命中的时候只发一条综合告警二是设置告警静默时间同一个规则短时间内不重复发送。SkyWalking的silence-period参数就是干这个用的单位是分钟合理配置之后能少收很多无效消息。5. 常见问题与排查技巧实录5.1 指标不显示或数据为空的对策接入SkyWalking之后发现UI上服务是有的但指标一片空白这种情况我遇到得不少原因几乎都出在探针配置和版本兼容上。第一种情况探针版本和OAP版本不一致。SkyWalking对版本兼容要求比较严格探针Agent的版本要比OAP Server的版本新或者一致不能低太多。有一次团队用了8.5.0的Agent对接8.9.0的OAP部分新版本的指标协议解析不了很多图表一直不出数据。解决办法很直接把Agent升级到和OAP一样的版本然后重点检查一下Agent启动日志里是否出现了协议不匹配的Warning。第二种情况业务服务使用了异步线程或者自定义的线程池。SkyWalking的探针默认会做跨线程的上下文传递如果你用了CompletableFuture、Async或者自建线程池容易出现Trace断开、指标统计不到的情况。异步场景下指标数据时有时无就和线程池中的上下文丢失有关。解决办法是在线程创建时调用SkyWalking的ContextManager显式传递上下文或者用官方提供的TraceCrossThread注解做线程装饰。第三种情况上报被安全策略拦截。有些企业级网络会限制gRPC/HTTP的传输端口默认的11800gRPC上报端口和12800HTTP端口如果没放通数据就悄无声息地丢在Agent侧。排查时第一件事就是测试Agent所在机器到OAP的端口连通性telnet或者nc -vz一下就知道了。指标不显示要按层次排查先看探针日志有没有报错再看OAP是否收到了数据最后看存储层有没有写入。按照“Agent → OAP → Storage → UI”的顺序逐个验证定位并不难。5.2 指标波动背后的深层原因解读指标不是恒定的线上服务的指标会有正常波动。作为技术人员要学会区分“正常波动”和“异常拐点”。常规的业务流量波动不用多说早晚高峰、整点定时任务、促销活动都可能导致CPM和响应时间同时攀升。这时候更值得关注的是“分离趋势”——CPM没变但响应时间涨了说明系统在某处开始排队CPM涨了但响应时间平稳说明系统的弹性伸缩还是好的CPM跌了同时响应时间也跌了但SLA也在跌说明大量请求直接被拒了健康检查拦截导致的假象。GC指标和响应时间联动的场景特别典型。年轻代GC频繁时响应时间曲线会出现毫秒级的小锯齿不影响整体一旦出现老年代GC响应时间会出现明显尖峰并且这尖峰延续的时间段正好覆盖GC停顿的时间段这就是典型的GC导致的长尾延迟。遇到这种情况首先调整堆内存分配其次检查是否有大对象频繁创建。数据库连接池耗尽的时候指标特征也非常明显服务端点的调用量其实没有下降但99%的请求响应时间同时大幅上升数据库访问的耗时并没有明显增长反而是服务自身处理耗时在涨。结合SkyWalking的线程指标——活跃线程数贴满上限——判断起来基本十拿九稳。教大家一个习惯别等到故障发生了才去看指标日常巡检时要有意识地把几组关联指标拉到一起观察。我每天的巡检就四件事看核心服务SLA和Apdex、看p99响应时间趋势、看JVM老年代和GC曲线、看数据库慢SQL指标排行。这套组合看完基本就能掌握系统的健康状况真出了问题也有非常明确的下钻路径。5.3 指标误读与口径选择的避坑建议最后写一些别人容易忽略的、但是实际踩过的坑。第一个坑平均响应时间害人不浅。线上一个接口高峰时段有一批超时请求把p99拉到3秒平均响应时间看起来才涨到800ms如果不看百分位你会以为系统很健康。所有关键路径的指标分析一律以p95和p99为准。特别是对外承诺了SLA的服务重点盯死p99。第二个坑时间窗口对不齐。SkyWalking的UI默认是一个全局时间范围但不同指标的聚合窗口可能不同。服务指标是分钟级聚合JVM指标可能是30秒或1分钟聚合数据库指标的聚合又可能是另一个窗口。分析的时候如果Total时间跨度大、窗口级别不一样比较数值会得出错误结论。建议拉图表时统一选择“过去15分钟”这类相对时间范围并看清图表下方的聚合粒度说明。第三个坑多实例聚合和单实例平均混淆。服务级指标是所有实例的聚合值实例级指标才是单独进程的表现。一个服务有三个实例一个内存泄漏了导致Full GC频繁但服务级的平均响应时间可能只上涨了15%看着问题不大。必须看实例维度的指标先把异常实例找出来才能做快速隔离而不是对着服务级指标发呆。排查顺序应该是“服务级确认问题 → 实例级定位进程 → Trace级下钻原因”。第四个坑依赖指标前后端口径差异。前面提过客户端视角和服务端视角的指标可能不一致具体到HTTP调用还会遇到网关超时配置比服务端超时配置短的情况——客户端已经在报超时了服务端却处理成功了。这种场景下客户端视角的失败数和服务端视角的成功数会对不上如果你只盯服务端成功率的告警就会漏掉大量用户实际感知的失败。处理方式是网关超时时间要大于服务端业务处理时间并在SkyWalking里同时建立服务和网关节点本身的告警规则。这行干久了踩坑就是家常便饭但正因为踩过坑才理解指标背后对应的真实系统行为。SkyWalking这套指标体系看起来繁复真正用顺之后你会发现它就是运维人员的第二双眼睛——每个曲线、每个数字都在替你盯着线上的风吹草动。我个人的体会是指标系统的建设不是一蹴而就的先盯核心链路逐步完善告警和看板最终形成自己团队的一套排障SOP这才是用好SkyWalking的正确打开方式。