SkyWalking之高階玩法
摘要:
SkyWalking是基於javaagent的兩大位元組碼操作工具之一的Byte Buddy實現的無侵入APM(application performance monitor) 系統,目前專案在Apache孵化器中,想了解SkyWalking和Byte Buddy原始碼的同學可在文章底...
- 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的外掛編寫,加上報警體系,可以進一步增加公司基礎元件的穩定性。
參考連結
- Apache SkyWalking(an APM system) github.com/apache/incu…
- Byte Buddy(runtime code generation for the Java virtual machine) github.com/raphw/byte-…