目录
分布式请求链路追踪_什么是ZipKin
分布式请求链路追踪_Docker搭建Zipkin服务
分布式请求链路追踪_Zipkin客户端搭建
分布式请求链路追踪_什么是SkyWalking
分布式请求链路追踪_SkyWalking核心概念
分布式请求链路追踪_什么是探针Java Agent
分布式请求链路追踪_Java探针日志监控实现之环境搭建
分布式请求链路追踪_Java探针日志监控实现之探针实现
什么是Zipkin
Zipkin是Twitter 的一个开源项目,它基于Google Dapper实现,它 致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包 括数据的收集、存储、查找和展现。
Zipkin4个核心的组件
1、Collector:收集器组件,它主要用于处理从外部系统发送过来的跟踪信息,将这些信息转换为 Zipkin内部处理的 Span 格式,以支持后续的存储、分析、展示等功能。
2、Storage:存储组件,它主要对处理收集器接收到的跟踪信息,默认会将这些信息存储在内存中, 我们也可以修改此存储策略,通过使用其他存储组件将跟踪信息存储到数据库中
3、RESTful API:API 组件,它主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是外接 系统访问以实现监控等。
4、UI:基于API组件实现的上层应用。通过UI组件用户可以方便而有直观地查询和分析跟踪信息
注意: zipkin分为服务端和客户端,服务端主要用来收集跟踪数据并且展示,客户端主要功能是发送给服务端,微服务的应用也就是客户端,这样一旦发生调用,就会触发监听器将sleuth日志数据传输给服务端。
实时效果反馈
1.zipkin主要作用_____数据。
A 服务熔断
B 负载均衡
C 收集并查看链路
D 链路追踪
为了搭建⼀条高可用的链路信息传递通道,我将使用RabbitMQ作为中转站,让各个应用服 务器将服务调⽤链信息传递给 RabbitMQ,而Zipkin 服务器则通过监听 RabbitMQ 的队列来 获取 调用链数据。相比于让微服务通过 Web 接口直连 Zipkin,使用消息队列可以大幅提高信息的送达率和传递效率。
安装RabbitMQ服务
docker run -d --name rabbitmq -e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest -p 15672:15672 -p 5672:5672 docker.io/macintoshplus/rabbitmqmanagement
下载Zipkin镜像
docker pull openzipkin/zipkin
启动容器
docker run --name rabbit-zipkin -d -p 9411:9411 --link rabbitmq -e RABBIT_ADDRESSES=rabbitmq:5672 -e RABBIT_USER=guest -e RABBIT_PASSWORD=guest openzipkin/zipkin
测试
此时可以访问zipkin的UI界面,
地址: http://192.168.66.101:9411,
界面如下:
最后,我们只需要验证消息监听队列是否已就位就可以了。我们使⽤ guest 账号登录 RabbitMQ,并切换到"Queues"面板,如果 Zipkin 和 RabbitMQ 的对接⼀切正常,那么你会在 Queues 面板下看到⼀个名为 zipkin 的队列。
三个服务添加依赖
首先,我们需要在每个微服务模块的 pom.xml 中添加 Zipkin 适配插件和 Stream 的依赖。其 中,Stream 是 Spring Cloud 中专门对接消息中间件的组件。
org.springframework.cloud
spring-cloud-sleuth-zipkin
org.springframework.cloud
spring-cloud-stream-binder-rabbit
配置文件需要配置一下zipkin服务端的地址,配置如下:
spring:
sleuth:
sampler:
# 日志数据采样百分比,默认0.1(10%),这里为了测试设置成了100%,生产环境只需要0.1即可
probability: 1.0
zipkin:
sender:
type: rabbit
rabbitmq:
addresses: 192.168.66.101:5672
queue: zipkin
测试 请求http://localhost:9527/order/index调用接口之后,再次访问 zipkin的UI界面
可以看到刚才调用的接口已经被监控到了,点击 SHOW 进入详情查看,如下图:
什么是SkyWalking
SkyWalking是中国人吴晟(华为)开源的一款APM工具是一个开源的可观测平台,主要用于收集,分析,聚合和可视化服务和云原生基础设施的数据。SkyWalking提供了一种简单的方式来维护分布式系统的视图关系,它甚至能够支持跨云的服务。 特别为微服务、云原生和基于容器(Docker, Kubernetes, Mesos)体系结构而设 计。
SkyWalkIng与ZipKin对比
Zipkin
Twitter公司开源的一个分布式追踪工具,被Spring Cloud Sleuth集成,使用广泛而稳定。
优点:
1、轻量级,SpringCloud集成,使用人数多,成熟
缺点:
1、侵入性
2、功能简单
3、欠缺APM报表能力(能力弱)
SkyWalking
SkyWalking是开源的一款分布式追踪,分析,告警的工具,现已属 于Apache旗下开源项目, SkyWalking为服务提供了自动探针代理, 将数据通过gRPC或者HTTP传输给后端平台,后端平台将数据存储在Storage中,并且分析数据将结果展示在UI中。
优点:
1、多种监控手段多语言自动探针,Java,.NET Core 和 Node.JS
2、轻量高效,不需要大数据
3、模块化,UI、存储、集群管理多种机制可选,
4、支持告警
5、社区活跃
缺点:
1、较为新兴,成熟度不够高
SkyWalking能够解决什么问题
1、SkyWalking提供了非常完善的分布式链路追踪功能
2、SkyWalking提供了非常完善的错误诊断功能
3、SkyWalking提供了非常完善的实时链路大屏功能
4、SkyWalking提供了非常完善的服务拓扑关系分析功能
5、SkyWalking提供了非常完善的链路指标及错误告警功能
6、SkyWalking提供了在线性能诊断功能
实时效果反馈
1.分布式链路追踪SkyWalking主要作用_____。
A 服务熔断
B 负载均衡
C 收集并查看链路
D 链路追踪
2.下列属于分布式链路追踪SkyWalking优点的是_____。
A 无代码侵入
B 多种监控手段多语言自动探针
C 支持告警
D 以上都是正确
注意:
1、宿主应用:被探针通过字节码技术引入应用。从探针的视角来看,应用是探针寄生的宿主。
2、探针:收集从应用采集到的链路数据,并将其转换为SkyWalking能够识别的数据格式。
3、RPC:宿主应用和平台后端之间的通信渠道。
4、平台后端:支持数据聚合、分析和流处理,包括跟踪,指标和日志等。
5、存储:通过开放的,可插拔的接口来存储SkyWalking的链路数据。 SkyWalking目前支持 ElasticSearch、H2、MySQL、TiDB、InfluxDB。
6、UI:一个可定制的基于WEB的界面,允许SkyWalking终端用户管理和可视化SkyWalking的链路数据。
实时效果反馈
1.下列不是SkyWalking支持的存储方式_____。
A ES
B MySQL
C H2
D Redis
探针产生的背景
在开发过程中,开发人员经常会使用IDEA的Debug功能(包含本地和远程)调试应用,在JVM进程期间获取应用运行的JVM信息,变量信息等。这些个技术通过Java Agent来实现的,那么Java Agent到 底是啥,为啥这么吊?
什么是探针
JavaAgent提供了一种在加载字节码时对字节码进行修改的方式。通 常使用ASM Javassist字节码工具修改class文件。
注意: javassist是一个库,实现ClassFileTransformer接口中的 transform()方法。ClassFileTransformer 这个接口的目的就是在class被装载到JVM之前将class字节码转换掉,从而达到动态 注入代码的目的。
Java探针工具技术原理
流程:
1、在JVM加载class二进制文件的时候,利用ASM动态的修改加载的class文件,在监控的方法前后添加计时器功能,用于计算监控方法耗时;
2 、将监控的相关方法和耗时及内部调用情况,按照顺序放入处理器;
3、处理器利用栈先进后出的特点对方法调用先后顺序做处理,当一个请求处理结束后,将耗时方法轨迹和入参map输出到文件中;
4 然后区分出耗时的业务,转化为xml格式进行解析和分析。
Java探针工具功能
1、支持方法执行耗时范围抓取设置,根据耗时范围抓取系统运行时出现在设置耗时范围的代码运 行轨迹。
2、支持抓取特定的代码配置,方便对配置的特定方法进行抓取,过滤出关系的代码执行耗时情况。
3、支持APP层入口方法过滤,配置入口运行前的方法进行监控,相当于监控特有的方法耗时,进行方法专题分析。
4、支持入口方法参数输出功能,方便跟踪耗时高的时候对应的入参数。
5、提供WEB页面展示接口耗时展示、代码调用关系图展示、方法耗时百分比展示、可疑方法凸显功能。
实时效果反馈
1.Java Agent Java代理,又叫____。
A Java探针
B 虚拟机
C 栈
D 以上都是错误
引入依赖
org.projectlombok
lombok
编写HelloController
@RestController
@Slf4j
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello agent";
}
}
打包SpringBoot项目
如何使用Java Agent
JDK1.5引入了java.lang.instrument包,开发者可以很方便的实现字节码增强。其核心功能由java.lang.instrument.Instrumentation接口提供。
Instrumentation 有两种使用方式:
1、在应用运行之前,通过premain()方法来实现,在应用启动时侵入并代理应用。
2、在应用运行之后,通过调用Attach AP和agentmain()方法来实现
注意: javassist是一个库,实现ClassFileTransformer接口中的 transform()方法。ClassFileTransformer 这个接口的目的就是在class被装载到JVM之前将class字节码转换掉,从而达到动态 注入代码的目的。
新建Maven项目javaagentdemo
Pom引入依赖
org.javassist
javassist
3.22.0-GA
javaagent
org.apache.maven.plugins
maven-shade-plugin
3.0.0
package
shade
com.tong.PreMainTraceAgent
Maven插件引入失败
在IDEA中使用maven-shade-plugin插件时会提示"Plugin 'maven-shade-plugin:' not found"
解决方法:
1、File -> Setting -> Build, Execution, Deployment -> Build Tools -> Maven -> 勾选Use plugin registry选项
2、File -> Invalidate Caches -> Invalidate and Restart
编写探针类TestAgent
package com.jenson;
import java.lang.instrument.Instrumentation;
/**
* @author Jenson
*/
public class TestAgent {
/**
* 在main方法运行前,与main方法运行于同一JVM中
*
* @param agentArgs agentArgs是premain函数得到的程序参数,随同"-javaagent"一同传入,
* 与main函数不同的是,该参数是一个字符串而不是一个字符串数组,
* 如果程序参数有多个,程序将自行解析这个字符串
* @param inst 一个java.lang.instrument.Instrumentation实例,由JVM自动传入,
* java.lang.instrument.Instrumentation是instrument包中的一个接口,
* 也是核心部分,集中了其中几乎所有的功能方法,例如类定义的转换和操作
*/
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("==============premain1执行===================");
System.out.println("agentArgs : " +agentArgs);
// 添加Transformer
inst.addTransformer(new TestTransformer());
}
}
编写TestTransformer
/**
* @author Jenson
*/
public class TestTransformer implements ClassFileTransformer {
public final String TEST_CLASS_NAME = "com.tong.controller.HelloController";
public final String METHOD_NAME = "hello";
public byte[] transform(ClassLoader loader,
String className,
Class> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
// System.out.println("className : " +className);
String finalClassName =className.replace("/", ".");
if (TEST_CLASS_NAME.equals(finalClassName)) {
System.out.println("class name匹配上了 !");
CtClass ctClass;
try {
ctClass = ClassPool.getDefault().get(finalClassName);
System.out.println("ctClass is OK !");
CtMethod ctMethod = ctClass.getDeclaredMethod(METHOD_NAME);
System.out.println("CtMethod is OK !");
ctMethod.insertBefore("System.out.println(\"字节码添加成功,打印日志 !\");");
return ctClass.toBytecode();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
return null;
}
}
项目测试打包
添加javaagent启动参数
java -javaagent:agent路径 -jar 项目名.jar
启动,打印出日志
发送请求http://localhost:8080/hello