架构师如何技术选型-全链路监控

Posted 35岁程序员那些事

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构师如何技术选型-全链路监控相关的知识,希望对你有一定的参考价值。

1、如何技术选型,应该是架构师必须具备的技能

  • 技术预研

  • 技术调研

  • 项目风险模型

  • 2、场景项目(全链路监控)

    2.1 项目背景
  • 调研某公司的技术研发团队的现状

  • 监控埋点项目太多,不统一

  • 业务稳定性凝聚力不够

  • 大中台小前台

  • 微服务化

  • 高效和赋能

  • 人力资源匮乏

  • 结果和关系导向

  • 2.2 技术选型

    技术选型范围:Openzipkin、Pinpoint、Incubator-skywalking、Lightstep、Appdash、Jaeger。

    2.2.1 Appdash

    Appdash是Go的应用程序跟踪系统,基于Google的Dapper和Twitter的Zipkin。 

    Appdash允许您跟踪应用程序中请求和操作的端到端处理(用于执行和调试)。它显示每个步骤的计时和特定于应用程序的元数据,并显示每个请求及其子项的树和时间轴。要使用appdash,您必须通过调用appdash录音机来检测应用程序。 您可以记录任何类型的事件或操作。 求及其子项的树和时间轴。要使用appdash,您必须通过调用appdash录音机来检测应用程序。 您可以记录任何类型的事件或操作。 提供了HTTP(客户端和服务器)和SQL的记录器和模式,可以编写自己的记录器和模式。

    Appdash遵循Google Dapper的设计和命名惯例。 如果您对某些架构选择的原因感到好奇,那么您应该阅读该论文。 项目基础组件:

  • Spans

    跨度是指一个操作及其所有子节点。 例如,HTTP处理程序通过调用系统中的其他组件来处理请求,而这些组件又会进行各种API和DB调用。 HTTP处理程序的范围包括所有下游操作及其后代; 同样,每个下游业务都是自己的跨度,并有自己的后代。 通过这种方式,Appdash构造了在处理HTTP请求期间发生的所有操作的树。

  • Event

    应用程序将其执行的各种操作(在处理请求的过程中)记录为事件。 事件可以是任意消息或元数据,也可以是由Go类型定义的结构化事件类型(例如HTTP ServerEvent或SQLEvent)

  • Recoder

    应用程序使用Recorder将事件发送给收集器,每个记录器与处理特定请求的操作树中的特定跨度相关联,并且通过记录器发送的所有事件自动与 该上下文相关联。

  • Collector

    收集器接收记录器发送的注释(事件的编码形式)。 通常,应用程序的Recorder与本地收集器(使用NewRemoteCollector创建)进行通信。此本地收集器将数据转发到远程appdash服务器(使用Ne wServer创建,该服务器组合了构成应用程序的所有服务的跟踪appdash服务器依次运行收集器,在网络上侦听此数据,然后存储它接收的内容。Appdash支持语言: Go、Rubby、Python,Appdash支持OpenTracing API及规范。

  • 2.2.2 Lightstep

    Lightstep全链路解决方案非常完整,整体解决方案和微服务架构生态完美的匹配,如果技术栈匹配,可以开箱即用,维护一个稳定的基线版本,Lightstep学习成本较高,可以复用Lightstep的架构思想,自研全链路框架。

    Lightstep特性:

  • Lightstep全链路的宗旨,在几秒钟内诊断出异常情况,包括网络,移动设备,整体设备和微服务。

  • 实时的监控每个请求, 无论基础架构如何设置,都可以在Web,移动设备,微服务和整体磁盘上进行

  • Lightstep支持SLA(服务等级协议)

  • 在分布式环境中,延迟暂停或故障的根本原因通常是在远程进程中。 LightStep有助于更广泛地理解系统范围内的相互依赖性以及每个组件对其他组件的影响

  • Lightstep支持语言:Java、Js、Go、Python、Object-c、Ruby,Lightstep支持OpenTracing API及规范。

    2.2.3 Jaeger

    Jaeger支持语言:Java、Go、Node、Python和C++,Jaeger支持OpenTracingAPI及规范, Jaeger是Uber开源的全链路监控框架,解决方案的完整性的程度和Lightstep差不多,整体学习成本要低,提供了丰富的探针客户端。

    Jaeger用于基于微服务的分布式系统监控和排错,包括:

  • 分布式上下文传播

  • 分布式事务监控

  • 根本原因分析

  • 服务依赖性分析

  • 性能/延迟优化

  • Jaeger支持高可扩展性,Jaeger后端旨在不会出现单点故障,并可根据业务需求进行扩展。 例如,Uber的任何给定Jaeger安装通常每天处理数十亿个跨度。Jaeger后端,Web UI和仪器库的设计初衷是为了支持OpenTracing标准。

  • 通过跨度参考将跟踪表示为有向非循环图(不仅仅是树)

  • 支持强类型span标记和结构化日志

  • 通过baggage支持通用分布式上下文传播机制

  • Jaeger支持两种流行的开源NoSQL数据库作为跟踪存储后端:Cassandra 3.4+和Elasticsearch 5.x / 6.x. 正在进行使用其他数据库的社区实验,例如ScyllaDB,InfluxDB,AmazonDynamoDB。 Jaeger还提供了一个简单的内存存储器,用于测试设置。

    Jaeger Web UI使用流行的开源框架(如React)在javascript中实现。 在v1.0中已经发布了几项性能改进,以允许UI有效地处理大量数据,并显示具有数万个跨度的跟踪(例如,我们尝试了80,000跨度的跟踪)。

    Jaeger后端作为Docker镜像的集合分发。 二进制文件支持各种配置方法,包括命令行选项,环境变量和多种格式的配置文件(yaml等)Kubernete s模板和Helm图表协助部署到Kubernetes集群。如何公司需要自研全链路,则可以参考Jaeger和Lightstep,优选Jaeger,Jaeger底层支持Zipkin标 准,可以无缝迁移,公司链路底层如果是采用Zipkin,可以完整的切入到新的自研的链路系统。所有Jaeger后端组件都默认公开Prometheus指标( 也支持其他指标后端)。 使用结构化日志库zap将日志写入标准输出。Jaeger兼容Zipkin,虽然我们建议使用OpenTracing API检测应用程序并绑定到Jaeger客户端库,以便从其他地方没有的高级功能中受益,但如果您的组织已经使用Zipkin库投资了检测,则不必重写所 有代码。 Jaeger通过HTTP接受Zipkin格式(Thrift或JSON v1 / v2)的跨度,向Zipkin提供向后兼容性。 从Zipkin后端切换只需将Zipkin库中的流量路由到Jaeger后端。

    2.2.4 Incubator-skywalking

    SkyWalking是一个开源的APM系统,包括监控,跟踪,诊断Cloud Native架构中分布式系统的功能。 核心功能如下:

  • 服务,服务实例,端点指标分析

  • 根本原因分析

  • 服务拓扑图分析

  • 服务,服务实例和端点依赖性分析

  • 检测到缓慢的服务和端点

  • 性能优化

  • 分布式跟踪和上下文传播

  • 报警

  • SkyWalking支持从不同来源收集遥测(痕迹和指标)数据,以便为不同的场景提供更多选项。SkyWalking探针覆盖率几乎达到100%,几乎覆盖了 所有的技术栈,全链路监控,探针覆盖率也是一个比较重要的指标。

    2.2.4 Openzipkin

    微服务框架SpringCloud已经整合了openzipkin,有现成的链路解决方案,底层框架直接使用Springboot,如果是为了节约开发成本,可以直接截取S pring-Cloud-Sleuth某一个里程碑版本,维护起来,并架构演化为自研链路框架。

    Spring Cloud Sleuth为Spring Cloud实施分布式跟踪解决方案,大量借用Dapper,Zipkin和HTrace。 对于大多数用户来说,探针应该是无感知的,并且所有与外部系统的交互都应该自动进行检测。 您可以简单地在日志中捕获数据,也可以将数据发送到远程收集器服务。

    Span是基本工作单元。 例如,发送RPC是一个新的跨度,就像RPC发送响应一样。 跨度由跨度的唯一64位ID和跨度为其一部分的跟踪的另一个64位ID标识。 Spans还有其他数据,例如描述,键值注释,导致它们的跨度的ID以及进程ID(通常是IP地址)。 跨度启动和停止,他们跟踪他们的时间信息。 创建跨度后,必须在将来的某个时刻停止它。 一组跨度形成一个称为Trace的树状结构。 例如,如果您正在运行分布式大数据存储,则可能会由put请求形成跟踪。将跟踪和跨度ID添加到Slf4J MDC,因此您可以从日志聚合器中的给定跟踪或跨度中提取所有日志;提供对常见分布式跟踪数据模型的抽象:跟踪,跨距(形成DAG),注释, 键值注释。 松散地基于HTrace,但兼容Zipkin(Dapper);探针常见的入口和出口点来自Spring应用程序(servlet过滤器,休息模板,预定动作,消息通道, zuul过滤器,假装客户端);如果spring-cloud-sleuth-zipkin可用,则该应用程序将通过HTTP生成并收集与Zipkin兼容的跟踪。 默认情况下,它将它们发送到localhost(端口9411)上的Zipkin收集器服务。 使用spring.zipkin.baseUrl配置服务的位置

    2.2.4 Pinpoint

    Twitter的 Zipkin 使用修改过的类库和它自己的容器(Finagle)来提供分布式事务跟踪的功能。但是,它要求在需要时修改代码。我们期望功能可以不修改代码就工作 并希望得到代码级别的可见性。为了解决这个问题,pinpoint中使用了字节码增强技术。Pinpoint agent干预发起RPC的代码以此来自动处理标签信息。

    字节码增强在手工方法和自动方法两者之间属于自动方法:

  • 手工方法: 开发人员使用ponpoint提供的API在关键点开发记录数据的代码 

  • 自动方法: 开发人员不需要代码改动,因为pinpoint决定了哪些API要调节和开发 每个方法的优缺点

    跟踪方式优点缺点
    手工跟踪1. 要求更少开发资源 2. API可以更简单并最终减少bug的数量1. 开发人员必须修改代码 2. 跟踪级别低
    自动跟踪1. 开发人员不需要修改代码 2. 可以收集到更多精确的数据因为有字节码中的 更多信息1. 在开发pinpoint时,和实现一个手工方法相比 ,需要10倍开销来实现一个自动方法 2. 需要更高能力的开发人员,可以立即识别需要 跟踪的类库代码并决定跟踪点 3. 增加bug发生的可能性,因为使用了如字节码 增强这样的高级开发技巧

    字节码增强是一种高难度和高风险的技术。但是,综合考虑使用这种技术开发需要的资源和难度,使用它仍然有很多的益处。虽然它需要大量的开发资源,在开发服务上它需要很少的资源。

  • 字节码增强的价值:

  • 隐藏API

  • 容易启用或者禁用

  • 由于字节码增强技术处理java字节码, 有增加开发风险的趋势,同时会降低效率。另外,开发人员更容易犯错。在pinpoint,我们通过抽象出拦截器(interceptor)来改进效率和可达性(acc essibility)。pinpoint在类装载时通过介入应用代码为分布式事务和性能信息注入必要的跟踪代码。这会提升性能,因为代码注入是在应用代码中直 接实施的。在pinpoint中,拦截器API在性能数据被记录的地方分开(separated)。为了跟踪,我们添加拦截器到目标方法使得before()方法和after() 方法被调用,并在before()方法和after()方法中实现了部分性能数据的记录。使用字节码增强,pinpoint agent可以记录需要方法的数据,只有这样采样数据的大小才能变小。

    2.3 项目优势

    项目开发的生命周期和上线之后维护的生命周期是否活跃,主要取决于项目立项之初的项目优势,假想项目优势如下:

  • 高效落地

  • 业务无侵入

  • 符合2-8原则(投入与产出)

  • 探针覆盖率高

  • 平台可扩展性

  • 数据可定制开发

  • 社区活跃度高

  • 技术栈匹配(技术二次投入调研成本低)

  • 整洁架构

  • 2.4 项目成本估算2.4.1 技术调研成本

    技术调研耗时:一人/5d,调研开源的主流的APM框架,考究是否支持OPENTRACING规范,以及技术借鉴成本。

    2.4.2 技术方案设计成本

    可以落地的技术方案设计成本:预估一人/5d 可以落地链路设计的基础架构搭建,以及预评估的可用插件的植入(不包含全部)

    2.4.3 技术方案评审成本

    技术方案评审讨论:头脑风暴、集思广益,结合业务场景的最佳解决方案,预估2d

    2.4.4 技术方案落地成本

    技术方案一期落地成本:按照以前做全链路的经验,全职开发前后端配合,60d

    2.4.5 技术方案落地成本

    项目实施成本主要是部门沟通和链路项目上线对业务系统影响面的评估

    2.4.6 项目推广成本

    分享和布道成本

    2.5 项目风险
  • 开发人力资源分配成本风险

  • 项目协调沟通成本风险

  • 方案落地成本风险

  • 2.6 全链路架构详细设计2.6.1 松耦合方案整体设计

    框架模块功能:

  • Instrumented-client-plugin 主要包括日志采集探针模块:比如Dubbo、Redis、Http、mysql、Rocketmq、Rabbitmq等插件 

  • Instrumented-server-plugin 主要包括日志采集通道模块:比如Http、Netty、Grpc、Kafka等插件 

  • Collector模块主要包括:Http、Netty、Grpc、Kafka服务端组件以及存储服务端插件 

  • Server模块:存储客户端插件,查询聚合模块

  • 2.6.1 AGENT方案整体设计

    Agent方案主要是将Instrumented-client-plugin和Instrumented-server-plugin和业务解耦,全部植入到agent组件中,对业务完全无感知。 整体设计如下:

    模块功能:

  • Collector:服务端通道模块、存储插件模块 

  • Server:前后端分离(UI、Query) 

  • Application:探针、agent、client 调研的公司目前的链路系统,应该是采用agent方案,可能数据传输通道和收集器逻辑可能有点不太一样,看针对原有的架构设计,从架构层面是否有优化的空间

  • 2.7 全链路领域模型设计

    基于openTracing规范: trace和traceId:trace是全局监控系统的一次跟踪(用traceId标示一次跟踪,贯穿整个跨进程请求),多个span信息,及其关系信息。

  • trace和traceId:trace是全局监控系统的一次跟踪(用traceId标示一次跟踪,贯穿整个跨进程请求),多个span信息,及其关系信息。 

  • span:一个span代表系统中具有开始时间和执行时长的逻辑运行单元。span之间通过嵌套或者顺序排列建立逻辑因果关系,包含logs和tags。

  • Logs:每个span可以进行多次Logs操作,每一次Logs操作,都需要一个带时间戳的时间名称,以及可选的任意大小的存储结构。

  • tags: 每个span可以有多个键值对(key:value)形式的Tags,Tags是没有时间戳的,支持简单的对span进行注解和补充,在一个span的生命周期 有效不能跨越span传递。

  • SpanContext: SpanContext跨越进程边界,传递到下级span的状态。(例如,包含traceid, spanid, sampled、baggage等数据),并用于封装Baggage.

  • Baggage: 存储在SpanContext中的一个键值对集合,在整个trace链路生命周期有效,可以跨越span、跨越进程进行传递.

  • ActiveSpan: 当前线程的活跃Span,对Span做了封装,也可以理解为一个Span的指针.

  • inject: SpanContext要做跨进程(如RPC)传输的时候,把SpanContext中的数据序列化到传输协议中。

  • extract: 与inject对应,从传输协议里,抽取数据反序列化成SpanContext。

  • 2.8 模块详细设计2.8.1 耦合探针

    设计描述:

  • 探针主要是要植入opentracing-api到宿主组件,并形成树形链路 

  • 探针的复杂性在于,每个组件都要封装,并且应用探针的覆盖率也是一个重要的考量指标

  • 2.8.1.1 dubbo

    重写dubbo filter,为每个应用包装ConsumerFilter和ProviderFilter,植入opentracing-api到dubbo,串联dubbo链路

    2.8.1.2 SpringMvc

    AOP切面,拦截注解@Controller和@ResetController,植入opentracing-api,拦截before和after,串联SpringMvc链路

    2.8.1.3 SpringService

    AOP切面,拦截注解@Service,植入opentracing-api,拦截before和after,串联SpringService链路

    2.8.1.4 线程池和线程

    统一线程和平台线程池,通过方法重载和反射植入opentracing-api,拦截before和after,串联线程链路

    2.8.1.5 消息中间件

    AOP侵入客户端

    2.8.1.6 agent

    agent也需要探针,只是探针逻辑被封装到了 agent,作为agent的个性化模块,独立于agent的基础模块之上。 

    agent设计原则:

  • agent针对应用和插件组合级别设置日志级别

  • 采样率可以细化到应用和插件的组合级别

  • 采样率可以细化到应用和插件的组合级别 

  • agent探针开关细化到应用和插件级别,探针开关细化,可以灵活的控制高并发流量下,某些探针流量在应用级别负载过高,但是容易造成 链路信息缺失,查询聚合会形成断路,在极端情况下,可以打开细粒度开关,保证业务的高可用 

  • agent重新造轮子的技术成本是蛮高的,可以复用开源的agent解决方案,避免重复造轮子,agent需要开发字节码框架,兼容不同的java版 本的差异性,需要对java字节码及虚拟机底层有更加深入的研究

  • 2.9 技术关键点突破设计2.9.1 如何保证链路的完整性
  • 分析公司现有业务场景:云上项目和内部项目占比,评估项目流量,数据量日存储达到TB级别以上(实际机 器的整体性能评估),可以切换为拉模式,数据量不是特别大的系统采用消息推模式,实时性比较高。拉模式:解 决方案是在埋点时输出日志到本地,通过日志Agent读取日志,然后再通过实时计算的处理层主动拉取日志再进 行处理。该方案直接复用应用机器存储日志,并且采用拉模式防止流量冲击过大。 推送模式:解决方案利用消息队 列的方式,埋点层主动发送消息,消息队列对消息进行存储,数据处理层从消息队列上订阅消息。这种方案可做 到数据不丢,且主动推送可以提高实时性,环境适应性强,但这种解决方案的成本是比较高的。拉推模式的灵活 切换,从流量入口确保高并发和高流量场景下,链路数据的整体完整性,从技术层面确保链路数据不丢失。

  • 链路数据丢失业务场景:不管是推/拉模式都不能确保数据完全不丢失,软件故障或者硬件故障都可能造成数 据丢失。设计解决方案:1) 硬件故障,数据丢失不可恢复,可以定期进行日志异步备份,保证数据不是完全丢失,可以恢复一部分,agent 读取可以动态路由到备份硬盘,拉取冗余数据,恢复丢失链路。2)软件故障,比如,网络抖动,在通道层面消 息丢失,导致链路完整性(因果关系)被破坏,链路因果关系缺失,极端情况会导致本来属于一个作用域(Trac eId)的span,被分割成不同的作用域,数据完全被隔离,特别是异步业务场景,如果都出现软件故障,如上问 题必现。

  • 2.9.2 如何通过agent完全与应用隔离,如何做到通过agent做负载,agent分布式部署
  • agent和应用耦合在一台机器,或者是同一个虚拟机下面,对运维的技术考究成本比较低,就是做CI/DI自动化部署(包括docker化),要在每台 机器上安装agent比较麻烦。 存在如下缺陷:1)如果应用是物理机隔离,再集群化,这样agent设计比较简单 2)如果针对应用是虚拟机隔离(docker也可以进行虚拟机隔离),agent考究兼容性 3)如果应用是云上部署,云上和内部系统之间agent的兼容性,也要考究。其实agent和应该耦合在一块,需要考究的技术成本也是蛮高的。 agent做负载,agent分布式部署技术门槛比较高,技术考究主要是在二次通信的性能损耗上,比如从application→agent切换为application-->RPC- ->agent,需要评估RPC的性能损耗和agent集群化之后,集群的整体吞吐量以及对业务性能的影响因子之间的总体对比和考究,还有agent是否会成 为数据流转的性能瓶颈的考究,以及集群部署之后的agent的路由规则,约定大于配置,这个只要和业务约定好,把麻烦留给框架,把傻瓜式配置留 给业务。

  • 2.9.3 如何回溯链路节点状态,快速的定位到某一个出问题的链路事件单元span
  • 引入链路全流程排查引擎,快速定位和回溯问题源。 全流程排查引擎:实际业务异常问题排查,比如线上某次系统调用异常,业务方需要追踪到具体的某一笔订单以及某一笔订单操作的某一个服务实 例的具体某一个探针方法,更变态的是要追踪到这笔异常订单是否由公司的某一个供应商的商品的具体某一个sku属性引起的,或者是正常情况下, 商品运营针对异常订单关联商品的操作链路追踪。在实际问题排查中经常会遇到如上描述的问题,这些问题都具有明确的业务含义,这些问题尽管 看上去和调用链并无关系,但可以用调用链得到很好的解决。在实际排查问题时,最有价值的切入点在于先从业务问题出发,再进一步在调用链中 确认问题所在之处。 我们可以根据业务时间ID反查调用链,从而顺藤摸瓜找到更多的上下游业务信息。例如一个交易订单(2135897412389123)发现存在问题,我们 可以根据订单号查到与之绑定的TraceId,根据TraceId不仅可以查看系统调用的事件,还可以看到与业务相关的事件,如用户下单、当前库存情况 等,也就是说根据交易ID可以在调用链上查看交易、商品库存以及支付等信息,大大提升错误排查速度。

  • 全流程排查引擎的关键在于:业务主键id与TraceId/RpcId的双向绑定。(提供个性化装饰器入口给业务,让业务自定义排查引擎主键,主键最好 唯一,也可以组合唯一,业务探针解决方案)

    常见的双向绑定有三种实现方式:

  • 在调用链的Tags 或UserData 中放入业务事件id,从而建立调用链到业务事件id 的关联;

  • 打通TraceId 到数据库的数据变更的关联,从而建立调用链到每次数据变更的关联;

  • 在业务日志中记录TraceId、业务事件id 等信息,从而建立调用链与业务事件日志的关联。(估计现在公司使用的这种方式)

  • 全流程排查引擎。核心部分是链路最初覆盖的的后端系统,包括服务、消息和缓存;在前端层面涉及前端用户访问日志,具有关联TraceId的能力 ;在移动端也具有关联TraceId的能力;通过对TraceId进行关联,可以打通用户访问日志;在数据库层面,通过SQL语句将TraceId传到数据库的binl og中,在数据复制和数据分发时可以非常容易获取到每次数据变更的记录与TraceId的关联;另外,业务通过自身的业务日志和异常堆栈也可以打印 TraceId;这样一来,业务层、移动端、前端、数据层所有的组件都与TraceId进行了关联,再关联上业务中的订单号、用户号、商品号、物流单号 、交易单号,最后形成一个非常强大的生态——从一个调用链可以看到上下游相关的订单、用户的详细信息,同时可以根据订单查到与该订单相关 的业务ID,再根据业务ID扩展到与其相关的更多ID,甚至是TraceId,最后形成TraceId-->业务ID-->新的TraceId的网状结构,将排查问题转化为从 网状结构中寻找需要的整段信息。

    2.9.4 如何减少渠道通信的性能开销

    渠道通信性能开销点:数据传输格式、序列化框架、承载数据的RPC框架,异步kafka和Rocketmq

    2.9.5 如何减少application和agent之间的通信开销

    通信由TCP→UDP,提高吞吐量。

    2.9.6 提高系统的QPS和TPS,底层服务端改用go语言,go天生的并发神器语言,要比java简单

    缺少技术栈储备,难点比较大。

    2.9.6 链路从支持单一的树状结构到DAG(有向无环图)支持并行链路数据结构的存储

    链路模型支持树和有向无环图两种数据结构。

    2.9.7 RectUI

    不能重复造轮子,第一期版本可以参照https://github.com/jaegertracing/jaeger-ui.git,将开源项目维护起来变为自研。

    2.10 项目实施方案

    项目内部系统功能测试和压力测试通过之后,就要考虑项目如何在业务系统中实施,初步计划方案如下:

  • 全链路系统部署必须申请单独的机器,与业务系统隔离

  • 如果用到kafka,线上要单独部署,以及部署单独的zk集群,与业务隔离 

  • es集群,如果条件允许,要单独部署,日志采集,属于高流量业务场景,对es的冲击量很大,必须要与核心业务的隔离,必须保证业务的 高可用

  • 大数据流式实时计算,比如按应用名称+时间域,预先聚合数据,不要直接通过es在内存中聚合计算,耗时耗资源 

  • collector服务无状态,如果条件允许可以docker化,做到线上弹性伸缩,可以节省机器资源和提高日志采集的高可用和高并发性能 

  • 链路实施必须要加全局开关,防止链路系统冲垮业务系统

  • 线上链路系统采样率必须要动态可配置,灵活的根据业务流量动态切换

  • 2.11 项目版本演化方案

    项目版本演化

  • 初始化测试开发版本1.0.0.SNAPSHOT,线上发布版本1.0.0.RELEASE

  • git issues统计并记录,并与感兴趣的参与者贡献代码

  • 里程碑版本 

  • 建立全链路推广钉钉群,定期同步版本发布信息,以及业务方使用的问题反馈,提高全链路的业务用户体现。 

  • 新特性和新插件,统一同步到度量系统,并指定链路系统的开发负责人以及问题解决人。

  • 2.12 项目推广方案

    前期投入大量的人力研发全链路监控框架,推广其实是项目落地的最后手段。

    推广阶段

  • 全链路知识体系普及分享,讲解全链路项目的优势以及能够解决的业务痛点 

  • 全链路接入方案和部署方案讲解,接入和部署透明化,让业务知道可能存在的风险点 

  • 链路压测报告输出,并同步给各个部门leader 试点项目,评估全链路项目的用户体验,以及对业务排查问题的效能是否已经提高 

  • 度量系统,度量全链路系统的用户体验,可视化,输出同步给业务线负责人

  • 大批量接入应用,评估链路系统的存储模块性能和React UI的聚合查询性能指标 

  • 新特性版本演化

  • Java|全链路监控



    前言



    随着分布式技术的发展与演进,微服务技术成为了大型分布式IT架构的必然选择。从本质上来讲,微服务是一种架构风格,将一个大型的系统拆分为多个拥有独立生命周期的应用,应用之间采用轻量级的通信机制进行通信。这些应用都是围绕具体业务进行构建,可以独立部署、独立迭代,也可能根据业务负载独立的水平扩展。微服务思想以及相关的技术为IT架构的发展带来了一系列深刻的变革。

    微服务技术让IT系统变得更敏捷、更健壮、更高性能的同时,也给带来了架构复杂度的提升,给应用监控带来了前所未有的挑战。在微服务时代,由于服务的拆分,单个用户请求会经过多个微服务应用,形成复杂的调用链路,使传统的依赖于单机业务日志的监控手段无从下手,这就需要建立全新的监控机制,帮助开发者全面洞察系统运行状态,并在系统遇到异常的时候快速的定位和解决问题。


    什么是全链路监控?



    在分布式微服务架构中,系统为了接收并处理一个前端用户请求,需要让多个微服务应用协同工作,其中的每一个微服务应用都可以用不同的编程语言构建,由不同的团队开发,并可以通过多个对等的应用实例实现水平扩展,甚至分布在横跨多个数据中心的数千台服务器上。单个用户请求会引发不同应用之间产生一串顺序性的调用关系,链路的概念就此诞生。

    Java|全链路监控

                               
    图:微服务链路

    随着业务规模的增长,不但来自于前端用户的请求频度会增加,链路也变得更长,这也代表着应用之间的调用关系变得越来越复杂。为了提升微服务系统在复杂链路下的健壮性和稳定性,有 3 个关键诉求需要我们去解决:

    1、如何梳理整套系统的调用关系,并评判应用上下游依赖的合理性?

    2、如何了解每一个应用的性能指标,并对系统容量进行合理的规划?

    3、当系统出现故障或异常的时候,如何第一时间发现问题、定位问题、解决问题?


    这3个关键诉求的核心挑战,都来源于应用之间复杂的链路。如果有一套成熟易用的机制,对每一条链路的行为进行记录,并进行深入的分析,提取出有价值的参考数据,就能让这些难题迎刃而解,这个重要的机制就是全链路监控。


    标准与规范



    十年前,Google 成为了分布式系统链路追踪服务的先行者,并通过《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》这篇著名论文阐述了如何在超大规模系统上建设低损耗(low overhead)、应用级透明(application-leveltransparency)、大范围部署(ubiquitous deployment)的链路追踪服务。


    Java|全链路监控

    图:一个链路完整的数据流转
     
    Dapper 阐述了对分布式系统进行链路追踪的技术细节,包括数据表示、埋点、传递、收集、存储与展示等方面,并提出了跟踪树、Span、Trace、Annotation 等重要概念,为全链路监控提供了理论指导。

    Java|全链路监控

    图:一个跟踪树里面5个Span的实时关系
          
    在 Dapper 的启发下,业界诞生了很多用于分布式链路追踪的开源组件,为了保持对链路中每一个环节的记录与匹配,不仅需要在应用内部对跟踪信息进行传递,还需要让跟踪信息跨越不同的应用以及不同的分布式组件。这需要制定一套统一的标准,让微服务体系中的所有应用遵循这套标准来实现跟踪信息的描述和传递,这套标准就是 OpenTracing。OpenTracing 抽象出一套与编程语言以及业务逻辑无关的接口,对链路追踪领域各类元素的统一管理,从而实现完整的全链路监控。

    本文不会深入介绍 Dapper 和 OpenTracing 的原理以及技术细节。我们只需要知道,优秀的全链路监控组件会尽可能的遵循 OpenTracing 标准,以获得更好的通用性以及扩展性。

          

    可选方案



    全链路监控组件如何获得链路相关的信息呢?最简单的方式是让开发者在业务代码中手工埋点,生成符合 OpenTracing 标准的链路信息,并汇入全链路监控组件。但手工埋点的方式要求开发者主动配合,并在业务代码中嵌入大量非业务逻辑。这样的方式是极为脆弱的,开发者稍有疏忽就会导致链路信息丢失,甚至影响到正常的业务逻辑。所以非手工埋点的自动链路信息采集,成为了业界的主流,其中包括两种实现方式:


    SDK 方式: 通过引入链路追踪 SDK 自动生成链路数据,并自动上报。对于底层框架没有公开API的情况,监控逻辑的注入会比较复杂,有可能需要开发者针对具体的底层框架预先做好适配工作。

    探针方式: 探针方式不需要在代码编译前引入 SDK ,而是在应用运行的过程中,通过一个 Agent 动态的拦截底层框架的行为,从而自动注入监控逻辑。像 Java 这样的编程语言可以通过字节码增强技术实现探针方式的链路信息采集。这是一种最开发者最友好的方式,不需要任何代码层面的改动,但并不是每一种编程语言都能提供探针机制,因此 SDK 方式也被很多全链路监控组件采用。
     
    不管是 SDK 方式还是探针方式,非手工埋点形式的链路信息采集都依赖于链路追踪组件对于底层框架的识别。这些底层框架包含的领域非常广,其中包含应用对外提供服务所需要的框架,应用进程内部的通讯框架,应用之间相互访问所需要的框架,应用访问外部系统所需要的框架等等。比如在 Java 体系中,用于提供 HTTP 服务的Tomcat、Jetty,用于进程内部通讯的RxJava,用于微服务应用之间相互调用的Feign,用于访问外部系统的 MyBatis、MySQL JDBC、HTTPClient,都属于这个范畴。对于多种编程语言以及种类繁多的底层框架的适配,是一项浩大的工程,一个全链路监控方案能够适配的底层框架越多,它的能力就越强大。

    Java|全链路监控

    表格:Java应用需要支持的基本组件和框架
     
    基础链路信息收集上来之后,需要进行统一存储,并对数据进行清洗与聚合,根据应用响应时间、请求数、错误率等指标进行下钻分析,并按应用、接口、链路、事务等多个维度进行展示,这也是一项非常复杂的工作。

    因此,全链路监控方案的技术门槛是非常高的,在开源的全链路监控产品中,真正遵循 OpenTracing 标准,又够被广泛认可和使用的产品非常少,其中通过 SDK 方式接入的产品以 Jaeger 为代表,通过探针方式接入的产品以 Skywalking 为代表。
     

    Java|全链路监控

    图:Jaeger技术架构
     

    最轻松的方案



    开源的全链路监控方案能帮助开发者更深入的理解全链路监控的思想、原理以技术细节,但在在生产环境大规模使用开源方案,还是会给开发者带来很大的挑战:


    维护工作复杂:除了客户端的SDK和探针外,一套全链路监控方案在服务端有计算组件、存储组件、展示组件,都需要单独进行维护。以Jaeger为例,仅在数据存储方面需要维护一套独立的Elasticsearch集群,需要投入很大的工作量。

    功能简单:对主流底层框架的全面支持,丰富的UI界面,完善的诊断机制和报警机制,这些都是一套优秀的全链路监控方案所必备的特质。开源方案在这些方面很难做到尽善尽美。

    缺少高可用保障:开源全 链路监控方案并没有完整的高可用机制,当某个组件出现故障,比如服务器宕机的时候,无法自动恢复,需要人工介入进行解决,在这个过程中正常的监控会受到影响。

    无法支撑大规模场景:当接入的应用数量达到上千个之后,开源全链路监控方案会暴露出各种性能问题,需要开发者修改源代码进行针对性的优化。

    影响正常业务:如果 SDK/探针存在设计上的缺陷,有可能导致应用出现不可预知的故障。这种情况极为 罕见,但一旦发生,后果会非常严重,这种情况下一般也只能等待开源社区将问题修复后才能恢复使用。

    之所以在生产环境使用开源全链路监控方案存在这么大挑战,是因为这些方案本身缺乏大规模实际业务场景的验证。对于技术实力非常强的互联网企业,会有专门的技术团队负责全链路监控项目,在使用开源产品的过程中如果遇到任何问题,都可以通过自身的技术实力进行修复和弥补。但对于绝大多数使用者而言,这些挑战所带来的都是漫长而痛苦的体验。

    有没有一套经历过大规模实际业务场景验证,又简单易用的全链路监控产品呢? 在云计算时代这个问题的答案是肯定的,阿里云ARMS就能满足这个要求,代表着业界在全链路监控以及应用性能管理领域的最高水平。

    Java|全链路监控

    图:ARMS定位问题
     
    应用实时监控服务ARMS(Application Real-Time Monitoring Service)起源于阿里巴巴内部的EagleEye(鹰眼)系统,已经经历了近10年的沉淀和演进。鹰眼 系统同时将基础设施层、分布式应用层、业务逻辑层与客户端层进行了全链路跟踪,每天对万亿级别的分布式调用进行分析,对底层的流计算、多维时序指标与事件存储体系等进行了大量优化,同时引入了时序检测、根因分析、业务链路特征等技术,将问题发现与定位由被动转为主动。

    在ARMS的理念中,对全链路监控的理解已经超出了一般意义上APM(应用性能管理的范畴),而是把“可观测性”作为产品的最重要使命。可观测性是一切自动化决策的基础,求最终目的是为一个复杂分布式系统所发生的一切给出合理解释。

    正是因为经历了大规模生产环境的长期验证,才使 ARMS 能够在易用性、功能性、稳定性方面做到极致,以开源领域最活跃的全链路监控项目 Skywalking 为例,我们可以从多个维度对两个产品进行对比:

    对比维度
    阿里云ARMS
    Skywalking
    Agent 稳定性
    链路压缩/编码/内存控制等手段保障,长时间稳定运行
    大规模场景下,稳定性无法保障
    数据准确性
    采样 + Agent端预聚合
    (指标绝对精准)
    采样(基于采样后数据统计,误差大)
    使用成本
    服务端全托管,免运维,与云产品一键集成,无需手工安装
    手工安装+运维人力+机器开销
    调用链分析
    丰富的应用报表,支持上下游链路分析,下钻分析
    报表单一,缺少下钻分析能力
    主动诊断
    支持慢调用/慢SQL/异常/CPU高/内存溢出等多种典型问题的根因定位能力
    仅支持慢调用查询
    报警
    完善报警体系,对接钉钉/WebHook/Email/短信网关等
    不支持
    配置动态下发
    多样化应用参数动态调优,无需重启应用
    手工配置,需要重启应用生效
    接入来,我们就通过阿里云ARMS,开启轻松玩转全链路监控之旅。


    应用接入



    ARMS采用无代码侵入探针接入方式,对于应用接入只需要非常简单的几个步骤,以Java应用为例:


    1、开通ARMS服务:登录阿里云控制台后,打开ARMS产品主页,按照提示开通“应用实时监控服务试用版”,开通服务后会获得15天的免费产品试用。

    2、下载探针(Agent):在公网环境以及VPC内,都提供了探针的下载链接,可以直接参考ARMS台的提示进行操作。

    3、修改应用的启动命令:通过-javaagent挂载探针,并配置对应的license Key以及应用名。比如我们启动SpringBoot应用为例,启动命令为:

    java-javaagent:/{user.workspace}/ArmsAgent/arms-bootstrap-1.7.0-SNAPSHOT.jar-Darms.licenseKey={LicenseKey} -Darms.appName={AppName} -jar demoApp.jar

    其中,-javaagent后面的路径是探针文件所在的路径,arms.licenseKey可以从ARMS的控制台获得,appName代表应用的名字。在微服务应用中,一个应用可以拥有多个对等的应用实例,这些对等的应用实例接入ARMS的时候,使用同样的应用名,这样ARMS可以把这个应用的多个实例放到一个分组中进行统一管理。

    修改完应用启动命令后,对应用进行重启,就能够成功接入ARMS。如果在1分钟后,ARMS控制台的应用列表能够看到新的应用,就代表接入成功。

    当然,对于Tomcat等通过操作系统脚本启动的应用,不能直接修改应用启动命令来挂载ARMS探针,这个时候只要对启动脚本进行修改即可,以Tomcat为例,我们在setenv.sh中加入如下配置:

    JAVA_OPTS="$JAVA_OPTS-javaagent:/{user.workspace}/ArmsAgent/arms-bootstrap-1.7.0-SNAPSHOT.jar-Darms.licenseKey={LicenseKey} -Darms.appName={AppName}"

    更多的 Jetty 等更多通过 Web 容器启动的应用可以参考ARMS的帮助文档。

    对于部署在阿里云EDAS或者容器服务Kubernetes的应用,接入工作会更加的简单,ARMS已经和这些产品进行了集成,使用者都不需要下载ARMS的探针到应用所在的节点,可以直接在控制台进行一键式的批量操作。

    特别重要的一点是,ARMS支持混合云模式,所以并不要求接入的应用一定要部署在阿里云,不管应用部署在线下IDC还是其他的云,都可以统一接入ARMS。当然,需要确保在混合云模式下,应用与ARMS服务端之间的网络是畅通的。


    核心实践一:了解你的系统




    应用接入后,可以通过ARMS获得哪些重要的信息,从而帮助使用者更好的了解整个系统呢?我们可以从这几个方面入手:


    应用列表和全局拓扑


    在应用列表视图,我们能看到每一个应用的健康度以及最近10分钟对外服务的响应情况。如果应用的状态列亮红灯,代表此应用运行不健康,我们可以继续点击红灯查看ARMS此应用生成的诊断报告,以进一步分析应用不健康的原因。


    Java|全链路监控

    图:应用列表视图
     
    点击应用列表右上角的全局拓扑按钮,能够通过可视化界面观察所有接入ARMS应用的拓扑结构,这个界面清晰的展示了所有应用的上下游组件以及相应的调用关系,能够帮助使用者从全局角度深入理解整个微服务系统。


    Java|全链路监控

    图:全局拓扑结构

    理想的微服务应用只有不同层级之间的单向依赖,这种依赖的原则是高层应用依赖于低层应用。同层应用之间的相互依赖,或者低层应用依赖于高层应用都是违背这个原则的。假设我们在全局拓扑视图里面,找到了环状依赖关系,说明微服务应用之间的依赖关系不清晰,可以考虑对应用的层次结构进行重构。

    应用总览


    从应用列表进入应用总览页,首先呈现给使用者的是概览分析视图,在这个视图中,我们能够查询应用在指定时间的关键指标。右上角的时间段是一个非常重要的选项,使用者可以根据需要来修改此应用关键指标的采集时间范围(默认15分钟)。在ARMS的很多视图里面,都提供了这个选项,来帮助使用者查看指定时间范围的监控信息。


    Java|全链路监控

    图:应用关键指标
     
    应用在选定时间内的总请求量、平均响应时间、错误数、实时实例数、FullGC 次数、慢 SQL 次数、异常次数和慢调用次数,以及这些指标和上一天的环比、上周的同比升降幅度等信息,都能够在这个视图体现。我们可以重点关注应用应用提供服务和应用依赖服务栏展示的指标曲线,如果在某个时间点发生了突变,可以进行针对性的排查。比如在某一个时间点,一个应用对外服务接口的请求量突然变低,极有可能是其中的一个节点发生了故障,需要特别关注。对于在ARMS展示出来的任何一条以时间维度为横座标的指标曲线,都可以继续选择其中的时间段进行下钻分析,这也是一个非常便捷的功能。


    Java|全链路监控

    图:在指标曲线上选择时间段进行下钻分析
     
    在拓扑图页签上,可以通过拓扑图更加直观地看到应用的上下游组件以及与它们的调用关系。相比全局拓扑图,单应用拓扑图能够展示更多细节信息,帮助使用者分析应用的上下游调用情况,从而更快速地找出性能瓶颈。


    Java|全链路监控

    图:应用拓扑
     

    应用详情


    在应用详情视图中,能够基于应用整体的维度以及应用内单实例的维度查看更多详细的信息,包括JVM信息、主机信息、SQL调用分析、异常和错误分析等等。

    主机监控功能用于监控CPU、内存、Disk(磁盘)、Load(负载)、网络流量和网络数据包的各项指标。当我们遇到硬件或网络故障的时候,这些基础资源的指标数据将非常有价值。当应用部署在 Kubernetes 的时候,Pod 监控和主机监控能够分别从pod和宿主机维度分别对指标数据进行展示。

    JVM监控功能通过可视化页面展示应用的GC情况、内存详情、线程详情,完全可以代替JStat、JStack 等 JDK 自带的 JVM 分析工具。同样,在以时间为横坐的曲线图处,可以继续选中一个时间段进行下钻分析。


    Java|全链路监控

    图:应用情况 – JVM监控
     
    如果一个应用的多个对等实例中,某一个出现了故障,我们就能够非常迅速的发现这个实例在应用情况视图中呈现出来的状态信息和其他实例存在非常大的区别,这样有助于我们迅速找到故障实例,并进行相应的处理。
     

    接口调用 & 外部调用


    当一个应用对外提供多个服务接口的时候,如何从分析每一个接口的服务质量,以及每一个接口对应的链路详细情况呢?这个时候接口调用视图就能发挥重要的作用。从这个应用所有提供的接口中,我们可以选中需要分析的单个接口,与这个接口相关的链路信息就能够从多个维度展示出来,其中包括接口的请求数、响应时间、错误数、返回状态码,以及在接口所对应的链路中,应用访问外部数据库(包括关系型数据库,以及Redis等非关系型数据库)的情况。如果访问这个接口的上游应用也接入了ARMS,还能从链路上游页签查看每一个上游应用访问这个接口的请求数、响应时间和错误数。同样,如果这个接口对应的链路在离开这个应用后,还会继续访问接入了ARMS的下游应用,我们也能从链路下游页签查看到针对每一个下游应用的请求情况。


    Java|全链路监控

    图:接口调用
     
    我们需要记住,接口调用基于单个应用接口的维度,对链路信息进行提取并展示。当一个应用的某个接口存在问题的时候,我们能迅速通过这个功能定位这个有问题的接口。

    在外部调用视图中,会把下游应用每一个实例以IP+端口的形式进行呈现,我们可以通过这个视图快速定位下游应用是否有某个实例存在故障。


    核心实践二:快速定位故障源和性能瓶颈




    通过核心实践一介绍的功能,相信大家已经可以对整个微服务系统形成全面而深入的了解。接下来,我们需要在系统遇到故障或系统问题的时候,通过ARMS来迅速定位故障源和性能瓶颈。


    我们以某个业务功能出现卡顿现象为例,来说明如何通过ARMS一步一步的进行排查。这种情况发生的时候,往往来自于前端用户的反馈,直观的表现是前端用户在进行操作的时候,返回时间比较长,或者收到系统异常相关的提示。

    核查应用的整体健康状态


    首先,我们从自身对于整个系统架构以及业务架构的了解,能够知道当问题发生的时候,前端用户的请求在经过安全系统、负载均衡组件以网关后,最先发往哪一个微服务应用。站在微服务链路的角度,这个应用负责接收并处理最终用户的请求,是链路的发起点,可以简称为入口应用。

    通过全局拓扑和应用拓扑视图,我们能够知道这个应用依赖于哪一些下游应用,这样就确定了与这次问题有可能发生关联的应用名单。

    回到应用列表视图,我们能查看到这些应用的整理健康状态,最先应该关注的是应用的状态列,如果亮红灯,说明系统已经诊断到某个应用存在明显的健康问题,这个时候我们可以点击红灯图标,让ARMS生成一份应用诊断报告。通过应用诊断报告,能很快的知道这个应用在哪一个时间点发生了故障。比如ARMS判断故障是由应用的某一个实例导致的情况下,会把可疑实例在报告中报出,让使用者点击实例链接就能进入单实例的详情页面,从错误率、硬件资源、JVM等维度对故障进行排查。

    Java|全链路监控

          
    图:诊断报告

    如果在应用列表视图,并没有发现亮红灯的应用,我们可以从健康度百分比、请求数、错误数、异常数、最近10分钟响应时间等数据中,快速判断一下有没有比较明显的与实际情况存在出入的应用。比如在最近10分钟内,有一个应用从某一个时间点开始,响应时间明显变长,我们就可以把这类应用列入需要进一步进行分析的名单。
     

    分析应用统计信息


    通过前一个步骤,找到的可疑应用名单后,我们逐个点击应用名,进行应用总览视图,分析应用的关键指标。ARMS会收集和展示选定时间内应用的总请求量、平均响应时间、错误数、实时实例数、FullGC次数、慢SQL次数、异常次数和慢调用次数,以及这些指标和上一天的环比、上周的同比升降幅度。我们主要关注这一些信息的环比以及同比升降情况,还可以修改右面右上角的时间段,来调整统计时间范围。

    这些展示的数据中,如果我们发现有明显的可疑现象,可以点击数字上的链接,进入更详细的分析视图。例如:我们发现某个应用今天的错误数相比昨天存在400%的涨幅,但总请求量变化不大,就可以判断出这个应用非常值得怀疑。接下来,我们可以直接进入错误分析视图,来观察具体哪一个时间段的哪一些接口存在问题。

    Java|全链路监控

    图:错误分析视图
          
    在应用总览展示的数据中,最应该值得关注的是慢SQL数据。ARMS会记录应用访问数据库的情况,当发现应用存在大量慢SQL的时候,就可以直接给出判断:该应用在访问数据库的环节存在问题。我们可以从慢SQL分析视图找到到底是哪一条SQL存在问题,从而针对性的进行优化。对于慢SQL的定义,可以通过应用的自定义配置进行修改(默认执行时间超过500ms会标记为慢SQL)
     

    通过调用链锁定问题应用


    如果通过前两个步骤还没有找到问题的根源,就需要借助ARMS的核心能力—全链路排查了。

    我们先进入入口应用的接口调用视图,结束实际业场景,我们能够快速找到哪一个接口存在响应时间过长的情况。接下来,我们进入接口快照视图,在这个视图中,ARMS记录了每一次具体接口调用的情况,包括耗时、状态、以及对应的TraceId。按照耗时从大到小的顺序,对列表进行排序,就能够找到指定时间内耗时最长的调用。

    Java|全链路监控

    图:接口快照视图

    接下来就需要重点分析接口调用耗时过长的问题了。我们知道,接口调用耗时是应用自身的处理速度,加上下游所有环节处理速度,以及所有网络时延的总和。当应用存在下游依赖的时候,整个调用链路的任何一个环节耗时过高,都会影响到接口的整体耗时。在这种情况下,我们需要利用TraceId提取出调用链路上的所有环节,进行统一的排查。点击TraceId所代表的链接,呈现出来的调用链路视图,就能帮助我们快速锁定真正存在性能瓶颈的应用。

    Java|全链路监控

    图:调用链路视图

    在调用链路视图中,可以查看到整个调用链路中,所经历的每一个应用的调用类型、服务名、IP地址,以及耗时。通过右侧的时间轴,能一步定位到哪一个应用存在性能瓶颈。
     

    锁定有问题的代码


    找到有问题的应用后,接下来可以通过对方法栈的剖析,排查出真正存在问题的代码片段。点击放大镜图标,弹出的窗口中展示了这个应用为了处理接口请求所经过的方法列表。同样,通过右侧的时间轴能够迅速定位哪一个方法执行的速度与预期不符。至此,我们已经能够确定慢调用的源头,从而有效的进行下一步的代码优化工作。

    Java|全链路监控

    图:方法栈视图
     

    线程分析 & 内存快照


    找到有问题的代码片断之后,慢调用的根本原因是什么呢?ARMS能够对应用的线程以及内存快照做进一步的分析,为使用者优化代码提供思路。

    线程分析功能提供线程粒度的CPU耗时和每类线程数量的统计,并且每5分钟记录一次线程的方法栈并聚合,可真实还原代码执行过程。如果我们发现导致慢调用的关键应用存在CPU占用率高的问题,可以通过线程分析功能找到消耗CPU最多的线程。选中某一异常线程后,能够通过右侧的CPU耗时和线程数曲线图分析CPU耗时与线程数变化。此外,还可以单击异常线程的方法栈,查看指定时间内的此线程的方法执行情况,例如查看处于BLOCKED状态的线程对应的方法,从而优化指定代码段,以便降低CPU使用率。

    Java|全链路监控

    图:线程分析视图
          
    JVM监控可以直观展示指定时间段内的多项内存指标,虽然图表能体现出内存使用量过大的情况,但无法显示具体信息,因此如果需要进一步排查问题产生的原因,可以创建内存快照,通过详细的日志查看内存占用的详细信息,方便排查内存泄漏和内存浪费等内存问题。点击JVM监控页面的创建内存快照按钮,可以让ARMS在线为应用生成内存快照,并通过控制台在线对内存快照进行分析,从而避免将大体积快照文件回传到开发者的本地环境进行分析。如果我们发现在慢调用比较严重的时间点,GC频繁或者出现了耗时长的FullGC,对于内存快照的分析是必不可少的工作。

    内存快照创建后,点击分析结果,就能够进入内存快照在线分析页,这个页面集成了MAT(Eclipse Memory Analyzer)内存分析工具的所有功能,具体的用法和实践可以参考MAT手册。

    Java|全链路监控

    图:内存分析报告

          

    核心实践三:提前预知风险




    构建一个健壮稳定的微服务体系,不能总是等着有问题和故障暴露出来之后,再进行排查和优化,只有建立一个可以提前预知风险机制,才能帮助我们尽可能的避免问题发生。报警机制是实现风险提前预知的核心,ARMS可以制定针对特定监控对象的报警规则,当规则被触发时,会通过预先指定的报警方式向报警联系人分组发送报警信息,以提醒用户采取必要的问题解决措施。

     

    创建联系人


    报警规则被触发时会向指定的联系人分组发送通知,而在创建联系人分组之前必须先创建联系人。所以在创建报警规则前,我们需要预先确定报警的接收者,配置好联系人和联系人分组。

    我可以在报警管理 > 联系人管理页面创建联系人,指定联系人用于接收通知的手机号码和邮箱地址,也可以提供用于自动发送报警通知的钉钉机器人地址。
     

    创建报警


    在ARMS控制台可以制定针对特定监控对象的报警,当报警规则被触发时,系统会以指定的报警方式向报警联系人分组发送报警信息,以提醒用户采取必要的问题解决措施。

    报警覆盖了JVM监控、异常接口监控、调用类型统计、主机监控、数据库指标等多种类型,每一种类型都预定义了一系列的可选规则,允许使用者在一个报警中添加一条或多条规则。每一条规则都包含一条时间参数,代表报警基于最近多少分钟之内的统计结果,而多条规则之间可以是“与“或者”或“的关系。

    Java|全链路监控


    以数据库指标这种类型为例,我们可以定义一条这样的规则:”最近60分钟之内,如果应用的多个实例在访问数据库的时候,平均响应时间大于2000毫秒,便触发系统报警”.

    图:数据库指标报警规则示例
     

    为新上线的应用自动创建报警


    我们还可以定义多条报警模板,批量创建报警,提高配置报警规则的效率,具体的操作和创建报警类似。

    ARMS已经为我们默认定义了5条报警模板,以方便我们使用,在默认情况下,每一个新接入ARMS的应用都会被自动追加如下5条报警:
    Ø  数据库异常报警模板:数据库响应时间长或数据库调用出错场景的报警
    Ø  异常调用报警模板:存在超时调用或错误调用场景的报警
    Ø  主机监控报警模板:CPU 水位过高或磁盘空间不足场景的报警
    Ø  进程异常报警模板:进程存活场景的报警
    Ø  GC异常报警模板:有过多的 FullGC、FullGC 耗时长或 YoungGC 耗时长场景的报警

    这5条默认的报警模板很有用,代表着ARMS对于最通用的一些报警场景的抽象,我们保留这几个模板,只在细节方面做出少许调整,用最少的配置提升风险预知的能力。


    构建多语言全链路监控体系



    除了Java语言外,ARMS还提供了PHP探针,PHP应用接入ARMS后,能够拥有和Java应用同样的全链路监控体验。除了Java和PHP之外 ,ARMS还对主流的编程语言提供了支持,我们可以选择开源的探针/SDK接入ARMS。受益于统一的全链路监控模型,如果一个微服务体系中存在多种语言之间的相互调用,只要把对应的应用都接入ARMS,就能够跨越多语言对调用链路进行统一的管理和分析。


          
    图:ARMS支持的编程语言

    当然,开源探针/SDK在功能方面和ARMS探针还存在不小的差距,ARMS针对更多语言的探针正在陆续发布中,希望能够尽快覆盖所有的主流编程语言。目前阶段,我们可以参考以下表格,选择最合适的接入方式。

    语言
    首选接入方式
    备选接入方式
    Java
    ARMS探针
    Skywalking探针
    PHP
    ARMS探针
    Jaeger SDK
    Go
    Jaeger SDK
    Skywalking SDK (非官方版本)
    Python
    Jaeger SDK
    Skywalking探针
    Node.js
    Skywalking 探针
    Jaeger SDK
    .Net
    Skywalking 探针
    Jaeger SDK
    C++
    Jaeger 探针

    表格:各种主流语言的接入方式
     

    以上是关于架构师如何技术选型-全链路监控的主要内容,如果未能解决你的问题,请参考以下文章

    银行全链路日志监控难点详解

    01 . 美团全链路CAT简介及部署

    Java|全链路监控

    阿里P9架构师谈:高并发网站的监控系统选型比较核心监控指标

    来自滴滴微博唯品会魅族点评关于全链路压测等问题实践分享

    3 年PB级企业三高大数据全域中台架构设计与实践之路