Skywalking安装和使用
安装
下载地址:https://skywalking.apache.org/downloads/
由于本地的ES是7.15.1版本 所有需要选择对应版本的
本地需要启动ES。ES安装可查看之前的博客:
配置ES启动
- 进入解压后的skywalking目录:
cd apache-skywalking-apm-bin-es7
# 修改config里面的
- 修改config目录下的
application.yml
文件
默认使用的是h2存储数据,修改为es7
selector: ${SW_STORAGE:elasticsearch7}
- 进入bin目录启动
nohup nice sh startup.sh &
-
打开 webapp/webapp.yml文件 查看UI访问端口
-
访问 http://localhost:8080/
Agent
agent探针
可以让我们不修改代码的情况下,对java应用上使用到的组件进行动态监控,获取运行数据发送到OAP上进行统计和存储。agent探针在java中是使用java agent技术实现的,不需要更改任何代码,java agent会通过虚拟机(VM)接口来在运行期更改代码。
进入 agent 目录
cd ~/tools/apache-skywalking-apm-bin-es7/agent/
目录 | 作用 |
---|---|
config | 配置文件 |
plugins | 使用的插件 |
optional-plugins | 可选的插件 如果需要使用,放入到plugins就会生效 |
项目集成
可查看官方文档: https://skywalking.apache.org/docs/main/v8.7.0/en/setup/service-agent/java-agent/readme/
修改应用名:打开agent/config目录,编辑agent_config文件
# The service name in UI
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
Tomcat
编辑 apache-tomcat-8.5.47/bin/catalina.sh 文件,在文件顶部添加
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/skywalking/apache- skywalking-apm-bin/agent/skywalking-agent.jar"; export CATALINA_OPTS
SpringBoot
IDEA配置VM参数
-javaagent:/Users/mpy/tools/apache-skywalking-apm-bin-es7/agent/skywalking-agent.jar
或者jar命令启动
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar -jar yourApp.jar
需要等待一下才能看到数据
常用插件
配置覆盖
本地多个项目 如何都使用同一份agent配置不同的项目名称呢?
可以使用Skywalking提供的配置覆盖功能通过启动命令动态指定服务名,这样agent只需要部署一份即可。Skywalking支持的几种配置方式:
- 系统配置(System properties)
使用skywalking. + 配置文件中的配置名
作为系统配置项来进行覆盖.
-Dskywalking.agent.service_name=skywalking_mysql
- 探针配置(Agent options)
-javaagent:/path/to/skywalking-agent.jar=[option1]=[value1],[option2]=[value2]
案例:
-javaagent:/path/to/skywalking-agent.jar=agent.service_name=skywalking_mysql
特殊字符
如果配置中包含分隔符( , 或者 = ) , 就必须使用引号包裹起来
-javaagent:/path/to/skywalking-agent.jar=agent.ignore_suffix='.jpg,.jpeg'
- 系统环境变量(System environment variables)
由于agent.service_name配置项如下所示:
agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
可以在环境变量中设置SW_AGENT_NAME的值来指定服务名。
覆盖优先级
探针配置 > 系统配置 >系统环境变量 > 配置文件中的值
所以启动命令可以修改为:
java -javaagent:/usr/local/skywalking/apache-skywalking-apm- bin/agent_mysql/skywalking-agent.jar - Dskywalking.agent.service_name=skywalking_mysql -jar skywalking_mysql.jar &
获取追踪ID
- 添加Jar包 和本地skywalking版本保持一致
org.apache.skywalking
apm-toolkit-trace
8.7.0
- 编写测试类
//获取trace id,可以在RocketBot追踪中进行查询
@GetMapping("/getTraceId")
public String getTraceId() {
//使当前链路报错,并且提示报错信息
ActiveSpan.error(new RuntimeException("Test-Error-Throwable"));
//打印info信息
ActiveSpan.info("Test-Info-Msg");
//打印debug信息
ActiveSpan.debug("Test-debug-Msg");
return TraceContext.traceId();
}
- 测试
过滤指定的端点
项目中的一些接口是不需要监控指标的,比如Swagger相关的端点,需要进行过滤
-
添加可选插件
apm-trace-ignore-plugin-8.7.0.jar
到 plugins目录中 -
编写测试类
//此接口可以被追踪
@GetMapping("/include")
public String include(){
return "include";
}
//此接口不可被追踪
@GetMapping("/exclude")
public String exclude(){
return "exclude";
}
- 添加启动参数
- Dskywalking.trace.ignore_path=/exclude
-
测试 include接口可以被监控,exclude无法被监控
-
匹配多路径
这里添加-Dskywalking.trace.ignore_path=/exclude参数来标识需要过滤哪些请求,支持 Ant Path 表达式:/path/* , /path/** , /path/?
- ? 匹配任何单字符
- * 匹配0或者任意数量的字符
- ** 匹配0或者更多的目录
告警功能
Skywalking每隔一段时间根据收集到的链路追踪的数据和配置的告警规则(如服务响应时间、服务响应时间百分比)等,判断如果达到阈值则发送相应的告警信息。发送告警信息是通过调webhook接口完成,具体的webhook接口可以使用者自行定义,从而开发者可以在指定的webhook接口中编写各种告警方式,比如邮件、短信等。告警的信息也可以在RocketBot中查看到。
默认的告警规则配置,位于skywalking安装目录下的config文件夹下 alarm-settings.yml
文件中
规则属性说明
属性 | 含义 |
---|---|
metrics-name | oal脚本中的度量名称 |
threshold | 阈值,与metrics-name和下面的比较符号相匹配 |
op | 比较操作符,可以设定>,<,= |
period | 多久检查一次当前的指标数据是否符合告警规则,单位分钟 |
count | 达到多少次后,发送告警消息 |
silence-period | 在多久之内,忽略相同的告警消息 |
message | 告警消息内容 |
include-names | 本规则告警生效的服务列表 |
webhooks可以配置告警产生时的调用地址。
webhooks:
# - http://127.0.0.1/notify/
# - http://127.0.0.1/go-wechat/
具体信息可以查看官方文档:https://skywalking.apache.org/docs/main/latest/en/setup/backend/backend-alarm/#webhook
- 配置文件修改
webhooks:
- http://127.0.0.1:8801/webhook
- 接收告警信息 自行处理
产生告警时会调用webhook接口,该接口必须是Post类型,同时接口参数使用RequestBody。参数格式为
[{
"scopeId": 1,
"scope": "SERVICE",
"name": "serviceA",
"id0": "12",
"id1": "",
"ruleName": "service_resp_time_rule",
"alarmMessage": "alarmMessage xxxx",
"startTime": 1560524171000,
"tags": [{
"key": "level",
"value": "WARNING"
}]
}]
private List lastList = new ArrayList<>();
@PostMapping("/webhook")
public void webhook(@RequestBody List alarmMessageList){
lastList = alarmMessageList;
}
java agent原理
上文中我们知道,要使用Skywalking去监控服务,需要在其 VM 参数中添加 -javaagent:/skywalking-agent.jar
。这里就使用到了java agent技术。
Java agent 是什么
Java agent是java命令的一个参数。参数 javaagent 可以用于指定一个 jar 包。
- 这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。
- Premain-Class 指定的那个类必须实现 premain() 方法。
当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行 -javaagent 所指定 jar 包内PremainClass 这个类的 premain 方法 。
如何使用java agent
使用 java agent 需要几个步骤:
- 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-RedefineClasses 和 Can-Retransform-Classes 选项。
- 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
- 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
- 使用参数 -javaagent: jar包路径 启动要代理的方法。
自定义Agent
Skywalking中对每个调用的时长都进行了统计,我们可以使用ByteBuddy
和Java agent
技术来模拟实现skywalking统计方法的调用时长
- 新建maven项目 agent
net.bytebuddy
byte-buddy
1.9.2
net.bytebuddy
byte-buddy-agent
1.9.2
- 编写PreMain方法
PreMainAgent类 通过MyInterceptor 插入业务逻辑
public static void premain(String agentArgs, Instrumentation inst) {
//创建一个转换器,转换器可以修改类的实现
//ByteBuddy对java agent提供了转换器的实现,直接使用即可
AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> builder
// 拦截任意方法
.method(ElementMatchers.any())
// 拦截到的方法委托给TimeInterceptor
.intercept(MethodDelegation.to(MyInterceptor.class));
new AgentBuilder // Byte Buddy专门有个AgentBuilder来处理Java Agent的场景
.Default()
// 根据包名前缀拦截类
.type(ElementMatchers.nameStartsWith("com.agenttest"))
// 拦截到的类由transformer处理
.transform(transformer)
.installOn(inst);
}
- 编写拦截方法
@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");
}
}
- 指定build方法
maven-assembly-plugin
false
jar-with-dependencies
true
com.PreMainAgent
com.PreMainAgent
true
true
make-assembly
package
single
- 新建测试项目agent-test
public class App
{
public static void main( String[] args )
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( "Hello World!" );
}
}
启动时指定javaagent为上面的项目打包生成的jar
- 测试 可以发现运行时自动执行了agent项目里面的方法
Open Tracing介绍
OpenTracing通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。OpenTracing中最核心的概念就是Trace
。
Trace
在广义上,一个trace代表了一个事务或者流程在(分布式)系统中的执行过程。在OpenTracing标准中,trace是多个span组成的一个有向无环图(DAG)
,每一个span代表trace中被命名并计时的连续性的执行片段。
图中每一个色块其实就是一个span。
Span
一个Span代表系统中具有开始时间和执行时长的逻辑运行单元。span之间通过嵌套或者顺序排列建立逻辑因果关系。
Span里面的信息包括:操作的名字,开始时间和结束时间,可以附带多个 key:value 构成的Tags(key必须是String,value可以是 String, bool 或者数字),还可以附带 Logs
信息(不一定所有的实现都支持)
一个span可以和一个或者多个span间存在因果关系。OpenTracing定义了两种关系: ChildOf
和 FollowsFrom
。这两种引用类型代表了子节点和父节点间的直接因果关系。未来,OpenTracing将支持非因果关系的span引用关系。(例如:多个span被批量处理,span在同一个队列中,等等)
- ChildOf 很好理解,就是父亲 Span 依赖另一个孩子 Span。比如函数调用,被调者是调用者的孩子,比如说 RPC 调用,服务端那边的Span,就是 ChildOf 客户端的。很多并发的调用,然后将结果聚合起来的操作,就构成了 ChildOf 关系。
- 如果父亲 Span 并不依赖于孩子 Span 的返回结果,这时可以说它他构成 FollowsFrom 关系。
如图所示,左边的每一条追踪代表一个Trace,而右边时序图中每一个节点就是一个Span。
Log的概念
每个span可以进行多次Logs操作,每一次Logs操作,都需要一个带时间戳的时间名称,以及可选的任意大小的存储结构。
Tags的概念
每个span可以有多个键值对(key:value)形式的Tags,Tags是没有时间戳的,支持简单的对span进行注解和补充。
如下图就是一个Tags的详细信息,其中记录了数据库访问的SQL语句等内容。