东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

SkyWalking 之高级用法

  • 2019-09-25
  • 本文字数:4457 字

    阅读完需:约 15 分钟

SkyWalking之高级用法

1 导读

SkyWalking 中 Java 探针是使用 JavaAgent 的两大字节码操作工具之一的 Byte Buddy(另外是 Javassist)实现的。项目还包含.Net core 和 Nodejs 自动探针,以及 Service Mesh Istio 的监控。总体上,SkyWalking 是一个多语言,多场景的适配,特别为微服务、云原生和基于容器架构设计的可观测性分析平台(Observability Analysis Platform)。


本文基于 SkyWalking 5.0.0-RC2 和 Byte Buddy 1.7.9 版本,会从以下几个章节,让大家掌握 SkyWalking Java 探针的使用,进而让 SkyWalking 在自己公司中的二次开发变得触手可及。


  • Byte Buddy 实现 JavaAgent 项目

  • 迭代 JavaAgent 项目的方法论

  • SkyWalking agent 项目如何 Debug

  • SkyWalking 插件开发实践


文章底部有 SkyWalking 和 Byte Buddy 相应的学习资源。

2Byte Buddy 实现

首先如果你对 JavaAgent 还不是很了解可以先百度一下,或在公众号内看下《JavaAgent 原理与实践》简单入门下。


SpringMVC 分发请求的关键方法相信已经不用我在赘述了,那我们来编写 Byte Buddy JavaAgent 代码吧。


 1 public class AgentMain { 2    public static void premain(String agentOps, Instrumentation instrumentation) { 3        new AgentBuilder.Default() 4                .type(ElementMatchers.named("org.springframework.web.servlet.DispatcherServlet")) 5                .transform((builder, type, classLoader, module) -> 6                        builder.method(ElementMatchers.named("doDispatch")) 7                                .intercept(MethodDelegation.to(DoDispatchInterceptor.class))) 8                .installOn(instrumentation); 9    }10}
复制代码


编写 DispatcherServlet doDispatch 拦截器代码(是不是跟 AOP 如出一辙)


 1 public class DoDispatchInterceptor { 2    @RuntimeType 3    public static Object intercept(@Argument(0) HttpServletRequest request, @SuperCall Callable<?> callable) { 4        final StringBuilder in = new StringBuilder(); 5        if (request.getParameterMap() != null && request.getParameterMap().size() > 0) { 6            request.getParameterMap().keySet().forEach(key -> in.append("key=" + key + "_value=" + request.getParameter(key) + ",")); 7        } 8        long agentStart = System.currentTimeMillis(); 9        try {10            return callable.call();11        } catch (Exception e) {12            System.out.println("Exception :" + e.getMessage());13            return null;14        } finally {15            System.out.println("path:" + request.getRequestURI() + " 入参:" + in + " 耗时:" + (System.currentTimeMillis() - agentStart));16        }17    }18}
复制代码


resources/META-INF/MANIFEST.MF


1Manifest-Version: 1.02Premain-Class: com.z.test.agent.AgentMain3Can-Redefine-Classes: true
复制代码


pom.xml 文件


1dependencies2    +net.bytebuddy.byte-buddy 3    +javax.servlet.javax.servlet-api *scope=provided4plugins5    +maven-jar-plugin *manifestFile=src/main/resources/META-INF/MANIFEST.MF6    +maven-shade-plugin *include:net.bytebuddy:byte-buddy:jar:7    +maven-compiler-plugin
复制代码


小结:没几十行代码就完成了,通过 Byte Buddy 实现应用组件 SpringMVC 记录请求路径、入参、执行时间 JavaAgent 项目,是不是觉得自己很优秀。

3 持续迭代 JavaAgent

本章节主要介绍 JavaAgent 如何 Debug,以及持续集成的方法论。


首先我的 JavaAgent 项目目录结构如图所示:



用项目是用几行代码实现的 SpringBootWeb 项目:


 1@SpringBootApplication(scanBasePackages = {"com"}) 2public class TestBootWeb { 3    public static void main(String[] args) { 4        SpringApplication.run(TestBootWeb.class, args); 5    } 6    @RestController 7    public class ApiController { 8        @PostMapping("/ping") 9        public String ping(HttpServletRequest request) {10            return "pong";11        }12    }13}
复制代码


下面是关键 JavaAgent 项目如何持续迭代与集成:


``


1VM options 增加:-JavaAgent:{$HOME}/Code/github/z_my_test/test-agent/target/test-agent-1.0-SNAPSHOT.jar=args


2Before launch 在 Build 之前增加:


3 Working directory:{$HOME}/Code/github/incubator-skywalking


4 Command line:-T 1C -pl test-agent -am clean package -Denforcer.skip=true -Dmaven.test.skip=true -Dmaven.compile.fork=true


小结:看到这里的将 JavaAgent 持续迭代集成方法,是不是瞬间觉得自己手心已经发痒起来,很想编写一个自己的 agent 项目了呢,等等还有一个好消息:test-demo 这 10 几行的代码实现的 Web 服务,居然有 5k 左右的类可以使用 agent 增强。


注意 mvn 编译加速的命令是 maven3+版本以上才支持的哈。

4SkyWalking Debug

峰回路转,到了文章的主题《SkyWalking 之高级用法》的正文啦。首先,JavaAgent 项目想 Debug,还需要将 agent 代码与接入 agent 项目至少在同一个工作空间内,网上方法有很多,这里我推荐大家一个最简单的方法。File->New->Module from Exisiting Sources…引入 skywalking-agent 源码即可



详细的 idea 编辑器配置:



优化 SkyWalking agent 编译时间,我的集成时间优化到 30 秒左右:


1VM options增加:-JavaAgent:-JavaAgent:{$HOME}/Code/github/incubator-skywalking/skywalking-agent/skywalking-agent.jar:不要用dist里面的skywalking-agent.jar,具体原因大家可以看看源码:apm-sniffer/apm-agent/pom.xml中的maven插件的使用。2Before launch 在Build之前增加:3    Working directory:{$HOME}/Code/github/incubator-skywalking4    Command line:-T 1C -pl apm-sniffer/apm-sdk-plugin -amd clean package -Denforcer.skip=true -Dmaven.test.skip=true -Dmaven.compile.fork=true:这里我针对插件包,因为紧接着下文要开发插件5另外根pom注释maven-checkstyle-plugin也可加速编译
复制代码

5kob 之 SkyWalking 插件编写

kob(贝壳分布式作业调度框架)是贝壳找房项目微服务集群中的基础组件,通过编写贝壳分布式作业调度框架的 SkyWalking 插件,可以实时收集作业调度任务的执行链路信息,从而及时得到基础组件的稳定性,了解细节可点击阅读《贝壳分布式调度框架简介》。想详细了解 SkyWalking 插件编写可在文章底部参考链接中,跳转至对应的官方资源,好话不多说,代码一把唆起来。


apm-sdk-plugin pom.xml 增加自己的插件 model


1<artifactId>apm-sdk-plugin</artifactId>2    <modules>3        <module>kob-plugin</module>4        ...5    <modules>
复制代码


resources.skywalking-plugin.def 增加自己的描述


1kob=org.apache.skywalking.apm.plugin.kob.KobInstrumentation
复制代码


在 SkyWalking 的项目中,通过继承 ClassInstanceMethodsEnhancePluginDefine 可以定义需要拦截的类和增强的方法,编写作业调度方法的 instrumentation


 1public class KobInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { 2    private static final String ENHANCE_CLASS = "com.ke.kob.client.spring.core.TaskDispatcher"; 3    private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.kob.KobInterceptor"; 4    @Override 5    protected ClassMatch enhanceClass() { 6        return NameMatch.byName(ENHANCE_CLASS); 7    } 8    @Override 9    protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {10        return null;11    }12    @Override13    protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {14        return new InstanceMethodsInterceptPoint[] {15                new InstanceMethodsInterceptPoint() {16                    @Override17                    public ElementMatcher<MethodDescription> getMethodsMatcher() {18                        return named("dispatcher1");19                    }20                    @Override21                    public String getMethodsInterceptor() {22                        return INTERCEPT_CLASS;23                    }24                    @Override25                    public boolean isOverrideArgs() {26                        return false;27                    }28                }29        };30    }31}
复制代码


通过实现 InstanceMethodsAroundInterceptor 后,定义 beforeMethod、afterMethod 和 handleMethodException 的实现方法,可以环绕增强指定目标方法,下面自定义 interceptor 实现 span 的跟踪(这里需要注意 SkyWalking 中 span 的生命周期,在 afterMethod 方法中结束 span)


 1public class KobInterceptor implements InstanceMethodsAroundInterceptor { 2    @Override 3    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,  Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { 4        final ContextCarrier contextCarrier = new ContextCarrier(); 5        com.ke.kob.client.spring.model.TaskContext context = (TaskContext) allArguments[0]; 6        CarrierItem next = contextCarrier.items(); 7        while (next.hasNext()) { 8            next = next.next(); 9            next.setHeadValue(JSON.toJSONString(context.getUserParam()));10        }11        AbstractSpan span = ContextManager.createEntrySpan("client:"+allArguments[1]+",task:"+context.getTaskKey(), contextCarrier);12        span.setComponent(ComponentsDefine.TRANSPORT_CLIENT);13        SpanLayer.asRPCFramework(span);14    }15    @Override16    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {17        ContextManager.stopSpan();18        return ret;19    }20    @Override21    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {22    }23}
复制代码


实现效果,将操作名改成任务执行节点+任务执行方法,实现 kob 的 SkyWalking 的插件编写,加上报警体系,可以进一步增加公司基础组件的稳定性。


作者介绍:


奇佐(企业代号名),目前负责贝壳找房 java 后端开发工作。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/6tRxWl_XYqDeIAx2fp4S5Q


2019-09-25 17:151990

评论

发布
暂无评论
发现更多内容

设计模式【6.1】-- 初探适配器模式

秦怀杂货店

Java 设计模式

今年双12,《代码随想录》冲榜TOP1

博文视点Broadview

推倒重来的觉悟

FunTester

单元测试 Mockito powermock spock FunTester

OPPO云VPC网络实践

安第斯智能云

云计算 SDN架构 智能网卡vpc

React进阶(四):路由介绍

No Silver Bullet

React 路由 12月日更

Vue之全局事件总线和消息订阅与发布

编程江湖

前端开发

大数据开发技术NN和2NN工作机制

编程江湖

大数据

JavaMoney规范(JSR 354)与对应实现解读

vivo互联网技术

Java、 API 虚拟化 虚拟货币

dart系列之:安全看我,dart中的安全特性null safety

程序那些事

flutter dart 程序那些事 12月日更 flutter 调试工具

云原生时代,领域驱动设计思想(DDD)如何落地?

华为云开发者联盟

软件架构 架构设计 建模 领域驱动设计思想 领域模型

给弟弟的信第12封|阅读对一个人有多重要

大菠萝

28天写作

使用 JavaScript 给微信用户发送消息

Jerry Wang

微信 sdk 28天写作 Web JS SDK 12月日更

Linux学习方法《Linux一学就会》:网络管理技术

侠盗安全

Linux linux运维 运维工程师 云计算架构师

技术分享| Linux高并发踩过的坑及性能优化

anyRTC开发者

Linux 音视频 高并发 服务器 高并发优化

在中国如何打造一个有生命力的开源项目?

Jianmu

DevOps 持续集成 CI/CD 开源社区 持续部署

龙蜥社区一周动态 | 12.06-12.10

OpenAnolis小助手

龙蜥社区

阿里巴巴、埃森哲、德勤三方圆桌对话——《与数字化先锋共绘创新蓝图》

大咖说

阿里巴巴 大咖说 数字经济 数智化

基于JSX的全新BDD工具 - Crius

RingCentral铃盛

面试官:说说react的渲染过程

全栈潇晨

React

设计模式【6.2】-- 再聊聊适配器模式

秦怀杂货店

Java 设计模式 适配器模式

初识腾讯移动通讯 TPNS~

阿策小和尚

28天写作 Android 小菜鸟 12月日更

Java反射机制获取运行时类的完整结构

编程江湖

JAVA开发

【LeetCode】保持城市天际线Java题解

Albert

算法 LeetCode 12月日更

react源码解析10.commit阶段

buchila11

React

0 基础学习 Flutter~(mini 进阶版)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter 内容合集 签约计划第二季

❤️使用 HTML、CSS 和 JS 创建在线音乐播放器(免费送完整源码)❤️

海拥(haiyong.site)

响应式 大前端 28天写作 签约计划第二季 12月日更

前端开发之cypress的自动化实践

@零度

前端 Cypress

音视频学习--X264码率控制--前瞻

Fenngton

音视频 H264 视频编解码 签约计划第二季

react源码解析9.diff算法

buchila11

React

使用 scipy.fft 进行Fourier Transform:Python 信号处理

华为云开发者联盟

Python 音频 信号处理 傅立叶变换 Fourier transform

存储空间降为原来的1/7,TDengine在中移物联网轨迹数据存储中的应用

TDengine

数据库 tdengine 时序数据库

SkyWalking之高级用法_文化 & 方法_奇佐_InfoQ精选文章