SkyWalking调研与初步实践
APM和调⽤链跟踪
随着企业经营规模的扩⼤,以及对内快速诊断效率和对外SLA(服务品质协议,service-level agreement)的追求,对于业务系统的掌控度的要求越来越⾼,主要体现在:
对于第三⽅依赖的监控,实时/准实时了解第三⽅的健康状况/服务品质,降低第三⽅依赖对于⾃⾝系统的扰动(服务降级、故障转移)对于容器的监控,实时/准实时的了解应⽤部署环境(CPU、内存、进程、线程、⽹络、带宽)情况,以便快速扩容/缩容、流量控制、业务迁移
业务⽅对于⾃⼰的调⽤情况,⽅便作容量规划,同时对于突发的请求也能进⾏异常告警和应急准备
⾃⼰业务的健康、性能监控,实时/准实时的了解⾃⾝的业务运⾏情况,排查业务瓶颈,快速诊断和定位异常,增加对⾃⼰业务的掌控⼒
同时,对于企业来说,能够更精确的了解资源的使⽤情况,对于成本核算和控制也有⾮常⼤的裨益。
在这种情况下,⼀般都会引⼊APM(Application Performance Management & Monitoring)系统,通过各种探针采集数据,收集关键指标,同时搭配数据呈现和监控告警,能够解决上述的⼤部分问题。
然⽽随着RPC框架、微服务、云计算、⼤数据的发展,同时业务的规模和深度相⽐过往也都增加了很多,⼀次业务可能横跨多个模块/服务/容器,依赖的中间件也越来越多,其中任何⼀个节点出现异常,都可能导致业务出现波动或者异常,这就导致服务质量监控和异常诊断/定位变得异常复杂,于是催⽣了新的业务监控模式:调⽤链跟踪
能够分布式的抓取多个节点的业务记录,并且通过统⼀的业务id(traceId,messageId,requestId等)将⼀次业务在各个节点的记录串联起来,⽅便排查业务的瓶颈或者异常点
产品对⽐
APM和调⽤链跟踪均不是新诞⽣事务,很多公司已经有了⼤量的实践,不过开源的并且能够开箱即⽤的产品并不多,这⾥主要选取了Pinpoint,Skywalking,CAT来进⾏对⽐(当然也有其他的例如Zipkin,Jaeger等产品,不过总体来说不如前⾯选取的3个完成度⾼),了解⼀下APM和调⽤链跟踪在开源⽅⾯的发展状态。
Pinpoint
是⼀个⽐较早并且成熟度也⾮常⾼的APM+调⽤链监控的项⽬,在全世界范围内均有⽤户使⽤,⽀持Java和PHP的探针,数据容器为HBase,其界⾯参考:
Skywalking
是⼀个新晋的项⽬,最近⼀两年发展⾮常迅猛,本⾝⽀持OpenTracing规范,优秀的设计提供了良好的扩展性,⽀持Java、PHP、.Net、NodeJs探针,数据容器为ElasticSearch,其界⾯参考:
CAT
是由美团开源的⼀个APM项⽬,也历经了多年的迭代升级,拥有⼤量的企业级⽤户,对于监控和报警整合⽐较紧密,⽀持Java、C/C++、.Net、Python、Go、NodeJs,不过CAT⽬前主要通过侵⼊性的⽅式接⼊,数据容器包括HDFS(存储原始数据)和mysql(⼆次统计),其界⾯参考:
横向对⽐
上⾯只是做了⼀个简介,那这三个项⽬各⾃有什么特⾊或者优势/劣势呢(三者的主要产品均针对Java,这⾥也主要针对Java的特性)?
Pinpoint
优势
⼤企业/长时间验证,稳定性和完成度⾼
探针收集的数据粒度⽐较细
HBase的数据密度较⼤,⽀持PB级别下的数据查询
代码设计考虑的扩展性较弱,⼆次开发难度较⼤(探针为插件式,开发⽐较简单)
拥有完整的APM和调⽤链跟踪功能
劣势
代码针对性强,扩展较难
容器为HBase,查询功能较弱(主要为时间维度)
探针的额外消耗较多(探针采集粒度细,⼤概10%~20%)
项⽬趋于成熟,⽽扩展难度较⼤,⽬前社区活跃度偏低,基本只进⾏探针的增加或者升级
缺少⾃定义指标的设计
Skywalking
优势
数据容器为ES,查询⽀持的维度较多并且扩展潜⼒⼤
项⽬设计采⽤微内核+插件,易读性和扩展性都⽐较强
主要的研发⼈员为华⼈并且均⽐较活跃,能够进⾏更加直接的沟通
拥有完整的APM和调⽤链跟踪功能
劣势
go和java后端开发劣势项⽬发展⾮常快,稳定性有待验证
ES数据密度较⼩,在PB级别可能会有性能压⼒
缺少⾃定义指标的设计
CAT
优势
⼤企业/长时间验证,稳定性和完成度⾼
采⽤⼿动数据埋点⽽不是探针,数据采集的灵活性更强
⽀持⾃定义指标
代码设计考虑的扩展性较弱,并且数据结构复杂,⼆次开发难度较⼤
拥有完善的监控告警机制
劣势
代码针对性强,扩展较难
需要⼿动接⼊埋点,代码侵⼊性强
APM功能完善,但是不⽀持调⽤链跟踪
基本组件
如果分别去看Pinpoint/Skywalking/CAT的整体设计,我们会发现三者更像是⼀个规范的三种实现,虽然各⾃有不同的机制和特性,但是从模块划分和功能基本是⼀致的:
当然也有⼀些微⼩的区别:
Pinpoint基本没有aggregator,同时query和alarm集成在了web中,只有agent,collector和web
Skywalking则是把collector、aggregator、alarm集成为OAP(Observability Analysis Platform),并且可以通过集部署,不同的实例可以分别承担collector或者aggregator+alarm的⾓⾊
CAT则和Skywalking类似,把collector、aggregator、alarm集成为cat-consumer,⽽由于CAT有⽐较复杂的配置管理,所以query和配置⼀起集成为cat-home
当然最⼤的区别是Pinpoint和Skywalking均是通过javaagent做字节码的扩展,通过切⾯编程采集数据,类似于探针,⽽CAT的agent 则更像是⼀个⼯具集,⽤于⼿动埋点
Skywalking
前戏这么多,终于开始进⼊主题,介绍今天的主⾓:Skywalking,不过通过之前的铺垫,我们基本都知道了Skywalking期望解决的问题以及总体的结构,下⾯我们则从细节来看Skywalking是怎么⼀步⼀步实现的。
模块构成
⾸先,Skywalking进⾏了精准的领域模型划分:
整个系统分为三部分:
agent:采集tracing(调⽤链数据)和metric(指标)信息并上报
OAP:收集tracing和metric信息通过analysis core模块将数据放⼊持久化容器中(ES,H2(内存数据库),mysql等等),并进⾏⼆次统计和监控告警
webapp:前后端分离,前端负责呈现,并将查询请求封装为graphQL提交给后端,后端通过ribbon做负载均衡转发给OAP集,再将查询结果渲染展⽰
⽽整个Skywalking(包括agent和OAP,⽽webapp后端业务⾮常简单主要就是认证和请求转发)均通过微内核+插件式的模式进⾏编码,代码结构和扩展性均⾮常强,具体设计可以参考:  ,Spring Cloud Gateway的GatewayFilterFactory的扩展也是通过这种plugin define 的⽅式来实现的。
Skywalking也提供了其他的⼀些特性:
配置重载:⽀持通过jvm参数覆写默认配置,⽀持动态配置管理
集管理:这个主要体现在OAP,通过集部署分担数据上报的流量压⼒和⼆次计算的计算压⼒,同时集也可以通过配置切换⾓⾊,分别⾯向数据采集(collector)和计算(aggregator,alarm),需要注意的是agent⽬前不⽀持多collector负载均衡,⽽是随机从集中选择⼀个实例进⾏数据上报
⽀持k8s和mesh
⽀持数据容器的扩展,例如官⽅主推是ES,通过扩展接⼝,也可以实现插件去⽀持其他的数据容器
⽀持数据上报receiver的扩展,例如⽬前主要是⽀持gRPC接受agent的上报,但是也可以实现插件⽀持其他类型的数据上报(官⽅默认实现了对Zipkin,telemetry和envoy的⽀持)
⽀持客户端采样和服务端采样,不过服务端采样最有意义
官⽅制定了⼀个数据查询脚本规范:OAL(Observability Analysis Language),语法类似Linq,以简化数据查询扩展的⼯作量⽀持监控预警,通过OAL获取数据指标和阈值进⾏对⽐来触发告警,⽀持webhook扩展告警⽅式,⽀持统计周期的⾃定义,以及告警静默防⽌重复告警
数据容器
由于Skywalking并没有⾃⼰定制的数据容器或者使⽤多种数据容器增加复杂度,⽽是主要使⽤ElasticSearch(当然开源的基本上都是这样来保持简洁,例如Pinpoint也只使⽤了HBase),所以数据容器的特性以及⾃⼰数据结构基本上就限制了业务的上限,以ES为例:
ES查询功能异常强⼤,在数据筛选⽅⾯碾压其他所有容器,在数据筛选潜⼒巨⼤(Skywalking默认的查询维度就⽐使⽤HBase的Pinpoint强很多)
⽀持sharding分⽚和replicas数据备份,在⾼可⽤/⾼性能/⼤数据⽀持都⾮常好
⽀持批量插⼊,⾼并发下的插⼊性能⼤⼤增强
数据密度低,源于ES会提前构建⼤量的索引来优化搜索查询,这是查询功能强⼤和性能好的代价,但是链路跟踪往往有⾮常多的上下⽂需要记录,所以Skywalking把这些上下⽂⼆进制化然后通过Base64编码放⼊data_binary字段并且将字段标记为not_analyzed来避免进⾏预处理建⽴查询索引
总体来说,Skywalking尽量使⽤ES在⼤数据和查询⽅⾯的优势,同时尽量减少ES数据密度低的劣势带来的影响,从⽬前来看,ES在调⽤链跟踪⽅⾯是不⼆的数据容器,⽽在数据指标⽅⾯,ES也能中规中矩的完成业务,虽然和时序数据库相⽐要弱⼀些,但在PB级以下的数据⽀持也不会有太⼤问题。
数据结构
如果说数据容器决定了上限,那么数据结构则决定了实际到达的⾼度。Skywalking的数据结构主要为:
数据维度(ES索引为skywalking_*_inventory)
service:服务
instance:实例
endpoint:接⼝
network_adress:外部依赖
数据内容
原始数据
调⽤链跟踪数据(调⽤链的trace信息,ES索引为skywalking_segment,Skywalking主要的数据消耗都在这⾥)
指标(主要是jvm或者envoy的运⾏时指标,例如ES索引skywalking_instance_jvm_cpu)
⼆次统计指标
指标(按维度/时间⼆次统计出来的例如pxx、sla等指标,例如ES索引skywalking_database_access_p75_month)
数据库慢查询记录(数据库索引:skywalking_top_n_database_statement)
关联关系(维度/指标之间的关联关系,ES索引为skywalking_*_relation_*)
特别记录
告警信息(ES索引为skywalking_alarm_record)
并发控制(ES索引为skywalking_register_lock)
其中数量占⽐最⼤的就是调⽤链跟踪数据和各种指标,⽽这些数据均可以通过OAP设置过期时间,以降低历史数据的对磁盘占⽤和查询效率的影响。
调⽤链跟踪数据
作为Skywalking的核⼼数据,调⽤链跟踪数据(skywalking_segment)基本上奠定了整个系统的基础,⽽如果要详细的了解调⽤链跟踪的话,就不得不提到。
openTracing基本上是⽬前开源调⽤链跟踪系统的⼀个事实标准,它制定了调⽤链跟踪的基本流程和基本的数据结构,同时也提供了各个语⾔的实现。如果⽤⼀张图来表现openTracing,则是如下:
其中:
SpanContext:⼀个类似于MDC(Slfj)或者ThreadLocal的组件,负责整个调⽤链数据采集过程中的上下⽂保持和传递
Trace:⼀次调⽤的完整记录
Span:⼀次调⽤中的某个节点/步骤,类似于⼀层堆栈信息,Trace是由多个Span组成,Span和Span之间也有⽗⼦或者并列的关系来标志这个节点/步骤在整个调⽤中的位置
Tag:节点/步骤中的关键信息
Log:节点/步骤中的详细记录,例如异常时的异常堆栈
Baggage:和SpanContext⼀样并不属于数据结构⽽是⼀种机制,主要⽤于跨Span或者跨实例的上下⽂传递,Baggage的数据更多是⽤于运⾏时,⽽不会进⾏持久化
以⼀个Trace为例:
⾸先是外部请求调⽤A,然后A依次同步调⽤了B和C,⽽B被调⽤时会去同步调⽤D,C被调⽤的时候会依次同步调⽤E和F,F被调⽤的时候
会通过异步调⽤G,G则会异步调⽤H,最终完成⼀次调⽤。
上图是通过Span之间的依赖关系来表现⼀个Trace,⽽在时间线上,则可以有如下的表达:
当然,如果是同步调⽤的话,⽗Span的时间占⽤是包括⼦Span的时间消耗的。
⽽落地到Skywalking中,我们以⼀条skywalking_segment的记录为例:
{
"trace_id": "52.70.15530767312125341",
"endpoint_name": "Mysql/JDBI/Connection/commit",
"latency": 0,
"end_time": 1553076731212,
"endpoint_id": 96142,
"service_instance_id": 52,
"version": 2,
"start_time": 1553076731212,
"data_binary": "CgwKCjRGnPvp5eikyxsSXhD///8BGMz62NSZLSDM+tjUmS0wju8FQChQAVgBYCF6DgoHZGIudHlwZRIDc3FsehcKC2RiLmluc3RhbmNlEghyaXNr  "service_id": 2,
"time_bucket": 20190320181211,
"is_error": 0,
"segment_id": "52.70.15530767312125340"
}
其中:
trace_id:本次调⽤的唯⼀id,通过snowflake模式⽣成
endpoint_name:被调⽤的接⼝
latency:耗时
end_time:结束时间戳
endpoint_id:被调⽤的接⼝的唯⼀id
service_instance_id:被调⽤的实例的唯⼀id
version:本数据结构的版本号
start_time:开始时间戳
data_binary:⾥⾯保存了本次调⽤的所有Span的数据,序列化并⽤Base64编码,不会进⾏分析和⽤于查询
service_id:服务的唯⼀id
time_bucket:调⽤所处的时段
is_error:是否失败
segment_id:数据本⾝的唯⼀id,类似于主键,通过snowflake模式⽣成
这⾥可以看到,⽬前Skywalking虽然相较于Pinpoint来说查询的维度要多⼀些,但是也很有限,⽽且除了endPoint,并没有和业务有关联
的字段,只能通过时间/服务/实例/接⼝/成功标志/耗时来进⾏⾮业务相关的查询,如果后续要增强业务相关的搜索查询的话,应该还需要
增加⼀些⽤于保存动态内容(如messageId,orderId等业务关键字)的字段⽤于快速定位。
指标
指标数据相对于Tracing则要简单得多了,⼀般来说就是指标标志、时间戳、指标值,⽽Skywalking中的指标有两种:⼀种是采集的原始指
标值,例如jvm的各种运⾏时指标(例如cpu消耗、内存结构、GC信息等);⼀种是各种⼆次统计指标(例如tp性能指标、SLA等,当然也
有为了便于查询的更⾼时间维度的指标,例如基于分钟、⼩时、天、周、⽉)
例如以下是索引skywalking_endpoint_cpm_hour中的⼀条记录,⽤于标志⼀个⼩时内某个接⼝的cpm指标:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。