偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

性能優(yōu)化那些事兒(三)

原創(chuàng) 精選
開發(fā) 開發(fā)工具
在討論完性能優(yōu)化的方面和策略之后,這次我們的文章更偏向技術(shù)層面,來分享下如何開發(fā)一個自己的性能分析工具(基于JVM)。

接上文:

在討論完性能優(yōu)化的方面和策略之后,這次我們的文章更偏向技術(shù)層面,來分享下如何開發(fā)一個自己的性能分析工具(基于JVM)。

『新』知識

考慮到咱們大多數(shù)還是開發(fā)業(yè)務(wù)為主,所以Java里面一些『鮮為人知』的API可能很多人都不知道,這里就簡單介紹一番,如果想深究的,就自己谷歌一下吧。

  • JVMTI(JVM Tool Interface)是 Java 虛擬機所提供的 native 編程接口,即底層的相關(guān)調(diào)試接口調(diào)用,我們熟知的Java調(diào)試其實也是基于它。
  • Instrumentation,雖然Java提供了JVMTI,但是對應(yīng)的agent需要用C/C++開發(fā),對Java開發(fā)者而言并不是非常友好。因此在Java SE 5的新特性中加入了Instrumentation機制。有了Instrumentation,開發(fā)者可以構(gòu)建一個基于Java編寫的Agent來監(jiān)控或者操作JVM了,比如替換或者修改某些類的定義等。

有了上面兩個知識,其實我們就可以開發(fā)一個簡單的Agent了,Instrumentation可以理解為JVM層面的AOP(Aspect Oriented Programming),通過應(yīng)用啟動時掛載Agent,我們可以對每一個class字節(jié)碼進行查看和修改。

  • ASM ASM是一種通用Java字節(jié)碼操作和分析框架,它可以用于修改現(xiàn)有的class文件或動態(tài)生成class文件,結(jié)合Instrumentation我們可以做到掛載Agent的時候,對字節(jié)碼進行修改,加上我們需要的性能監(jiān)控手段。ASM的學(xué)習(xí)是有難度的,需要對字節(jié)碼有所了解,但由于其性能優(yōu)秀,被各種工具作為修改字節(jié)碼的首選,比如大家熟悉的Cglib。
  • Javassist 依舊是一個字節(jié)碼的修改工具,但對初學(xué)者更加友好,不需要過多了解字節(jié)碼層面,可以書寫Java語法片段對已有class字節(jié)進行修改,缺點是過于模板化,難以優(yōu)化,并且功能有限。我們做性能分析工具,本身是要盡可能減少插入字節(jié)碼對現(xiàn)有代碼的影響,并且注入的速度也要盡可能快,所以一般都會選擇ASM作為首選項。

好了,介紹完Instrumentation和ASM,我們是不是就可以滿足制作性能分析工具的前提條件了呢?你看我們通過Instrumentation進行JVM層面的AOP,再通過ASM對JAVA的字節(jié)碼進行修改,就可以著手完成性能分析最重要的埋點環(huán)節(jié)了。

看起來沒有錯,但是誰也不希望我們增強修改過的代碼一直存在內(nèi)存中,分析一次就對環(huán)境造成不可逆的破壞吧。Instrumentation可以通過addTransformer添加字節(jié)碼轉(zhuǎn)換器,也可以將字節(jié)碼恢復(fù)原樣(只需要removeTransformer再retransformClasses就可以恢復(fù)了),但javaAgent畢竟是個單獨的jar包,它也會有一些依賴,將其加載進來必然會引發(fā)新的Class加載甚至是Class的沖突。那么新的問題就出來了,javaAgent如何不對現(xiàn)有的類有影響呢?

ClassLoader 類加載器,我們可以采用一個新的類加載器,專門加載javaAgent里面的類庫,這樣就可以解決agent的類引發(fā)沖突的問題,在舊版本JDK中我們很難對ClassLoader做卸載,并且類的卸載是很麻煩的事情,限制很多,好在我們現(xiàn)在多數(shù)用的都是jdk1.8,只要遵循類卸載的規(guī)則,對ClassLoader進行清理還是很輕松的。

額外的類加載器實現(xiàn)了業(yè)務(wù)代碼和Agent代碼類的隔離,使它們可以安全引用包,并且可以對Agent的類進行卸載,但這樣同時引入了一個新的問題。類是隔離的,我在對業(yè)務(wù)代碼進行增強時,如何向agent代碼傳遞信息?增強的代碼一定是被加載在AppClassLoader里,如何與AgentClassLoader進行通訊呢?

BootStrapClassLoader 啟動類加載器,該ClassLoader是JVM在啟動時創(chuàng)建的,理解這一部分知識,就一定要理解ClassLoader的雙親委派機制。我們可以創(chuàng)建一個非常簡單的Spy類和一個SpyHandler接口,Spy類定義好一些靜態(tài)方法用于代碼增強時調(diào)用,而SpyHandler則是定義一些用于通訊傳參的接口。我們將這兩個類打成jar包,并通過Instrumentation的appendToBootstrapClassLoaderSearch接口,在agent加載時引入BootStrapClassLoader類中,這樣我們在各個ClassLoader中都能訪問Spy類和SpyHandler接口了。

通過上面的介紹,我們現(xiàn)在可以動手做一個自己的APM工具了,通過Instrumentation+ASM,我們可以實現(xiàn)Class文件的修改增強,甚至可以修改JDK自帶的類比如String,通過自定義的ClassLoader我們可以隔離Agent的類和業(yè)務(wù)的類,通過打入BootStrap的Spy,我們可以實現(xiàn)跨ClassLoader之間的通訊。

萬事俱備,我們現(xiàn)在可以開始動手實現(xiàn)一個自己的APM工具了吧!

打住,其實上面這些功能不需要自己一一實現(xiàn),我們不需要重復(fù)制造輪子,來自阿里開源項目JVM-SANDBOX此時華麗登場。這個項目屏蔽了ASM難以使用的缺點,也簡化了Instrumentation打樁過程,并且實現(xiàn)了ClassLoader的隔離,也有了BootStrapClassLoader中的Spy類,我們在此框架的基礎(chǔ)上進行開發(fā)更為簡單。

原圖鏈接:https://github.com/alibaba/jvm-sandbox/wiki/img/jvm-sandbox-classloader.png

集『大』成

我們擁有了JVM-SANDBOX這一利器,似乎節(jié)約了我們很多的時間,我們現(xiàn)在終于可以著手性能分析了。

那么怎么進行性能分析呢?

  • Zipkin,開源的鏈路追蹤。
  • Jaeger,開源的鏈路追蹤支持Zipkin協(xié)議,個人感覺更為好用。

我們可以引入Zipkin或者Jaeger作為收集者和UI展現(xiàn),根據(jù)自己的喜好選擇一個好用的開源工具。通過sandbox提供的功能,我們可以很方便編寫埋點代碼,將我們的鏈路追蹤工具集成到Agent里面,最終實現(xiàn)無侵入的定制化鏈路追蹤。

通過集成ZipkinClient或者JaegerClient我們可以進行埋點收集,我們似乎把一些功能以搭積木的方式組裝起來,解決了一個頗為復(fù)雜的實現(xiàn),這就是開源的魅力所在。其實在實際的過程中我們還遇到了一些困難,比如如何追蹤異步調(diào)用,如何追蹤跨線程的調(diào)用,如何處理線程池,如何處理ForkJoin?

其中最為復(fù)雜的是如何處理那些跨線程的派發(fā),我們?nèi)绾螌㈡溌返纳舷挛脑诙鄠€線程中傳遞。JDK的InheritableThreadLocal類可以完成父線程到子線程的值傳遞。但對于使用線程池等會池化復(fù)用線程的執(zhí)行組件的情況,線程由線程池創(chuàng)建好,并且線程是池化起來反復(fù)使用的;這時父子線程關(guān)系的ThreadLocal值傳遞已經(jīng)沒有意義,應(yīng)用需要的實際上是把 任務(wù)提交給線程池時的ThreadLocal值傳遞到任務(wù)執(zhí)行時。

說起來可能不好理解,總得來說無論是ThreadLocal還是InheritableThreadLocal都無法處理線程池或者ForkJoin帶來的線程復(fù)用的副作用,即無法有效準確安全的傳遞鏈路的上下文,不信大家可以試一試。

那么怎么解決這個問題呢?沒錯,就是修改JDK源碼,讓線程池在進行調(diào)度的時候具有安全準確傳遞上下文信息的能力,比如對Runnable和Callable接口進行增強處理,讓其可以攜帶線程的上下文。如果要對JDK的代碼進行增強,我們需要非常熟悉線程調(diào)度、線程池、Forkjoin的源碼,還需要小心處理值的傳遞確保安全,聽起來就很危險,也很困難。不用擔(dān)心我們不是第一次遇到這種問題的人,我們再次搬來了阿里的開源產(chǎn)品TTL,這個庫解決的就是上面描述的問題。

但是找到開源產(chǎn)品也并不一定能解決所有的問題,transmittable-thread-local雖然能夠解決線程復(fù)用時傳值的問題,但是它的實現(xiàn)對JDK代碼進行了『過分』的修改,以至于Instrumentation不能進行動態(tài)增強,它需要在啟動時未加載到ClassLoader的時候?qū)DK的源碼進行增強,并不能對已加載的JDK源碼進行動態(tài)增強,也就是說這種增強只能發(fā)生在一開始,不能發(fā)生在中間時間,且不可卸載。

這是因為Instrumentation的redefineClasses這個方法存在限制:重定義不得添加、移除、重命名字段或方法;不得更改方法簽名、繼承關(guān)系(不然那些商業(yè)的熱重載技術(shù)怎么賺錢。。)。而TTL的增強違反了這個原則,我們需要對其修改,并集成到Agent中。這個改造比較無趣也不好解說,可以直接看改造后的JVM-SANDBOX,我們?yōu)榱撕罄m(xù)使用方便,將TTL庫直接用BootStrapClassLoader加載了進去。

開源

最終開源的性能分析工具可以在這里找到:https://github.com/tmtbe/PVisualization,配合改造后的JVM-SANDBOX,可以實現(xiàn)360度無死角的性能鏈路追蹤分析,開發(fā)埋點也非常便捷,也無需考慮任何線程池的問題。

原圖鏈接:https://github.com/tmtbe/PVisualization/raw/master/source/img.png

責(zé)任編輯:趙寧寧 來源: Thoughtworks洞見
相關(guān)推薦

2022-04-08 09:47:55

性能優(yōu)化開發(fā)

2022-02-18 19:24:15

性能優(yōu)化代碼

2022-06-20 05:40:25

數(shù)據(jù)庫MySQL查詢

2013-03-12 17:33:17

Linux系統(tǒng)性能調(diào)優(yōu)

2021-06-02 08:33:31

TPCTPC-H系統(tǒng)

2018-09-26 06:50:19

2011-02-25 14:35:00

2022-02-08 17:39:04

MySQL服務(wù)器存儲

2013-12-26 14:23:03

定位系統(tǒng)GPS監(jiān)測

2021-06-09 13:28:40

密碼安全身份認證數(shù)據(jù)安全

2022-02-09 17:08:57

卡頓App 流暢性用戶

2012-07-31 09:14:20

蘋果三星

2016-03-02 09:34:03

runtime消息ios開發(fā)

2017-05-18 16:30:29

Linux內(nèi)存管理

2022-05-13 14:36:12

網(wǎng)絡(luò)犯罪網(wǎng)絡(luò)攻擊密碼

2012-03-12 13:55:22

交互設(shè)計

2017-08-21 17:00:55

2010-09-14 11:36:24

上網(wǎng)行為管理網(wǎng)絡(luò)安全網(wǎng)康科技

2022-05-23 08:34:08

微前端微服務(wù)開發(fā)

2022-10-08 00:02:00

CSS工具系統(tǒng)
點贊
收藏

51CTO技術(shù)棧公眾號