APM (Application Performance Management)
即应用性能管理系统,是对企业系统即时监控以实现对应用程序性能管理和故障管理的系统化的解决方案。应用性能管理,主要指对企业的关键业务应用进行监测、优化,提高企业应用的可靠性和质量,保证用户得到良好的服务,降低 IT 总拥有成本。CAT | Zipkin | Apache SkyWalking | |
---|---|---|---|
调用链可视化 | 有 | 有 | 有 |
聚合报表 | 非常丰富 | 少 | 较丰富 |
服务依赖图 | 简单 | 简单 | 好 |
埋点方式 | 侵入 | 侵入 | 非侵入,运行期字节码增强 |
VM 指标监控 | 好 | 无 | 有 |
告警支持 | 有 | 无 | 有 |
多语言支持 | Java、C/C++、Node.js、Python、Go | 丰富 | Java、LUA、Python、.NET、Node.js、PHP、GO2Sky |
存储机制 | MySQL(报表)、本地文件、HDFS(调用链) | 可选 inMemory、MySQL、ES(生产)、Cassandra(生产) | ES、MySQL、Sharding Sphere、TiDB、H2 |
社区支持 | 主要在国内,点评/美团 | 文档丰富,国外主流 | Apache 支持,国内社区好 |
国内案例 | 点评、携程、陆金所、拍拍贷等 | 京东、阿里定制不开源等 | 华为、小米、当当、微众银行等 |
源头 | eBay CAL | Google Dapper | Google Dapper |
同类产品 | 暂无 | Uber Jaeger、Spring Cloud Sleuth | Naver Pinpoint |
出现年份 | 2011 | 2012 | 2015 |
Github Stars | 14.1k | 13.3k | 14.3k |
亮点 | 企业生产级,报表丰富 | 社区生态好 | 非侵入,Apache 背书 |
不足 | 用户体验一般,社区一般 | APM 报表能力弱 | 时间不长,文档一般,仅限中文社区 |
pods
一样,服务实例未必就是操作系统上的一个进程。但当你在使用打点代理的时候,一个服务实例实际就是操作系统上的一个真实进程。SkyWalking 逻辑上分为四部分:探针、平台后端、存储和用户界面。
java -javaagent:E:\Workspaces\LearnWorkspace\SkyWalking示例\skywalking\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar -Dskywalking.agent.service_name=skywalking-user -Dskywalking.collector.backend_service=127.0.0.1:11800 -jar user-1.0.0-SNAPSHOT.jar
agent.config
配置文件。
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES:127.0.0.1:11800}
logging.level=${SW_LOGGING_LEVEL:INFO}
SW_AGENT_NAME
环境变量在你的操作系统中已存在,并且它的值为 skywalking-demo
,那么这里的 agent.service_name
的值将会被覆写为 skywalking-demo
, 否则, 它将会被设置成 Your_ApplicationName
。告警的消息通过 HTTP 请求进行发送,请求方法是 POST,Content-Type 是 application/json,JSON 格式基于 List<org.apache.skywalking.oap.server.core.alarm.AlarmMessage。
public class PreMainAgent {
/**
* 在这个 premain 函数中,开发者可以进行对类的各种操作。
* 1、agentArgs 是 premain 函数得到的程序参数,随同 “– javaagent”一起传入。与 main 函数不同的是,
* 这个参数是一个字符串而不是一个字符串数组,如果程序参数有多个,程序将自行解析这个字符串。
*
* 2、Inst 是一个 java.lang.instrument.Instrumentation 的实例,由 JVM 自动传入。*
* java.lang.instrument.Instrumentation 是 instrument 包中定义的一个接口,也是这个包的核心部分,
* 集中了其中几乎所有的功能方法,例如类定义的转换和操作等等。
*/
public static void premain(String agentArgs, Instrumentation inst) {
System.out.println("premain 方法执行 1");
System.out.println(agentArgs);
}
/**
* 如果不存在 premain(String agentArgs, Instrumentation inst)
* 则会执行 premain(String agentArgs)
*/
public static void premain(String agentArgs) {
System.out.println("premain 方法执行 2");
System.out.println(agentArgs);
}
}
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<!--自动添加META-INF/MANIFEST.MF -->
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Premain-Class>com.zp.skywalking.javaagentdemo.PreMainAgent</Premain-Class>
<Agent-Class>com.zp.skywalking.javaagentdemo.PreMainAgent</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.10.14</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.10.14</version>
<scope>test</scope>
</dependency>
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 PreMainAgent {
public static void premain(String agentArgs, Instrumentation inst) {
//创建一个转换器,转换器可以修改类的实现
//ByteBuddy对java agent提供了转换器的实现,直接使用即可 AgentBuilder.Transformer transformer = new AgentBuil
AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
return builder
// 拦截任意方法
.method(ElementMatchers.<MethodDescription>any())
// 拦截到的方法委托给 TimeInterceptor
.intercept(MethodDelegation.to(MyInterceptor.class));
}
};
new AgentBuilder // Byte Buddy 专门有个 AgentBuilder 来处理 Java Agent 场景
.Default()
// 根据包名前缀拦截类
.type(ElementMatchers.nameStartsWith("com.myspace.server"))
// 拦截到的类由 transformer 处理
.transform(transformer)
.installOn(inst);
}
}
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 MyInterceptor {
@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.getName() + ":" + (System.currentTimeMillis() - start) + "ms");
}
}
}
com.myspace.server
包下。public class Main {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000);
System.out.println("Hello World!");
}
}