因为SpringBoot3.0以上移除了Sleuth,迁移到了MicrometerTracingBrave,所以直接使用MicrometerTracingBrave即可。
在之前安装过RabbitMQ的虚拟机中继续安装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
http://192.168.126.11:9411
在gateway9527和payment8001和payment8002以及openfeign-order80项目的POM文件中添加tracing和zipkin依赖。
<!-- brave和zipkin依赖项 -->
<!-- https://mvnrepository.com/artifact/io.micrometer/micrometer-observation 用于收集应用程序的度量数据-->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.micrometer/micrometer-tracing-bridge-brave 用于与分布式追踪工具Brave集成-->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.openfeign/feign-micrometer 用于收集客户端请求的度量数据-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
<version>12.3</version>
</dependency>
<!-- RabbitMQ的消息驱动 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<!-- 用于将Brave跟踪数据报告到Zipkin跟踪系统的库上 -->
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
在gateway9527和payment8001和payment8002以及openfeign-order80项目的yml文件中添加和brave和zipkin的配置信息。
spring:
rabbitmq:
host: 192.168.126.11
port: 5672
username: guest
password: guest
## 设置zipkin和brave配置和tracing的日志信息
logging.pattern.level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
management:
zipkin:
tracing:
endpoint: http://192.168.126.11:9411/api/v2/spans
tracing:
sampling:
# 采样率的概率,100%采样
probability: 1.0
gateway9527项目的YML文件配置跳过路由验证和Order的微服务路由
org:
my:
jwt:
# 跳过认证路由
skipAuthUrls:
- /user/login
- /order/index
spring:
application:
#设置应用名
name: cloud-gateway
cloud:
gateway:
# 路由配置
routes:
# 路由ID,没有固定规则但要求唯一,建议配合服务名
- id: cloud-order-consumer
# 匹配后提供服务的路由地址 (即目标服务地址) lb后跟提供服务的微服务的名字
uri: lb://CLOUD-ORDER-CONSUMER
# 断言会接收一个输入参数,返回一个布尔值结果
predicates:
# 路径相匹配的进行路由
- Path=/order/*
测试链路追踪
1)启动Eureka7001和Eureka7002和openfeign-order80和gateway9527和payment8001以及payment8002服务
2)打开Centos7虚拟机,启动RabbitMQ和Zipkin服务
3)在浏览器访问:http://localhost:9527/order/index
请求成功后,在浏览器中打开Zipkin可视化界面:http://192.168.126.11:9411/
可以看到这时候Zipkin已经存在调用链的链路信息。
在helloagent项目的POM文件中添加如下依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.zzx</groupId>
<artifactId>helloagent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在com.zzx.controller包下创建HelloController类,代码如下
package com.zzx.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello JavaAgent";
}
}
启动helloagent项目后,在浏览器访问:localhost:8080/hello
对helloagent项目进行打包,即先打开maven的窗口,然后找到下图的packeage双击,等待打包,出现Success即打包成功。
打完包后,在target目录中会有一个以项目命名的 jar包文件以及控制台出现Success。
在javaagent项目的POM文件中添加如下依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzx</groupId>
<artifactId>javaagent</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- javassist是一个处理Java字节码的类库 -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.2-GA</version>
</dependency>
</dependencies>
<build>
<finalName>javaagent</finalName>
<plugins>
<!--
META-INF 下 MANIFEST.MF 文件 内容
Manifest-Version: 1.0
Premain-Class: com.jenson.TestAgent
下面Maven插件可以自动实现
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Premain-Class>com.zzx.TestAgent</Premain-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
在javaagent项目的com.zzx包下,创建修改.class文件的探针实现类TestTransformer ,代码如下
package com.zzx;
import javassist.*;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class TestTransformer implements ClassFileTransformer {
private final String CLASS_NAME = "com.zzx.controller.HelloController";
private final String METHOD_NAME = "hello";
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
// 1.获取类名字
String name = className.replace("/",".");
// 2.判断是否是我要修改的类
if(name.equals(CLASS_NAME)){
// 3.javassist是一个处理java字节码的类库
//java字节码存储在一个class file的二进制文件里
//每个class文件包含一个java类或接口
//java ssist.ctclass 就是class文件的抽象表示
CtClass ctClass;
try {
// 4.获取helloController类搜索路径
ctClass = ClassPool.getDefault().get(name);
System.out.println("CtClass is OK");
// 5.获取类中的方法
CtMethod method = ctClass.getDeclaredMethod(METHOD_NAME);
System.out.println("CtMethod is OK");
method.insertBefore("System.out.println(\"字节码添加成功,打印日志\");");
return ctClass.toBytecode();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}
}
在javaagent项目的com.zzx包下,创建探针类TestAgent,代码如下
package com.zzx;
import java.lang.instrument.Instrumentation;
/**
* 探针类
*/
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("********* premain 执行了 **********");
System.out.println("agentArgs:"+agentArgs);
inst.addTransformer(new TestTransformer());
}
}
因为项目下target目录在项目没有显示,此时可以在项目的文件夹中去找
打开项目文件夹下的target文件夹,复制下面的第一个jar包到刚刚存放helloagent.jar的文件夹下。
测试探针
1)进入命令行后,输入:java -javaagent:javaagent.jar -jar helloagent-0.0.1-SNAPSHOT.jar
2)在浏览器中访问:localhost:8080/hello
即在访问后,会打印字节码添加成功,打印日志这个字符串。代表JAVA探针修改.class文件成功。
下载9.4.0版本的SkyWalking:https://dlcdn.apache.org/skywalking/9.4.0/apache-skywalking-apm-9.4.0.tar.gz
在opt目录中,输入将JDK解压到/usr/local的命令:tar -zxvf jdk-11.0.15.1_linux-x64_bin.tar.gz -C /usr/local/
进入到/usr/local目录下,获取JDK名字,再编辑profile文件:vim /etc/profile
,在文件底部添加如下配置:
export JAVA_HOME=/usr/local/jdk-11.0.15.1
export PATH=$PATH:$JAVA_HOME/bin
source /etc/profile
java -version
到opt目录下,在命令行中输入命令解压SkyWalking到/usr/local目录中:tar -zxvf apache-skywalking-apm-9.4.0.tar.gz -C /usr/local/
SkyWalking解压后的目录:
修改web的yml文件的端口号信息:vim /usr/local/apache-skywalking-apm-bin/webapp/application.yml
启动SkyWalking服务
cd /usr/local/apache-skywalking-apm-bin/bin
./startup.sh
在体验完Java探针后,打开之前的cloud项目,复制cloud-consumer-openfeign-order80,粘贴到cloud父工程中,并修改名字为cloud-consumer-openfeign-skywalking-order80
移除cloud-consumer-openfeign-skywalking-order80项目的POM文件中之前的brave和zipkin的依赖
此时再复制cloud-provider-payment8001项目,粘贴到cloud父项目中,改名字为cloud-provider-skywalking-payment8001
跟上面的cloud-consumer-openfeign-skywalking-order80修改步骤相同。
最后,在cloud-consumer-openfeign-skywalking-order80项目的YML文件中添加如下配置
spring:
main:
#允许存在多个Feign调用相同Service的接口
allow-bean-definition-overriding: true
即允许多个接口使用@FeignClient调用同一个服务。
下载JavaAgent:https://dlcdn.apache.org/skywalking/java-agent/8.15.0/apache-skywalking-java-agent-8.15.0.tgz
直接在文件夹中解压JavaAgent到当前文件即可,然后剪切该文件夹到cloud父工程即可。
编辑SkyWalkingOrderFeignMain80项目Configuration的VM options,代码如下
-javaagent:D:\CODE\IDEA\cloud\skywalking-agent\skywalking-agent.jar
-DSW_AGENT_NAME=consumer-order
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.126.11:11800
编辑SkyWalkingPaymentMain8001项目Configuration的VM options,代码如下
-javaagent:D:\CODE\IDEA\cloud\skywalking-agent\skywalking-agent.jar
-DSW_AGENT_NAME=provider-payment
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.126.11:11800
此时-DSW_AGENT_NAME是指服务名字(自定义),只需要保证唯一性即可。
下载elasticsearch:docker pull elasticsearch:8.7.1
创建并启动Elasticsearch:docker run --restart=always -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms512m -Xmx512m" --name='es' -d elasticsearch:8.7.1
拷贝docker下的es容器的elasticsearch.yml文件:docker cp es:/usr/share/elasticsearch/config/elasticsearch.yml .
修改拷贝到当前目录下的elasticsearch.yml文件:vim elasticsearch.yml
,配置如下
cluster.name: "docker-cluster"
network.host: 0.0.0.0
#----------------------- BEGIN SECURITY AUTO CONFIGURATION -----------------------
#
# The following settings, TLS certificates, and keys have been automatically
# generated to configure Elasticsearch security features on 10-05-2023 15:57:14
#
# --------------------------------------------------------------------------------
# Enable security features
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
# Enable encryption for HTTP API client connections, such as Kibana, Logstash, and Agents
xpack.security.http.ssl:
enabled: false
keystore.path: certs/http.p12
# Enable encryption and mutual authentication between cluster nodes
xpack.security.transport.ssl:
enabled: false
verification_mode: certificate
keystore.path: certs/transport.p12
truststore.path: certs/transport.p12
#----------------------- END SECURITY AUTO CONFIGURATION -------------------------
将修改的elasticsearch.yml文件拷贝到es容器下存放elasticsearch.yml的目录下:docker cp elasticsearch.yml es:/usr/share/elasticsearch/config/
重启ES服务:docker restart es