skywalking操作手册

1. Skyalking介绍

1.1 Skywalking概述

SkyWalking 是一个开源可观测性平台,用于收集、分析、聚合和可视化来自服务和云原生的数据 基础 设施。SkyWalking 提供了一种简单的方法来保持分布式系统的清晰视图,甚至可以跨云。 它是一个现代 APM,专为云原生、基于容器的分布式系统而设计。

1.2 Skywalking整体架构

在这里插入图片描述

SkyWalking在逻辑上分为四个部分:探针,平台后端,存储和UI。

  1. 探测器收集遥测数据,包括各种格式(SkyWalking,Zipkin,OpenTelemetry,Prometheus,Zabbix等)的指标,跟踪,日志和事件。

    2. 平台后端支持数据聚合、分析和流流程,涵盖跟踪、指标、日志和事件。充当聚合器角色和/或接收者角色。

    3. 存储通过开放/可插拔接口存储SkyWalking数据。您可以选择现有实现,例如 ElasticSearch,H2,MySQL,TiDB,BanyanDB,或者实现你自己的。

    4. UI是一个高度可定制的基于Web的界面,允许SkyWalking最终用户可视化和管理SkyWalking数据。

2.Skyalking部署

安装包下载

https://skywalking.apache.org/downloads/

注意:目前最高版本为OAP 9.4.0版本【注意9.4.0 未测试jdk1.8 可能无法使用,因此建议使用的9.3.0版本 】,Agent版本为8.14

2.1 服务端OAP部署

2.1.1修改配置文件

进去config目录,找到oap配置文件 application.yml

在这里插入图片描述

里面有很多模块配置项,具体配置可以看官方文档,此处我们只修改oap数据源,其余保持默认,找到配置文件中的storage 模块,可以看到里面很多数据源配置,elasticserch,h2,mysql等,此处我们选择elasticsearch作为数据存储,修改selector 值即可。

在这里插入图片描述

2.1.2 启动OAP组件

进入bin目录

在这里插入图片描述

可以看到bin目录下有bat脚本和sh脚本,其中oapService是oap的启动脚本,其中分为两种类型,init和非init,如果用init的脚本启动,则会初始化oap的数据库相关表或者es 索引,非init则直接启动oap服务。所以第一次启动我们选择oapServiceInit.bat 启动,初始化es 相关索引,下次启动用oapService.bat启动即可。

2.2 服务端UI部署

2.2.1 修改配置文件

​ 进入webapp目录,webapp.yml为ui服务的配置文件,里面有端口号以及spring cloud gateway的相关配置

在这里插入图片描述

2.2.2 启动ui服务

进入bin目录,使用webappService.sh启动即可

2.3 客户端Agent部署

2.3.1 javaagent 目录介绍

Agent目录结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dcDm7Gb4-1679988433405)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230328150916449.png)]

在这里插入图片描述

2.3.2 集成javaAgent插件

1、配置文件

Javaagent配置文件在 agent config目录下,具体参数请参考官网介绍,其中

agent.service_name 为服务名称,其他默认,我们修改此项即可。

在这里插入图片描述

部分配置说明:

  • agent.namespace:命名空间,可通过此参数实现隔离 agent.service_name:在链路追踪 UI

    中展示的应用名,如果是微服务架构,可以和注册中心中的应用名一致

    agent.is_cache_enhanced_class:如果为true,则SkyWalking代理会将所有检测到的类文件缓存到内存或磁盘文件中(由类缓存模式决定) collector.backend_service:后端Collector收集器的地址 logging.file_name:日志文件名

    logging.level:日志等级 logging.max_file_size:日志文件大小控制

    logging.max_history_files:历史日志文件个数控制 plugin.mount:挂载插件的文件夹名

    plugin.mysql.trace_sql_parameters:收集sql的参数

    agent.ignore_suffix,表示对请求追踪进行忽略,多个路径用逗号分隔,在实际的生产环境中某些请求是不需要被追踪的,例如心跳检查/health,监控指标/metrics等等,我们需要将对应的插件jar包apm-trace-ignore-plugin-8.4.0.jar拷贝到plugins目录下并进行对应的配置,配置文件内容部分如下

# If the operation name of the first span is included in this set, this segment should be ignored. Multiple values should be separated by `,`.#agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}
2.3.3 javaagent集成

在这里插入图片描述

   常用配置:
   -javaagent:/opt/skwalking/skywalking-agent/skywalking-agent.jar
   -Dskywalking.agent.service_name=服务名
   -Dskywalking.collector.backed_service=127.0.0.1:11800  --OAP通讯地址

3.Skywalking自定义链路追踪

3.1 概念

Span

  1. EntrySpan代表服务提供商。它也是服务器端的端点。作为一个APM系统,我们的目标是 应用程序服务器。因此,几乎所有的服务和MQ消费者都是EntrySpan。
  2. LocalSpan 表示一种不涉及远程服务的普通 Java 方法。它既不是 MQ 生产者/消费者 也不是服务(例如 HTTP 服务)提供者/消费者。
  3. ExitSpan 表示服务的客户端或 MQ 生产者。它在SkyWalking的早期版本中被命名。 例如,通过JDBC访问数据库和读取Redis/Memcached被归类为ExitSpan。LeafSpan

ContextCarrier

为了实现分布式跟踪,必须绑定跨进程跟踪,并且上下文必须传播 在整个过程中。这就是ContextCarrier的用武之地。

以下是有关如何在分布式呼叫中使用上下文载体的步骤。A->B

1.在客户端创建一个新的空。ContextCarrier

2.创建退出跨度 或 用于启动 .ContextManager#createExitSpanContextManager#injectContextCarrier

3.将所有项目放入heads(例如HTTP HEAD),附件(例如Dubbo RPC框架)或消息(例如Kafka)中。ContextCarrier

4.通过服务调用传播到服务器端。ContextCarrier

5.在服务器端,从标题、附件或消息中获取所有项目。

6.创建 EntrySpan 或用于绑定客户端和服务器端。ContextManager#createEntrySpanContextManager#extract

服务器端使用 Tomcat 7 服务器插件

ContextCarrier contextCarrier = new ContextCarrier();
            CarrierItem next = contextCarrier.items();
            while (next.hasNext()) {
                next = next.next();
                next.setHeadValue(request.getHeader(next.getHeadKey()));
            }

ContextSnapshot

除了跨进程跟踪之外,还必须支持跨线程跟踪。例如,两个异步进程(内存中 MQ) 和批处理在 Java 中很常见。跨进程和跨线程跟踪非常相似,因为它们都需要传播 上下文,但跨线程跟踪不需要序列化。

以下是跨线程传播的三个步骤:

1.用于获取 ContextSnapshot 对象。ContextManager#capture

2.让子线程通过方法参数或由现有参数携带访问 ContextSnapshot

3.在子线程中使用。ContextManager#continued

3.2 Tracing API 接口跟踪

依赖工具包

 
      org.apache.skywalking
      apm-toolkit-trace
      ${skywalking.version}
   

使用 API 获取traceID。TraceContext.traceId()

使用 API 获取segmentID。TraceContext.segmentId()

使用 API 获取 spanId。TraceContext.spanId()

@Trace注释的方法将尝试使用给定的键 () 和 () 标记当前活动范围 如果根本没有活动跨度,则此注释无效。 可以重复使用,并且可以与 一起使用,请参阅下面的示例。 的与自定义增强跟踪中支持的内容相同。@TagTag#key()Tag#value()@Tag@TracevalueTag

在跟踪方法的上下文中添加自定义标记。ActiveSpan.tag(“key”, “val”)

ActiveSpan.error()将当前范围标记为错误状态。

ActiveSpan.error(String errorMsg)使用消息将当前范围标记为错误状态。

ActiveSpan.error(Throwable throwable)使用可抛出对象将当前范围标记为错误状态。

ActiveSpan.debug(String debugMsg)在当前范围中添加调试级别日志消息。

ActiveSpan.info(String infoMsg)在当前范围中添加信息级别日志消息。

ActiveSpan.setOperationName(String operationName)自定义操作名称。

3.2.1 侵入式追踪

如果要用@tag或@tags注解,前提是必须要使用@Trace注解,不然仅仅给业务方法加@Tag注解的话,SkyWalking也不会显示

@Tag注解中key我们可以自定义,而value的写法就固定了,如果要查看返回值就只能写returnedObj,如果要查看请求参数就只能用arg,下标代表第几个请求参数

返回值的对象,注意要重写toString()方法,不然在SkyWalking的界面中显示的只是一个对象的内存地址

3.2.2 非侵入式追踪

  1. 激活插件,将插件从optional-plugins/apm-customize-enhance-plugin-x.x.x.jar移动到plugin/apm-customize-enhance-plugin-x.x.x.jar。
  2. 在agent.config中配置plugin.customize.enhance_file,指明增强规则文件,比如/absolute/path/to/customize_enhance.xml。
  3. 在customize_enhance.xml中配置增强规则

    
        
        
            arg[0]
            arg[2].['k1']
            arg[4].[1]
        
        
    


文件中的配置说明

配置 说明
class_name 要被增强的类
method 类的拦截器方法
operation_name 如果进行了配置,将用它替代默认的operation_name
operation_name_suffix 表示在operation_name后添加动态数据
static 方法是否为静态方法
tag 将在local span中添加一个tag。key的值需要在XML节点上表示。
log 将在local span中添加一个log。key的值需要在XML节点上表示。
arg[x] 表示输入的参数值。比如args[0]表示第一个参数。
.[x] 当正在被解析的对象是Array或List,你可以用这个表达式得到对应index上的对象。
.[‘key’] 当正在被解析的对象是Map, 你可以用这个表达式得到map的key。

3.3 openTracing API 接口跟踪

依赖工具包,例如使用 maven 或 gradle

   
      org.apache.skywalking
      apm-toolkit-opentracing
      {project.release.version}
   

代码示例:

Tracer tracer = new SkywalkingTracer();
Tracer.SpanBuilder spanBuilder = tracer.buildSpan("/yourApplication/yourService");

3.4 跨线程追踪

​ SkyWalking提供了跨线程构建Trace的能力,通过对 Callable、Runnable、Supplier 这3种接口的实现者进行增强拦截,将 Trace 的上下文信息传递到子线程中,实现了异步链路追踪。有非常多的方式来实现Callable,Runnable,Supplier 这3种接口。

SkyWalking提供了一种既通用又快捷的方式来规范这一现象:

1.只拦截增强带有@TraceCrossThread 注解的类;

2.通过装饰的方式包装任务,避免大刀阔斧的修改

原始类 提供的包装类 拦截方法 使用技巧
Callable CallableWrapper call CallableWrapper.of(xxxCallable)
Runnable RunnableWrapper run RunnableWrapper.of(xxxRunable)
Supplier SupplierWrapper get SupplierWrapper.of(xxxSupplier)

包装类 都有注解 @TraceCrossThread ,skywalking内部的拦截匹配逻辑是,标注了@TraceCrossThread的类,拦截 其名称为call 或run或 get ,且没有入参的方法;对使用者来说大致分为2种方式:

1.自定义类,实现接口 Callable、Runnable、Supplier,加@TraceCrossThread注解。当需要有更多的自定义属性时,考虑这种方式;参考 CallableWrapper、RunnableWrapper 、SupplierWrapper 的实现方式。

通过xxxWrapper.of 装饰的方式,即CallableWrapper.of(xxxCallable)、RunnableWrapper.of(xxxRunable)、SupplierWrapper.of(xxxSupplier)。大多情况下,通过这种包装模式即可。

依赖工具包,例如使用 maven 或 gradle

 
      org.apache.skywalking
      apm-toolkit-trace
      ${skywalking.version}
   

用法 1.

 @TraceCrossThread
    public static class MyCallable implements Callable {
        @Override
        public String call() throws Exception {
            return null;
        }
    }...
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    executorService.submit(new MyCallable());

用法 2.

    ExecutorService executorService = Executors.newFixedThreadPool(1);
    executorService.submit(CallableWrapper.of(new Callable() {
        @Override public String call() throws Exception {
            return null;
        }
}));
或
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    executorService.execute(RunnableWrapper.of(new Runnable() {
        @Override public void run() {
            //your code        }
    }));

用法 3.

    @TraceCrossThread
    public class MySupplier implements Supplier {
        @Override
        public String get() {
            return null;
        }
    }...
    CompletableFuture.supplyAsync(new MySupplier());
或
    CompletableFuture.supplyAsync(SupplierWrapper.of(()->{
            return "SupplierWrapper";
    })).thenAccept(System.out::println);

用法 4.

    CompletableFuture.supplyAsync(SupplierWrapper.of(() -> {
        return "SupplierWrapper";
    })).thenAcceptAsync(ConsumerWrapper.of(c -> {
        // your code visit(url)        System.out.println("ConsumerWrapper");
    }));
或
    CompletableFuture.supplyAsync(SupplierWrapper.of(() -> {
        return "SupplierWrapper";
    })).thenApplyAsync(FunctionWrapper.of(f -> {
        // your code visit(url)        return "FunctionWrapper";
    }));

3.5自定义插件

3.5.1 引入依赖


    4.0.0

    com.itmuch.skywalking
    apm-string-plugin
    jar
    1.0.0-SNAPSHOT

    
        org.apache.skywalking.apm.dependencies
        net.bytebuddy
        ${shade.package}.${shade.net.bytebuddy.source}
    

    
        
            org.apache.skywalking
            apm-agent-core
            8.12.0
            provided
        

        
            org.apache.skywalking
            apm-util
            8.8.1
            provided
        

        
            org.apache.commons
            commons-lang3
            3.4
            provided
        
    

    
        
            
                maven-shade-plugin
                
                    
                        package
                        
                            shade
                        
                        
                            false
                            true
                            true
                            true
                            
                                
                                    ${shade.net.bytebuddy.source}
                                    ${shade.net.bytebuddy.target}
                                
                            
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    6
                    6
                
            
        
    

3.5.2 继承ClassInstanceMethodsEnhancePluginDefine

非静态

package com.itmuch.skywalking.plugin.define;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.DeclaredInstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;

public class DemoMethodInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {

    public static final String INTERCEPT_CLASS="com.springboot.master.service.impl.AsyncServiceImpl";

    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(INTERCEPT_CLASS);
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[]{
                new DeclaredInstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher getMethodsMatcher() {
                        System.out.println("-----------------------------");
                        return ElementMatchers.named("getCityName");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return "com.itmuch.skywalking.plugin.DemoMethodInterceptor";

                    }

                    @Override
                    public boolean isOverrideArgs() {
                        return false;
                    }
                }
        };
    }
}

静态

package com.itmuch.skywalking.plugin.define;

import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;

public class StringReplaceInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
    @Override
    protected ClassMatch enhanceClass() {
        // 指定想要监控的类
        return NameMatch.byName("org.apache.commons.lang3.StringUtils");
    }

    @Override
    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return new ConstructorInterceptPoint[0];
    }

    @Override
    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        // 指定想要监控的实例方法,每个实例方法对应一个InstanceMethodsInterceptPoint
        return new InstanceMethodsInterceptPoint[0];
    }

    @Override
    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
        // 指定想要监控的静态方法,每一个方法对应一个StaticMethodsInterceptPoint
        return new StaticMethodsInterceptPoint[]{
                new StaticMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher getMethodsMatcher() {
                        // 静态方法名称
                        return ElementMatchers.named("replace");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        // 该静态方法的监控拦截器类名全路径
                        return "com.itmuch.skywalking.plugin.StringReplaceInterceptor";
                    }

                    @Override
                    public boolean isOverrideArgs() {
                        return false;
                    }
                }
        };
    }
}

3.5.3 实现MethodsAroundInterceptor

静态方法实现StaticMethodsAroundInterceptor

package com.itmuch.skywalking.plugin;

import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;

import java.lang.reflect.Method;

public class StringReplaceInterceptor implements StaticMethodsAroundInterceptor {
    @Override
    public void beforeMethod(Class aClass, Method method, Object[] argumentsTypes, Class[] classes, MethodInterceptResult methodInterceptResult) {
        // 创建span(监控的开始),本质上是往ThreadLocal对象里面设值
        AbstractSpan span = ContextManager.createLocalSpan("replace");

        /*
         * 可用ComponentsDefine工具类指定Skywalking官方支持的组件
         * 也可自己new OfficialComponent或者Component
         * 不过在Skywalking的控制台上不会被识别,只会显示N/A
         */
        span.setComponent(ComponentsDefine.TOMCAT);

        span.tag(new StringTag(1000, "params"), argumentsTypes[0].toString());
        // 指定该调用的layer,layer是个枚举
        span.setLayer(SpanLayer.CACHE);
    }

    @Override
    public Object afterMethod(Class aClass, Method method, Object[] objects, Class[] classes, Object o) {
        String retString = (String) o;
        // 激活span,本质上是读取ThreadLocal对象
        AbstractSpan span = ContextManager.activeSpan();
        // 停止span(监控的结束),本质上是清理ThreadLocal对象
        ContextManager.stopSpan();
        return retString;
    }

    @Override
    public void handleMethodException(Class aClass, Method method, Object[] objects, Class[] classes, Throwable throwable) {
        AbstractSpan activeSpan = ContextManager.activeSpan();

        // 记录日志
        activeSpan.log(throwable);
        activeSpan.errorOccurred();
    }
}

非静态方法实现InstanceMethodsAroundInterceptor

package com.itmuch.skywalking.plugin;


import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.StringTag;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;


import java.lang.reflect.Method;

public class DemoMethodInterceptor implements InstanceMethodsAroundInterceptor {

    @Override
    public void beforeMethod(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, MethodInterceptResult methodInterceptResult) throws Throwable {
        // 创建span(监控的开始),本质上是往ThreadLocal对象里面设值
        AbstractSpan span = ContextManager.createLocalSpan("demo");

        /*
         * 可用ComponentsDefine工具类指定Skywalking官方支持的组件
         * 也可自己new OfficialComponent或者Component
         * 不过在Skywalking的控制台上不会被识别,只会显示N/A
         */
        span.setComponent(ComponentsDefine.TOMCAT);

        span.tag(new StringTag(1000, "params"), "demo");
        // 指定该调用的layer,layer是个枚举
        span.setLayer(SpanLayer.CACHE);    }

    @Override
    public Object afterMethod(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, Object o) throws Throwable {
        String retString = (String) o;
        // 激活span,本质上是读取ThreadLocal对象
        AbstractSpan span = ContextManager.activeSpan();
        // 停止span(监控的结束),本质上是清理ThreadLocal对象
        ContextManager.stopSpan();
        return retString;
    }

    @Override
    public void handleMethodException(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class[] classes, Throwable throwable) {

    }
}

3.5.3 在resourse目录下编写skywalking-plugin.def文件

Plugin=com.itmuch.skywalking.plugin.define.StringReplaceInstrumentation
Plugin=com.itmuch.skywalking.plugin.define.DemoMethodInstrumentation

Key随意写 ,value为继承ClassInstanceMethodsEnhancePluginDefine类的全路径,注意多个key最好保持一致

文件名固定为skywalking-plugin.def

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://www.net2asp.com/ea1c9a3e6e.html