目录
APM 系统概述
分布式链路追踪
什么是 OpenTracing
Skywalking 整体架构
Skywalking优势
Skywalking主要概念介绍
Skywalking 环境搭建
agent 的使用
RocketBot 的使用
配置覆盖
获取追踪ID
过滤指定的端点
告警功能
Java agent 原理
Skywalking 根据官方的解释,Skywalking是一个可观测性平台(Observability Analysis Platform简称 OAP)和应用性能管理系统(Application Performance Management 简称 APM)。提供分布式链路追踪、服务网格(Service Mesh)遥测分析、度量(Metric)聚合和可视化一体化解决方案。
APM 系统概述
APM(Application Performance Monitoring)即应用性能管理系统,是对企业系统即时监控以实现对应用程序性能管理和故障管理的系统化的解决方案。应用性能管理,主要指对企业的关键业务应用进行检测、优化、提高企业应用的可靠性和质量,保证用户得到良好的服务,降低IT拥有的成本。APM系统是可以帮助理解系统行为、用于分析性能问题的工具,以便发生故障的时候,能够快速定位和解决问题。
分布式链路追踪
随着分布式系统和微服务架构的出现,一次用户的请求会经过多个系统,不同服务之间的调用关系十分复杂,任何一个系统出错都可能影响整个请求的处理结果。以往的监控系统往往只能知道单个系统的健康状况、一次请求的成功失败,无法快速定位失败的根本原因。
除此之外,复杂的分布式系统也面临下面这些问题:
【1】性能分析:一个服务依赖很多服务,被依赖的服务也依赖了其他服务。如果某个接口耗时突然变长了,那未必是直接调用的下游服务慢了,也可能是下游的下游慢了造成,如何快速定位耗时变长的根本原因呢?
【2】链路梳理:需求迭代很快,系统之间调用关系变化频繁,靠人工很难梳理清楚系统链路拓扑(系统之间的调用关系)。
为了解决这些问题。Google推出了一个分布式链路追踪系统 Dapper,之后各个互联网公司都参照 Dapper的思想推出了自己的分布式链路追踪系统,而这些系统就是分布式系统下的 APM系统。
什么是 OpenTracing
分布式链路跟踪最先由 Google在 Dapper论文中提出,而 OpenTracing 通过提供平台无关、厂商无关的 API,使得开发人员能够方便的添加(或更换)追踪系统的实现。下图是一个分布式调用的例子,客户端发起请求,请求首先到达负载均衡器,接着经过认证服务,订单服务,然后请求资源,最后返回结果。
虽然这种图对于看清各组件的组合关系是很有用的,但是存在如下问题:
【1】不能很好的显示组件的调用时间,是串行调用还是并行调用,如果展现更复杂的调用关系,会更加复杂。
【2】这种图也无法显示调用间的时间间隔以及是否通过定时调用来启动调用。
一种更有效的展现一个调用过程的图:
基于 OpenTracing我们就可以很轻松的构建出上面这幅图。
Skywalking 整体架构
Skywalking 提供 Tracing 和 Metrics 数据的获取和聚合。
Metric 的特点是,它是可累加的:他们具有原子性,每个都是一个逻辑计量单元,或者一个时间段内的柱状图。 例如:队列的当前深度可以被定义为一个计量单元,在写入或读取时被更新统计; 输入 HTTP请求的数量可以被定义为一个计数器,用于简单累加; 请求的执行时间可以被定义为一个柱状图,在指定时间片上更新和统计汇总。
Tracing的最大特点就是,它在单次请求的范围内,处理信息。 任何的数据、元数据信息都被绑定到系统中的单个事务上。 例如:一次调用远程服务的RPC执行过程;一次实际的SQL查询语句;一次HTTP请求的业务性ID。
总结,Metric主要用来进行数据的统计,比如HTTP请求数的计算。Tracing主要包含了某一次请求的链路数据。详细的内容可以查看Skywalking开发者吴晟翻译的文章,Metrics, tracing 和 logging 的关系 :链接
整体架构包含如下三个组成部分:
【1】探针(agent)负责进行数据的收集,包含了 Tracing和 Metrics的数据,agent会被安装到服务所在的服务器上,以方便数据的获取。
【2】可观测性分析平台OAP(Observability Analysis Platform),接收探针发送的数据,并在内存中使用分析引擎(Analysis Core)进行数据的整合运算,然后将数据存储到对应的存储介质上,比如Elasticsearch、MySQL数据库、H2数据库等。同时OAP还使用查询引擎(Query Core)提供HTTP查询接口。
【3】Skywalking提供单独的 UI进行数据的查看,此时 UI会调用 OAP提供的接口,获取对应的数据然后进行展示。
Skywalking优势
Skywalking相比较其他的分布式链路监控工具,具有以下特点:
【1】社区相当活跃。Skywalking已经进入 apache孵化,目前的 start数已经超过11K,最新版本6.5.0已经发布。开发者是国人,可以直接和项目发起人交流进行问题的解决。
【2】Skywalking支持Java,.NET Core和Node.JS语言。相对于其他平台:比如 Pinpoint支持 Java和 PHP,具有较大的优势。
【3】探针无侵入性。对比 CAT具有倾入性的探针,优势较大。不修改原有项目一行代码就可以进行集成。
【4】探针性能优秀。有网友对 Pinpoint和 Skywalking进行过测试,由于 Pinpoint收集的数据过多,所以对性能损耗较大,而Skywalking探针性能十分出色。
【5】支持组件较多。特别是对 Rpc框架的支持,这是其他框架所不具备的。Skywalking对Dubbo、gRpc等有原生的支持,甚至连小众的 motan和 sofarpc都支持。
Skywalking主要概念介绍
服务(Service):一个独立的应用(Application);
端点(Endpoint):应用对外提供的接口;
实例(Instance):相同服务部署的节点就是实例,同一服务可以部署多个;
用户服务就是 Skywalking的服务(Service),用户服务其实就是一个独立的应用(Application),在6.0之后的 Skywalking将应用更名为服务(Service)。端点就是对外提供的HTTP接口。实例就是上述的192.168.1.100和192.168.1.101。
Skywalking 环境搭建
【链接】
agent 的使用
agent 探针可以让我们不修改代码的情况下,对 Java应用上使用到的组件进行动态监控,获取运行数据发送到 OAP上进行统计和存储。agent探针在 Java中是使用 Java agent技术实现的,不需要更改任何代码,Java agent会通过虚拟机(VM)接口在运行期更改代码。Agent 探针支持 JDK1.6-12的版本,Agent探针所有的文件在 Skywalking的 agent文件夹下。文件目录如下:
部分插件在使用上会影响整体的性能或者由于版本问题放置于可选插件包中,不会直接加载,如果需要使用,将可选插件中的 jar包拷贝到 plugins包下。
【1】Linux 下 Tomcat7和8中使用 Skywalking。编辑 catalina.sh文件,在文件顶部添加:
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar"; export CATALINA_OPTS
【2】Window 下只需要需改 tomcat目录 /bin/catalina.bat文件的第一行为:
set "CATALINA_OPTS=-javaagent:/path/to/skywalking-agent/skywalking-agent.jar"
【3】Spring Boot中使用:Skywalking 与 SringBoot集成提供了完善的支持。使用命令启动 SpringBoot项目
java -javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent_boot/skywalking-agent.jar -Dserver.port=8082 -jar skywalking_springboot.jar &
RocketBot 的使用
Skywalking 的监控 UI页面成为 RocketBot,我们可以通过 8080端口进行访问,由于 8080端口容易冲突,可以修改 webapp/webapp.yml 来更改启动端口;
server:port: 8080
本例中更改为9010端口防止冲突,访问 http://虚拟机地址IP:9010/ 打开 RocketBot界面
仪表盘:打开 RocketBot默认会出现仪表盘页面
拓扑图:查看应用之间的调用关系;
追踪:当某一笔调用出现了问题时,可以根据“列表”、“树结构”、“表格”三种形式查看具体哪个环节出了问题;
数据库的使用情况,可以查看sql执行的语句以及查询的时长。方便问题的查找;
配置覆盖
在之前的案例中,我们每次部署应用都需要复制一份 agent,需改其中的服务名称。可以使用 Skywalking提供的配置覆盖功能通过启动命令动态指定服务名,这样 agent只需要部署一份即可。Skywalking支持的集中配置方式:
系统配置(System properties)使用 skywalking. + 配置文件中的配置名作为系统配置项来进行覆盖。添加前缀的原因是因为,agent 的系统配置和环境与目标应用共享,所以加上前缀可以有效避免冲突。通过如下进行 agent.service_name的覆盖:
-Dskywalking.agent.service_name=skywalking_mysql
探针配置(Agent options),在指定 agent jar包后通过=键值对指定配置信息,例如:多个配置使用逗号分隔。如果配置中包含分隔符(,或者=)需要使用引号进行包裹。
-javaagent:/path/to/skywalking-agent.jar=agent.service_name=skywalking_mysql
系统环境变量(System environment variables)由于 agent.service_name配置项如下:如果在环境变量中设置了 SW_AGENT_NAME 的值,该值就会被指定为服务名。
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
覆盖优先级:探针配置>系统配置>系统环境变量>配置文件中的值
获取追踪ID
Skywalking 提供我们 Trace工具包,用于在追踪链路时进行信息的打印或者获取对应的追踪ID。首先需要在 pom.xml文件中添加 trace 工具包的依赖。
<skywalking.version>6.5.0</skywalking.version>
<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-trace</artifactId><version>${skywalking.version}</version>
</dependency>
不过这种方式的缺点是对代码有侵入。获取追踪ID的方法是:TraceContext.traceId(); 或者通过添加 @Trace 注解。
过滤指定的端点
在开发过程中,有一些端点(接口)不需要去进行监控,比如 Swagger相关的端点。这个时候我们就可以使用 Skywalking提供的过滤插件来进行过滤。
【1】在 agent 中的/agent/option-plugins/apm-trace-ignore-plugin-6.4.0.jar 插件拷贝到 plugins目录中。
【2】在启动应用时,添加 -Dskywalking.trace.ignore_path=/xxx 参数来表示需要过滤哪些请求,支持 Ant Path表达式:/path/*,/path/**,path/?(?匹配任何单字符 * 匹配0或者任意数量的字符 **匹配0或者更多的目录)
告警功能
Skywalking每隔一段时间根据收集到的链路追踪的数据和配置的告警规则(如服务响应时间、服务响应时间百分比)等,判断如果达到阈值则发送响应的告警信息。发送告警信息是通过调用 webhook接口完成,具体的 webhook接口可以自定义,从而开发者可以在指定的 webhook接口中编写各种告警方式,比如邮件、短信等。告警的信息也可以在 RocketBot中查看到。以下是默认的告警规则配置,位于 Skywalking安装目录下的 config文件夹下 alarm-settings.yml文件中:
rules:# Rule unique name, must be ended with `_rule`.endpoint_percent_rule:# Metrics value need to be long, double or intmetrics-name: endpoint_percentthreshold: 75op: <# The length of time to evaluate the metricsperiod: 10# How many times after the metrics match the condition, will trigger alarmcount: 3# How many times of checks, the alarm keeps silence after alarm triggered, default as same as period.silence-period: 10service_percent_rule:metrics-name: service_percent# [Optional] Default, match all services in this metricsinclude-names:- service_a- service_bthreshold: 85op: <period: 10count: 4webhooks:- http://127.0.0.1//alarm/test
metrics-name:指定的规则(与规则名不同,这里是对应的告警中的规则map,具体可查看https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/backend-alarm.md#list-of-all-potential-metrics-name,其中一些常见的,endpoint_percent_rule——端点相应半分比告警,service_percent_rule——服务相应百分比告警)
threshold:阈值,与 metrics-name 和下面的比较符号相匹配;
op:比较操作符,可以设定>,<,=,即如metrics-name: endpoint_percent, threshold: 75,op: < ,表示如果相应时长小于平均75%则发送告警;
period:多久检查一次当前的指标数据是否符合告警规则;
counts:达到多少次告警后,发送告警消息;
silence-period:在多久之内,忽略相同的告警消息;
message:告警消息内容;
include-names:使用本规则告警的服务列表 ;
自定义 WebHooks:
@RequestMapping("/alarm")
@RestController
public class AlarmController {@AutowiredAlarmService alarmService;@RequestMapping(value = "/test",method = RequestMethod.POST)public void alarm(@RequestBody List<AlarmMessageDto> alarmMessageList){System.out.println(alarmMessageList.toString());//具体处理告警信息alarmService.doAlarm(alarmMessageList);}
}
/**实体类"scopeId":1, //指的是告警的范围类型(源码中有定义常量org.apache.skywalking.oap.server.core.source.DefaultScopeDefine)"name":"gateway", //告警服务名称"id0":3, //与服务名称一一匹配"id1":0, //暂时未做使用 "alarmMessage":"Response time of service gateway is more than 1000ms in 3 minutes of last 10 minutes.","startTime":1569552742633 //告警发起时间戳
*/
@Data
public class AlarmMessageDto {private int scopeId;private String name;private int id0;private int id1;private String alarmMessage;private long startTime;
}
Java agent 原理
上文中我们知道,要使用 Skywalking去监控服务,需要在其 VM参数中添加 “-javaagent:/usr/local/skywalking/apache-skywalking-apm-bin/agent/skywalking-agent.jar"。这里就使用到了 java agent技术。
Java agent 是 java命令的一个参数。参数 javaagent 可以用于指定一个 jar包。这个 jar包的 MANIFEST.MF 文件必须指定 Premain-Class项。Premain-Class指定的那个类必须实现 premain()方法。当 Java虚拟机启动时,在执行 main函数之前,JVM会先运行 -javaagent所指定 jar包内 Premain-Class 这个类的 premain方法。
如果编写自己的 agent,使用 java agent 需要几个步骤:
【1】定义一个 MANIFEST.MF 文件,必须包含 Premain-Class选项,通常也会加入 Can-Redefine-Classes 和 Can-Retransform-Classes选项;
【2】创建一个 Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定;
public class PreMainAgent{public static void premain(String agentArgs, Instrumentation inst){System.out.println("premain执行:");}
}
【3】将 premain的类和 MANIFEST.MF 文件打成 jar包;
【4】使用参数 -javaagent:jar包路径 启动要代理的方法;