skywalking学习笔记

前言

随着业务越来越复杂,企业应用也进入了分布式服务化的阶段,传统的日志监控等方式无法很好达到跟踪调用,排查问题等需求。在谷歌论文《 Dapper,大规模分布式系统的跟踪系统》的指导下,许多优秀的APM应运而生。

分布式追踪系统发展很快,种类繁多,给我们带来很大的方便。但在数据采集过程中,有时需要侵入用户代码,并且不同系统的 API 并不兼容,这就导致了如果您希望切换追踪系统,往往会带来较大改动。OpenTracing为了解决不同的分布式追踪系统 API 不兼容的问题,诞生了 OpenTracing 规范。OpenTracing 是一个轻量级的标准化层,它位于应用程序/类库和追踪或日志分析程序之间。详细介绍见 opentracing文档中文版。

本文要介绍的就是国人吴晟基于OpenTracking实现的开源项目skywalking(码云、github)。

skywalking简介

针对分布式系统的APM(应用性能监控)系统,特别针对微服务、cloud native和容器化(Docker, Kubernetes, Mesos)架构, 其核心是个分布式追踪系统。

特点

  • 性能好
    针对单实例5000tps的应用,在全量采集的情况下,只增加 10% 的CPU开销。详细评测见《skywalking agent performance test》。

  • 支持多语言探针

  • 支持自动及手动探针
    自动探针:Java支持的中间件、框架与类库列表
    手动探针:OpenTrackingApi、@Trace注解、trackId集成到日志中。

架构

安装

  • agent
    探针,用来收集和发送数据到归集器。

    1. 增加jvm参数 -javaagent:/path/to/skywalking-agent/skywalking-agent.jar
    2. 配置conf文件 /config/agent.config
    
    # 当前的应用编码,最终会显示在webui上。
    # 建议一个应用的多个实例,使用有相同的application_code。请使用英文
    agent.application_code=Your_ApplicationName
    
    # 每三秒采样的Trace数量
    # 默认为负数,代表在保证不超过内存Buffer区的前提下,采集所有的Trace
    # agent.sample_n_per_3_secs=-1
    
    # 设置需要忽略的请求地址
    # 默认配置如下
    # agent.ignore_suffix=.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg
    
    # 探针调试开关,如果设置为true,探针会将所有操作字节码的类输出到/debugging目录下
    # skywalking团队可能在调试,需要此文件
    # agent.is_open_debugging_class = true
    
    # 对应Collector的config/application.yml配置文件中 agent_server/jetty/port 配置内容
    # 例如:
    # 单节点配置:SERVERS="127.0.0.1:8080" 
    # 集群配置:SERVERS="10.2.45.126:8080,10.2.45.127:7600" 
    collector.servers=127.0.0.1:10800
    
    # 日志文件名称前缀
    logging.file_name=skywalking-agent.log
    
    # 日志文件最大大小
    # 如果超过此大小,则会生成新文件。
    # 默认为300M
    logging.max_file_size=314572800
    
    # 日志级别,默认为DEBUG。
    logging.level=DEBUG
    复制代码
    1. 启动被监控应用
  • collector
    链路数据归集器,数据可以落地ElasticSearch,单机也可以落地H2,不推荐,H2仅作为临时演示用。

  • web
    web可视化平台,用来展示落地的数据。

  • ui
    单独的开源ui项目,更美观易用。demo

界面

  • 拓扑
  • 实例
  • 系统监控
  • 调用链路
  • span
  • 服务

对比

分布式链路追踪技术对比

技术

  • Java Agent
    Java agent是用一个简单的jar文件来表示的。跟普通的Java程序很相似,Java agent定义了一些类作为入口点。 这些作为入口点的类需要包含一个静态方法,这些方法会在你原本的Java程序的main方法调用之前被调用:

    class MyAgent {
      public static void premain(String args, Instrumentation inst) {
        // implement agent here ...
      }
    }
    复制代码

    关于处理Java agent时最有趣的部分,是premain方法中的第二个参数。这个参数是以一个Instrumentation接口的实现类实例的形式存在的。这个接 口提供了一种机制,能够通过定义一个ClassFileTransformer,来干预对Java类的加载过程。有了这种转设施,我们就能够在Java类 被使用之前,去实现对类逻辑的强化。
    在最基本的用例中,Java agent会用来设置应用属性或者配置特定的环境状态,agent能够作为可重用和可插入的组件。如下的样例描述了这样的一个agent,它设置了一个系统属性,在实际的程序中就可以使用该属性了:

    public class Agent {
      public static void premain(String arg) {
        System.setProperty("my-property", “foo”);
      }
    }
    复制代码

    如果要使用这个agent,必须要将agent类和资源打包到jar中,并且在jar的manifest中要将Agent-Class属性设置为包含premain方法的agent类。(agent必须要打包到jar文件中,它不能通过拆解的格式进行指定。)接下来,我们需要启动应用程序,并且在命令行中通过javaagent参数来引用jar文件的位置:

    java -javaagent:myAgent.jar -jar myProgram.jar
    复制代码

    我们还可以在位置路径上设置可选的agent参数。在下面的命令中会启动一个Java程序并且添加给定的agent,将值myOptions作为参数提供给premain方法:

    java -javaagent:myAgent.jar=myOptions -jar myProgram.jar
    复制代码

    通过重复使用javaagent命令,能够添加多个agent。
    但是,Java agent的功能并不局限于修改应用程序环境的状态,Java agent能够访问Java instrumentation API,这样的话,agent就能修改目标应用程序的代码。Java虚拟机中这个鲜为人知的特性提供了一个强大的工具,有助于实现面向切面的编程。
    如果要对Java程序进行这种修改,我们需要在agent的premain方法上添加类型为Instrumentation的第二个参数。Instrumentation参数可以用来执行一系列的任务,比如确定对象以字节为单位的精确大小以及通过注册ClassFileTransformers实际修改类的实现。ClassFileTransformers注册之后,当类加载器(class loader)加载类的时候都会调用它。当它被调用时,在类文件所代表的类加载之前,类文件transformer有机会改变或完全替换这个类文件。按照这种方式,在类使用之前,我们能够增强或修改类的行为,如下面的样例所示:

    public class Agent {
     public static void premain(String argument, Instrumentation inst) {
       inst.addTransformer(new ClassFileTransformer() {
         @Override
         public byte[] transform(
           ClassLoader loader,
           String className,
           Class classBeingRedefined, // 如果类之前没有加载的话,值为null
           ProtectionDomain protectionDomain,
           byte[] classFileBuffer) {
           // 返回改变后的类文件。
         }
       });
     }
    }
    复制代码

    通过使用Instrumentation实例注册上述的ClassFileTransformer之后,每个类加载的时候,都会调用这个transformer。为了实现这一点,transformer会接受一个二进制和类加载器的引用,分别代表了类文件以及试图加载类的类加载器。
    Java agent也可以在Java应用的运行期注册,如果是在这种场景下,instrumentation API允许重新定义已加载的类,这个特性被称之为“HotSwap”。不过,重新定义类仅限于替换方法体。在重新定义类的时候,不能新增或移除类成员,并且类型和签名也不能进行修改。当类第一次加载的时候,并没有这种限制,如果是在这样的场景下,那classBeingRedefined会被设置为null。

  • Byte Buddy
    Byte Buddy是开源的、基于Apache 2.0许可证的库,它致力于解决字节码操作和instrumentation API的复杂性。Byte Buddy所声称的目标是将显式的字节码操作隐藏在一个类型安全的领域特定语言背后。通过使用Byte Buddy,任何熟悉Java编程语言的人都有望非常容易地进行字节码操作。 作为Byte Buddy的简介,如下的样例展现了如何生成一个简单的类,这个类是Object的子类,并且重写了toString方法,用来返回“Hello World!”。与原始的ASM类似,“intercept”会告诉Byte Buddy为拦截到的指令提供方法实现:

    Class dynamicType = new ByteBuddy()
      .subclass(Object.class)
      .method(ElementMatchers.named("toString"))
      .intercept(FixedValue.value("Hello World!"))
      .make()
      .load(getClass().getClassLoader(),          
            ClassLoadingStrategy.Default.WRAPPER)
      .getLoaded();
    复制代码

    详见ByteBuddy作者的《Make agents, not frameworks》及译文《构建Java Agent,而不是使用框架》。

源码分析

  • Agent模块

    1. 加载配置信息
    2. 加载插件
    3. 加载所需服务
    4. 使用ByteBuddy增强class

    详见skywalking源码分析之javaAgent工具ByteBuddy的应用 。

更详细的源码分析见芋道源码-skywailking。

参考

Apache SkyWalking
分布式链路追踪&应用监控APM软件-skywalking

转载于:https://juejin.im/post/5ab5b0e26fb9a028e25d7fcb

你可能感兴趣的:(skywalking学习笔记)