Skywalking安装和使用


安装

下载地址:https://skywalking.apache.org/downloads/

由于本地的ES是7.15.1版本 所有需要选择对应版本的

本地需要启动ES。ES安装可查看之前的博客:

配置ES启动

  1. 进入解压后的skywalking目录:
cd apache-skywalking-apm-bin-es7
# 修改config里面的 
  1. 修改config目录下的 application.yml 文件

默认使用的是h2存储数据,修改为es7

selector: ${SW_STORAGE:elasticsearch7}

  1. 进入bin目录启动
nohup nice sh startup.sh &
  1. 打开 webapp/webapp.yml文件 查看UI访问端口

  2. 访问 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支持的几种配置方式:

  1. 系统配置(System properties)
    使用 skywalking. + 配置文件中的配置名作为系统配置项来进行覆盖.

-Dskywalking.agent.service_name=skywalking_mysql

  1. 探针配置(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'

  1. 系统环境变量(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

  1. 添加Jar包 和本地skywalking版本保持一致

            org.apache.skywalking
            apm-toolkit-trace
            8.7.0
        
  1. 编写测试类
//获取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();
    }
  1. 测试

过滤指定的端点

项目中的一些接口是不需要监控指标的,比如Swagger相关的端点,需要进行过滤

  1. 添加可选插件 apm-trace-ignore-plugin-8.7.0.jar 到 plugins目录中

  2. 编写测试类

//此接口可以被追踪
    @GetMapping("/include")
    public String include(){
        return "include";
    }
	
//此接口不可被追踪
    @GetMapping("/exclude")
    public String exclude(){
        return "exclude";
    }
  1. 添加启动参数
- Dskywalking.trace.ignore_path=/exclude
  1. 测试 include接口可以被监控,exclude无法被监控

  2. 匹配多路径
    这里添加-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

  1. 配置文件修改
webhooks:
  - http://127.0.0.1:8801/webhook
  1. 接收告警信息 自行处理
    产生告警时会调用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 包。

  1. 这个 jar 包的 MANIFEST.MF 文件必须指定 Premain-Class 项。
  2. Premain-Class 指定的那个类必须实现 premain() 方法。

当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行 -javaagent 所指定 jar 包内PremainClass 这个类的 premain 方法 。

如何使用java agent

使用 java agent 需要几个步骤:

  1. 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-RedefineClasses 和 Can-Retransform-Classes 选项。
  2. 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
  3. 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
  4. 使用参数 -javaagent: jar包路径 启动要代理的方法。

自定义Agent

Skywalking中对每个调用的时长都进行了统计,我们可以使用ByteBuddyJava agent技术来模拟实现skywalking统计方法的调用时长

  1. 新建maven项目 agent

            net.bytebuddy
            byte-buddy
            1.9.2
        
        
            net.bytebuddy
            byte-buddy-agent
            1.9.2
        
  1. 编写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);
    }
  1. 编写拦截方法
@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");
        }
    }
  1. 指定build方法

        
            
                maven-assembly-plugin
                
                    false
                    
                        jar-with-dependencies
                    
                    
                        
                        
                            true
                        
                        
                            com.PreMainAgent
                            com.PreMainAgent
                            true
                            true
                        
                    
                
                
                    
                        make-assembly
                        package
                        
                            single
                        
                    
                
            
        
    
  1. 新建测试项目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

  1. 测试 可以发现运行时自动执行了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语句等内容。