SkyWalking之高級玩法

導讀

  • SkyWalking是基於javaagent的兩大字節碼操做工具之一的Byte Buddy實現的無侵入APM(application performance monitor) 系統,目前項目在Apache孵化器中,想了解SkyWalking和Byte Buddy源碼的同窗可在文章底部參考連接中,跳轉至對應的官方資源。
  • 本文會已經過Byte Buddy實現應用組件SpringMVC記錄請求路徑、入參、執行時間的javagent項目、持續迭代javaagent項目的方法論、SkyWalking agent在項目如何持續debug插件代碼、以及SkyWalking插件開發實踐的四個章節,讓你們掌握SkyWalking的玩法,進而讓SkyWalking在本身公司中的二次開發變得觸手可及。

Byte Buddy實現

  • 首先若是你對javaagent還不是很瞭解能夠先百度一下,或在公衆號內看下《JavaAgent原理與實踐》簡單入門下。SpringMVC分發請求的關鍵方法相信已經不用我在贅述了,讓咱們代碼代碼一把唆吧。
  • 編寫Byte Buddy javaagent代碼
public class AgentMain {
    public static void premain(String agentOps, Instrumentation instrumentation) {
        new AgentBuilder.Default()
                .type(ElementMatchers.named("org.springframework.web.servlet.DispatcherServlet"))
                .transform((builder, type, classLoader, module) ->
                        builder.method(ElementMatchers.named("doDispatch"))
                                .intercept(MethodDelegation.to(DoDispatchInterceptor.class)))
                .installOn(instrumentation);
    }
}
複製代碼
  • 編寫DispatcherServlet doDispatch攔截器代碼(是否是跟AOP一模一樣)
public class DoDispatchInterceptor {
    @RuntimeType
    public static Object intercept(@Argument(0) HttpServletRequest request, @SuperCall Callable<?> callable) {
        final StringBuilder in = new StringBuilder();
        if (request.getParameterMap() != null && request.getParameterMap().size() > 0) {
            request.getParameterMap().keySet().forEach(key -> in.append("key=" + key + "_value=" + request.getParameter(key) + ","));
        }
        long agentStart = System.currentTimeMillis();
        try {
            return callable.call();
        } catch (Exception e) {
            System.out.println("Exception :" + e.getMessage());
            return null;
        } finally {
            System.out.println("path:" + request.getRequestURI() + " 入參:" + in + " 耗時:" + (System.currentTimeMillis() - agentStart));
        }
    }
}
複製代碼
  • 增長agent描述文件resources.META-INF.MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: com.z.test.agent.AgentMain
Can-Redefine-Classes: true
複製代碼
  • pom.xml文件
dependencies
    +net.bytebuddy.byte-buddy 
    +javax.servlet.javax.servlet-api *scope=provided
plugins
    +maven-jar-plugin *manifestFile=src/main/resources/META-INF/MANIFEST.MF
    +maven-shade-plugin *include:net.bytebuddy:byte-buddy:jar:
    +maven-compiler-plugin
複製代碼
  • 小結:沒幾十行代碼就完成了經過Byte Buddy實現應用組件SpringMVC記錄請求路徑、入參、執行時間javagent項目,是否是以爲本身很優秀。

持續迭代javaagent

  • 本小結主要介紹javaagen如何debug,以及持續集成。
  • 首先個人javajagent項目目錄結構如圖所示:
  • 應用項目是用幾行代碼實現的SpringBootWeb項目:
@SpringBootApplication(scanBasePackages = {"com"})
public class TestBootWeb {
    public static void main(String[] args) {
        SpringApplication.run(TestBootWeb.class, args);
    }
    @RestController
    public class ApiController {
        @PostMapping("/ping")
        public String ping(HttpServletRequest request) {
            return "pong";
        }
    }
}

複製代碼
  • 下面是關鍵javaagent項目如何持續迭代與集成:
VM options增長:-javaagent:/Users/zhao/Code/github/z_my_test/test-agent/target/test-agent-1.0-SNAPSHOT.jar=aaaaa
Before launch 在Build以前增長:
    Working directory:/Users/zhao/Code/github/incubator-skywalking
    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加強,根據二八原則,通常的程序員至少熟悉1k左右的類,還不挑一個本身熟悉的類去挑戰下?
  • 注意mvn編譯加速的命令是maven3+版本以上才支持的哈。

SkyWalking Debug

  • 峯迴路轉,到了文章的主題SkyWalking之高級玩法的正文啦,其實經過了上面的鋪墊,我想你們也或多或少已經知道我要說怎麼SkyWalking怎麼Debug了。因此我這裏主要講幾個能夠優化點,避免你們以爲沒有新意,提早賣個關子,個人集成時間優化到30秒左右哈:
VM options增長:-javaagent:-javaagent:/Users/zhao/Code/github/incubator-skywalking/skywalking-agent/skywalking-agent.jar:不要用dist裏面的skywalking-agent.jar,具體緣由你們能夠看看源碼^_^
Before launch 在Build以前增長:
    Working directory:/Users/zhao/Code/github/incubator-skywalking
    Command line:-T 1C -pl apm-sniffer/apm-sdk-plugin -amd clean package -Denforcer.skip=true -Dmaven.test.skip=true -Dmaven.compile.fork=true: 這裏我針對插件包,由於緊接着下文要開發插件
另外根pom註釋maven-checkstyle-plugin也可加速編譯
複製代碼
  • javaagent項目想debug,還須要將agent代碼與接入agent項目至少在同一個工做空間內,網上方法有不少,這裏我推薦你們一個最簡單的方法。File->New->Module from Exisiting Sources...引入skywalking-agent源碼便可

kob之SkyWalking插件編寫

  • kob(貝殼分佈式做業調度框架)是貝殼找房項目微服務集羣中的基礎組件,經過編寫貝殼分佈式做業調度框架的SkyWalking插件,能夠實時收集做業調度任務的執行鏈路信息,從而及時獲得基礎組件的穩定性,瞭解細節可點擊閱讀《貝殼分佈式調度框架簡介》。想詳細瞭解SkyWalking插件編寫可在文章底部參考連接中,跳轉至對應的官方資源,好話很少說,代碼一把唆起來。
  • apm-sdk-plugin pom.xml增長本身的插件model
<artifactId>apm-sdk-plugin</artifactId>
    <modules>
        <module>kob-plugin</module>
        ...
    <modules>
複製代碼
  • resources.skywalking-plugin.def增長本身的描述
kob=org.apache.skywalking.apm.plugin.kob.KobInstrumentation
複製代碼
  • 編寫方法instrumentation
public class KobInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
    private static final String ENHANCE_CLASS = "com.ke.kob.client.spring.core.TaskDispatcher";
    private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.kob.KobInterceptor";
    @Override
    protected ClassMatch enhanceClass() {
        return NameMatch.byName(ENHANCE_CLASS);
    }
    @Override
    protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
        return null;
    }
    @Override
    protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
        return new InstanceMethodsInterceptPoint[] {
                new InstanceMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return named("dispatcher1");
                    }
                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPT_CLASS;
                    }
                    @Override
                    public boolean isOverrideArgs() {
                        return false;
                    }
                }
        };
    }
}
複製代碼
  • 自定義interceptor實現span的建立
public class KobInterceptor implements InstanceMethodsAroundInterceptor {
    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,  Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
        final ContextCarrier contextCarrier = new ContextCarrier();
        com.ke.kob.client.spring.model.TaskContext context = (TaskContext) allArguments[0];
        CarrierItem next = contextCarrier.items();
        while (next.hasNext()) {
            next = next.next();
            next.setHeadValue(JSON.toJSONString(context.getUserParam()));
        }
        AbstractSpan span = ContextManager.createEntrySpan("client:"+allArguments[1]+",task:"+context.getTaskKey(), contextCarrier);
        span.setComponent(ComponentsDefine.TRANSPORT_CLIENT);
        SpanLayer.asRPCFramework(span);
    }
    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
        ContextManager.stopSpan();
        return ret;
    }
    @Override
    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
    }
}
複製代碼
  • 實現效果,將操做名改爲任務執行節點+任務執行方法,實現kob的SkyWalking的插件編寫,加上報警體系,能夠進一步增長公司基礎組件的穩定性。

參考連接

相關文章
相關標籤/搜索