Skywalking使用与探针机制
对于 大型 几十个、几百个微服务构成的微服务架构系统 出现问题无法快速定位、各个微服务之间的依赖关系理不清、各个微服务的接口性能很难分析、业务调用流程处理顺序理不清skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。
对于 大型 几十个、几百个微服务构成的微服务架构系统 出现问题无法快速定位、各个微服务之间的依赖关系理不清、各个微服务的接口性能很难分析、业务调用流程处理顺序理不清
skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。SkyWalking 是观察性分析平台和应用性能管理系统,提供分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案。
官网:http://skywalking.apache.org/
下载:http://skywalking.apache.org/downloads/
Github:https://github.com/apache/skywalking
文档: https://skywalking.apache.org/docs/main/v8.4.0/readme/
中文文档: https://skyapm.github.io/document-cn-translation-of-skywalking/
Skywalking架构的四个部分
上部分使用java的Agent机制从应用中收集链路信息 发送给SkyWalking OAP服务器
下部分SkyWalking OAP 当收到上部分发来的链路信息之后进行分析 分析结果存到外部存储器 以提供查询
右部分Storage:Tracing数据存储,目前支持ES、MySQL、Sharding Sphere、TiDB、H2多种存储器,目前采用较多的是ES,主要考虑是SkyWalking开发团队自己的生产环境采用ES为主
左部分SkyWalking UI:负责提供控制台,查看链路等等
Agent机制 是jdk1.5提供的可以获取jvm中的字节码 然后对它进行增强
在idea中使用Agent机制(探针机制)
给jvm传参 javaagent: 传入一个实现premain方法的jar 看下面代码
Agent类 加强类
package bat.ke.qq.com;
import java.lang.instrument.Instrumentation;
public class AmAgent {
public static void premain(String args, Instrumentation instrumentation){
System.out.println("premain:" + args);
}
}
加强类的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">
<parent>
<artifactId>trace-agent</artifactId>
<groupId>bat.ke.qq.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>agent-demo</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<Project-name>${project.name}</Project-name>
<Project-version>${project.version}</Project-version>
<Premain-Class>bat.ke.qq.com.AmAgent</Premain-Class> // 这里指定<Premain-Class> 这个preamin会比main先运行
</manifestEntries>
</archive>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
被加强类
package com.am;
public class AgentTest {
public static void main(String[] args) {
// TODO 启动服务 获取进程 memory jvm
// Instrument 定位到UserService 统计方法执行时间
// 微服务 引入nacos pom jar yml
System.out.println("hello world");
// TODO业务逻辑 UserService方法 统计方法执行时间
}
}
被加强类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">
<parent>
<artifactId>trace-agent</artifactId>
<groupId>bat.ke.qq.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>agent-demo2</artifactId>
<dependencies>
</dependencies>
</project>
然后在被加强类启动之前传入jvm参数-javaagent:D:\2021java代码存放地\Skywalking\agent-demo\target\agent-demo-1.0-SNAPSHOT.jar=name=123
D:\2021java代码存放地\Skywalking\agent-demo\target\agent-demo-1.0-SNAPSHOT.jar 所指的文件就是加强类的jar 然后运行被加强类可以看到效果
以上是简单使用 下面加入了修改字节码
加强类
package com.am;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import java.lang.instrument.Instrumentation;
public class FoxAgent {
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("premain:获取方法调用时间");
AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader) {
return builder
// 拦截任意方法
.method(ElementMatchers.<MethodDescription>any())
// 指定方法拦截器,此拦截器中做具体的操作
.intercept(MethodDelegation.to(TimeInterceptor.class));
}
};
AgentBuilder.Listener listener = new AgentBuilder.Listener() {
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, DynamicType dynamicType) {}
@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { }
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, Throwable throwable) { }
@Override
public void onComplete(String typeName, ClassLoader classLoader, JavaModule module) { }
};
new AgentBuilder
.Default()
// 指定需要拦截的类
.type(ElementMatchers.nameStartsWith("com.tuling"))
.transform(transformer)
.with(listener)
.installOn(inst);
}
}
加强类所用的
package com.am;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
public class TimeInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@SuperCall Callable<?> callable) throws Exception {
long start = System.currentTimeMillis();
try {
// 原方法执行
return callable.call();
} finally {
System.out.println(method + ": cost " + (System.currentTimeMillis() - start) + "ms");
}
}
}
加强类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">
<parent>
<artifactId>trace-agent</artifactId>
<groupId>bat.ke.qq.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bytebuddy-demo</artifactId>
<dependencies>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.5.13</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.5.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<Project-name>${project.name}</Project-name>
<Project-version>${project.version}</Project-version>
<Premain-Class>com.tuling.FoxAgent</Premain-Class>
</manifestEntries>
</archive>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactSet>
<includes>
<include>javassist:javassist:jar:</include>
<include>net.bytebuddy:byte-buddy:jar:</include>
<include>net.bytebuddy:byte-buddy-agent:jar:</include>
</includes>
</artifactSet>
</configuration>
</plugin>
</plugins>
</build>
</project>
被加强类
package com.am;
public class AgentBytebuddyTest {
public static void main(String[] args) {
HelloService helloService = new HelloService();
helloService.say();
helloService.say2();
}
}
被加强类所用的
package com.am;
public class HelloService {
public String say(){
System.out.println("===hello world====");
return "hello world";
}
public String say2(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello world";
}
}
被加强类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">
<parent>
<artifactId>trace-agent</artifactId>
<groupId>bat.ke.qq.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bytebuddy-demo2</artifactId>
</project>
利用agent机制 实现业务零侵入 打印jvm使用情况
加强类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">
<parent>
<artifactId>trace-agent</artifactId>
<groupId>bat.ke.qq.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Metric-tool</artifactId>
<dependencies>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
<type>jar</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<Project-name>${project.name}</Project-name>
<Project-version>${project.version}</Project-version>
<Premain-Class>com.tuling.FoxAgent</Premain-Class>
</manifestEntries>
</archive>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<artifactSet>
<includes>
<include>javassist:javassist:jar:</include>
</includes>
</artifactSet>
</configuration>
</plugin>
</plugins>
</build>
</project>
加强类
package com.am;
import java.lang.instrument.Instrumentation;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class AmAgent {
public static void premain(String agentArgs, Instrumentation inst) {
//每隔5秒打印JVM内存和GC信息
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Metric.printMemoryInfo();
Metric.printGCInfo();
}
}, 0, 5000, TimeUnit.MILLISECONDS);
}
}
加强类所用的 打印jvm使用情况实现
package com.am;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.Arrays;
import java.util.List;
/**
*
* 获取JVM 内存以及GC信息
*
*/
public class Metric {
private static final long MB = 1048576L;
public static void printMemoryInfo() {
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
MemoryUsage headMemory = memory.getHeapMemoryUsage();
String info = String.format("\nHeapMemory init: %s\t max: %s\t used: %s\t committed: %s\t use rate: %s\n",
headMemory.getInit() / MB + "MB",
headMemory.getMax() / MB + "MB", headMemory.getUsed() / MB + "MB",
headMemory.getCommitted() / MB + "MB",
headMemory.getUsed() * 100 / headMemory.getCommitted() + "%"
);
System.out.print(info);
MemoryUsage nonheadMemory = memory.getNonHeapMemoryUsage();
info = String.format("NonHeapMemory init: %s\t max: %s\t used: %s\t committed: %s\t use rate: %s\n",
nonheadMemory.getInit() / MB + "MB",
nonheadMemory.getMax() / MB + "MB", nonheadMemory.getUsed() / MB + "MB",
nonheadMemory.getCommitted() / MB + "MB",
nonheadMemory.getUsed() * 100 / nonheadMemory.getCommitted() + "%"
);
System.out.println(info);
}
public static void printGCInfo() {
List<GarbageCollectorMXBean> garbages = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean garbage : garbages) {
String info = String.format("name: %s\t count:%s\t took:%s\t pool name:%s",
garbage.getName(),
garbage.getCollectionCount(),
garbage.getCollectionTime(),
Arrays.deepToString(garbage.getMemoryPoolNames()));
System.out.println(info);
}
}
}
被加强类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">
<parent>
<artifactId>trace-agent</artifactId>
<groupId>bat.ke.qq.com</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>Metric-tool-demo</artifactId>
</project>
被加强类
package com.am;
import java.util.ArrayList;
import java.util.List;
public class MetricToolAgentTest {
public static void main(String[] args) {
boolean flag = true;
while (flag) {
List<Object> list = new ArrayList<Object>();
list.add("Hello World");
}
}
}
SkyWalking环境搭建
下载:http://skywalking.apache.org/downloads/
目录结构:
搭建SkyWalking OAP 服务
先使用默认的H2数据库存储,不用修改配置
config/application.yml
使用vim指令进入config/application.yml搜索storage 可以看到它的下一行是selector: ${SW_STORAGE:h2}
启动脚本 bin/startup.sh
日志信息存储在logs目录
启动成功后会启动两个服务,一个是skywalking-oap-server,一个是skywalking-web-ui
skywalking-oap-server服务启动后会暴露11800 和 12800 两个端口,分别为收集监控数据的端口11800和接受前端请求的端口12800,修改端口可以修改config/applicaiton.yml
skywalking-web-ui服务会占用 8080 端口, 修改端口可以修改webapp/webapp.yml
Skywalking到这就搭建好了
然后使用
准备一个springboot程序,打成可执行jar包,写一个shell脚本,在启动项目的Shell脚本上,通过 -javaagent 参数进行配置SkyWalking Agent来跟踪微服务;
startup.sh脚本:
#!/bin/sh
# SkyWalking Agent配置
export SW_AGENT_NAME=springboot-skywalking-demo #Agent名字,一般使用`spring.application.name`
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置 Collector 地址。
export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大Span数量,默认为 300。
export JAVA_AGENT=-javaagent:/usr/local/soft/apache-skywalking-apm-bin-es7/agent/skywalking-agent.jar
java $JAVA_AGENT -jar springboot-skywalking-demo-0.0.1-SNAPSHOT.jar #jar启动
这样启动之后 访问请求 就可以在Skywalking UI界面中查看到 多个微服务 只需要添加javaagent参数指定skywalking-agent.jar这个jar文件即可
在idea中使用 也是给jvm传参
# skywalking-agent.jar的本地磁盘的路径
-javaagent:D:\apache\apache-skywalking-apm-es7-8.4.0\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar
# 在skywalking上显示的服务名
-DSW_AGENT_NAME=springboot-skywalking-demo
# skywalking的collector服务的IP及端口
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.3.100:11800
自定义链路 就是可以让Skywalking可以检测到我们的业务代码
导入依赖
<!-- SkyWalking 工具类 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.4.0</version>
</dependency>
在业务方法中可以TraceContext获取到traceId
@RequestMapping("/list")
public List<User> list(){
//TraceContext可以得到Skywalking的上下文 下面的代码时绑定一个key-value
TraceContext.putCorrelation("name", "fox");
Optional<String> op = TraceContext.getCorrelation("name");
log.info("name = {} ", op.get());
//获取跟踪的traceId
String traceId = TraceContext.traceId();
log.info("traceId = {} ", traceId);
return userService.list();
}
userService.list();会调用到下面的list 然后list方法加了@Trace注解 这样Skywalking就可以把list方法加入到链路中 @Tag注解是用来把方法返回值写到SKywalking中
@Trace
@Tag(key = "list", value = "returnedObj")
public List<User> list(){
return userMapper.list();
}
@Trace
@Tags({@Tag(key = "param", value = "arg[0]"),
@Tag(key = "user", value = "returnedObj")})
public User getById(Integer id){
return userMapper.getById(id);
}
日志集成
logback官方配置 https://github.com/apache/skywalking/blob/master/docs/en/setup/service-agent/java-agent/Application-toolkit-logback-1.x.md
log4j官方配置 https://skywalking.apache.org/docs/main/v8.4.0/en/setup/service-agent/java-agent/application-toolkit-log4j-1.x/
log4j2j官方配置 https://skywalking.apache.org/docs/main/v8.4.0/en/setup/service-agent/java-agent/application-toolkit-log4j-2.x
Skywalking集群部署
Skywalking集群是将skywalking oap作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一个skywalking oap在运行,就能进行跟踪。
搭建一个skywalking oap集群需要:
(1)至少一个Nacos(也可以是nacos集群)
(2)至少一个ElasticSearch(也可以是es集群)
(3)至少2个skywalking oap服务;
(4)至少1个UI(UI也可以集群多个,用Nginx代理统一入口)
1.修改config/application.yml文件
使用nacos作为注册中心
修改nacos配置
修改存储策略,使用elasticsearch7作为storage
修改elasticsearch7配置
配置ui服务webapp.yml文件的listOfServers,写两个地址
listOfServers是OAP的地址
然后springboot应用传入的jvm参数的更改
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.3.10:11800,192.168.3.12:11800
更多推荐
所有评论(0)