本文内容是笔者基于 GOTC 2023 全球开源技术峰会整理。
前端为什么要接入链路追踪
大家都应该经历过这样的事情:某一个页面或者某一个请求比较慢,前后端分别调查后数据对不上,或者很难说明差异的来源是由什么造成的,这就是单点监控带来的问题。然后是问题定位,前端作为系统的出入口,导致很多团队问题一般界线模棱两可的问题都会交给前端去定位,相信很容前端应该都经历过这样的痛苦,而作为前端也只能人肉的去分析这些问题,目前并没有什么好的手段自动发现问题。最后就是数据价值,比起后端,前端是与用户最接近的,可以获得非常多的用户使用信息,包括性能、接口、行为、地址位置、网络信息等等。这些信息单独来看可能是有一些价值的,但是对整个 IT 系统而言价值没有充分挖掘,形成了数据孤岛。
链路追踪问题和挑战
一条典型的链路展示
上面图片中是一条典型链路的基本结构。首先是端侧,端侧平台众多,常见的端侧有 Android、IOS 应用以及电脑端的浏览器和应用;在国内还有各个APP平台的小程序、小游戏、公众号等。端侧的繁荣景象导致链路追踪端侧 SDK 的开发成本非常高,需要适配和测试的平台非常多。而且端侧一般来说网络也比较复杂,有弱网的情况,如何保证 SDK 能够完整、正确、高效的发送日志也是一个非常棘手的问题。
其次是网关层,它在云原生的加持下变得更加独立和复杂,该层一般包括网关、负载均衡、防火墙等。用户的请求请过网关层到达服务端,这样的曲折链路导致用户测请求和服务端请求中间变得不再透明和直接,一般很少有方法能够持续的检测网关层不同节点之间的延迟。
最后是服务层,服务层的检测相对容易很多,已经有很多平台服务能够支持服务层的链路追踪服务。
从这条典型的链路可以看到构建全端的链路追踪服务痛点还是非常多的,下面展开讲讲需要解决的痛点:
痛点一:多端采集问题
端侧是全端全链路建设的核心发起点,是生成链路追踪 id 的第一环(本章主要介绍和 Javascript 相关端全链路的建设。端侧需要解决的问题非常多,大致分为五类:
-
平台众多,包含桌面平台、浏览器(Web)平台、国内特殊的小程序平台和全栈框架,既要全部兼容,还要保证端侧 agent 包的大小不至于膨胀过大有一定的难度。
-
兼容难度大,不同平台需要兼容的接口不一样,特别是路由、请求、缓存相关的。
-
上下文获取难,javascript 端侧的执行环境不同于后端 java、go,目前还没有很好的获取当前 context 的标准,而且小程序情况更加恶劣,各个厂家的实现方式都不一样。
-
日志丢错问题,端侧存在弱网的情况可能发送不成功,而且端侧用户是即来即走的模式,设备或者网页随时可能关闭。
-
高 QPS 问题,用户量大的情况下,端侧流量会非常大,需要保证高流量下稳定写入。
痛点二:统一协议问题
链路追踪业界提供的方案非常多,国内外厂商都有,前端链路追踪用的比较多的有sentry,自建相对比较方便,github 上也有一些开源的支持小程序的插件。但是整体来看呢,可观测系统会包含日志、指标、链路等多种需要接入的系统,业界很少有能够满足前后端一体化统一协议的问题。例如前后端通信方案不统一、日志系统和链路追踪系统等多套方案不统一、不同系统隔离数据不互通,以及很多方案都是厂商绑定的,不方便迁移未来迁移的别的方案。而且链路追踪采集数据涉及的面非常广,不仅包括采集协议,还涉及到存储的方式、流批计算等。
链路追踪设计方案
统一协议 OpenTelemetry
云原生基金会CNCF在合并OpenCensus和OpenTracing后诞生了OpenTelemetry项目,旨在将Logging、Tracing、Metrics三者进行统一,实现数据的互通互操作。OpenTelemetry最核心的功能是产生、收集可观察性数据,并支持传输到各种的分析软件中,整体的架构如上图所示,其中Otel Library用于产生统一格式的可观察性数据;Collector用来接收这些数据,并支持把数据传输到各种类型的后端系统。OpenTelemetry标准化对于可观测有着重要的意义。
在此基础上,我们基于 OpenTelemetry 的协议打造了自研的 SLS OT JS SDK,旨在和后端统一日志、Trace的协议格式。选择自研主要是因为开源的 OT JS SDK 目前主要用于nodejs端,而用户前端的包体过大,达到100KB,我们自研的 SDK 非常轻量级,仅 15KB 大小。
确保日志不丢失
JS SDK 在设计之初就确保了高可用性。首先是数据缓存,根据平台的不同有多种策略选择,优先选择 IndexDB,在其他小程序平台可以选择 local storage。其次是数据发送,支持多种发送方式包括最省流量的点图,以及性能和成功率最高的 beacon。最后是数据通道,除了默认的域名上报外,还支持使用 DCDN,支持就近访问上报,这个能够大大提高发送成功率。
统一协议的全端 SDK 架构
下图就是我们全端的 JS SDK 的架构,全插件化设计。有一层兼容层,适配了大部分 JS 平台的接口包括请求、路由。支持全自动埋点,发送请求时自动会带上 TraceID、SpanID、当前页面的 PageID 和 当前会话 SessionID,支持和服务端以及云产品中间层打通。所有端的日志会和后端日志一起统一写入 SLS 统一接入层,支持定义一个 plugin 后写入其他支持 OT 的厂商。
全平台链路追踪架构
下图是 SLS 全平台链路追踪的架构,里面重点画出了和前端相关的部分,前端支持了主流的web平台和小程序平台还有桌面平台,也和阿里云一些流量转发的云产品做了打通。首先系统有一层统一接入层,支持高流量并发接入,所有端包括前端后端app端都会以统一的协议接入统一接入层。
统一接入层后面是统一存储层,会将所有端的接入分析日志、链路数据、指标数据。然后是数据处理层,我们使用 SLS 上统一的 ETL 和 schedule SQL 引擎,按分钟汇总 trace 数据,计算每一条trace的拓扑和指标,最后汇总到标准的数据存储,接入的用户可以方便的搜索规整后的日志库和指标库。
最后为了充分的挖掘我们前端agent记录的数据的价值,系统还提供了许多上层的应用,包括链路分析、拓扑分析、根因分析还有告警等。
前端链路追踪分析案例
案例一:打通网关、负载均衡
上文介绍过网关层在云原生的加持下变得更加独立和复杂,SLS 通过和阿里云各个网关层合作,在全链路的每个网关层节点上支持将 HTTP 协议 header 中的 traceid 和 spanid 记录在网关的访问日志中。我们会综合所有网关的访问日志、Trace的日志,根据请求时间、处理时间、内置默认顺序等,重新计算出每个节点的 traceid 和 spanid,通过这样的方式打通了所有的链路环节。
案例二:多维度智能异常分析
端侧的数据是比较丰富的,和后端相比,端侧通常会多出地域(机房、城市、省份)、设备型号、设备版本、运营商等。除了这些信息外,基本的端侧性能数据、用户的访问行为、接口的性能和报错也可以收集,有了这些数据后就可以针对这些属性构建异常分析程序。
第一步是针对业务属性构建告警,比如流量下跌告警、交易量下跌告警,此类告警构建相对是比较容易的。
第二步是针对每一个告警进行异常分析,基于一个深度学习异常分析算法,支持单维归因和组合归因,通过正向显示和反向显示的比较能够分析出异常的原因。