日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 單片機(jī) > 架構(gòu)師社區(qū)
[導(dǎo)讀]作者:未完成交響曲,資深Java工程師!目前在某一線互聯(lián)網(wǎng)公司任職,架構(gòu)師社區(qū)合伙人! 本文源碼基于Pinpoint 2.0.3-SNAPSHOT版本 官方開源地址:https://github.com/naver/pinpoint Pinpoint Agent Pinpoint通過字節(jié)碼增強(qiáng)技術(shù)來實(shí)現(xiàn)無侵入式的調(diào)用鏈采集。

分布式系統(tǒng)性能監(jiān)控工具,初探Pinpoint Agent啟動源碼

作者:未完成交響曲,資深Java工程師!目前在某一線互聯(lián)網(wǎng)公司任職,架構(gòu)師社區(qū)合伙人!


本文源碼基于Pinpoint 2.0.3-SNAPSHOT版本
官方開源地址:https://github.com/naver/pinpoint

Pinpoint Agent

Pinpoint通過字節(jié)碼增強(qiáng)技術(shù)來實(shí)現(xiàn)無侵入式的調(diào)用鏈采集。其核心實(shí)現(xiàn)是基于JVM的Java Agent機(jī)制。

我們使用Pinpoint時,需要在Java應(yīng)用啟動參數(shù)上加上-javaagent:$AGENT_PATH/pinpoint-bootstrap-$VERSION.jar參數(shù),這樣,當(dāng)我們的Java應(yīng)用啟動時,會同時啟動Agent。

Pinpoint Agent在啟動的時候,會加載plugin文件夾下所有的插件,這些插件會對特定class類修改字節(jié)碼,在一些指定的方法調(diào)用前后加上鏈路采集邏輯(比如Dubbo中AbstractProxyInvokerinvoke()方法),這樣就實(shí)現(xiàn)了調(diào)用鏈監(jiān)控功能。

Pinpoint官方文檔中的原理描述:

分布式系統(tǒng)性能監(jiān)控工具,初探Pinpoint Agent啟動源碼
在這里插入圖片描述

在pintpoin-bootstrap模塊中,我們可以在pom文件中看到maven插件里有MANIFEST相關(guān)的配置,指定了 Premain-Class,這個配置在打包時也會生成到MANIFEST.MF文件中:
分布式系統(tǒng)性能監(jiān)控工具,初探Pinpoint Agent啟動源碼
在這里插入圖片描述

執(zhí)行premain()方法

通過上述配置可知,當(dāng)我們啟動接入了pinpoint的Java應(yīng)用時,會先執(zhí)行PinpointBootStrap.premain()方法:

去掉了日志等非核心邏輯代碼

public static void premain(String agentArgs, Instrumentation instrumentation) {
    // 1.設(shè)置啟動狀態(tài),避免重復(fù)初始化
    final boolean success = STATE.start();
    if (!success) {
        return;
    }

    // 2.初始化和解析啟動參數(shù)
    final JavaAgentPathResolver javaAgentPathResolver = JavaAgentPathResolver.newJavaAgentPathResolver();
    final String agentPath = javaAgentPathResolver.resolveJavaAgentPath();
    final Map<String, String> agentArgsMap = argsToMap(agentArgs);
    final ClassPathResolver classPathResolver = new AgentDirBaseClassPathResolver(agentPath);

    // 3.查找核心jar包
    final AgentDirectory agentDirectory = resolveAgentDir(classPathResolver);
    BootDir bootDir = agentDirectory.getBootDir();
    appendToBootstrapClassLoader(instrumentation, bootDir);

    // 4.獲取類加載器,加載核心jar中的類
    ClassLoader parentClassLoader = getParentClassLoader();
    final ModuleBootLoader moduleBootLoader = loadModuleBootLoader(instrumentation, parentClassLoader);
    PinpointStarter bootStrap = new PinpointStarter(parentClassLoader, agentArgsMap, agentDirectory, instrumentation, moduleBootLoader);

    // 5.啟動bootStrap
    if (!bootStrap.start()) {
        logPinpointAgentLoadFail();
    }
}

可以看到premain()方法有兩個參數(shù),最重要的是這個instrumentation對象

Instrumentation是Java提供的一個來自JVM的接口,該接口提供了一系列查看和操作Java類定義的方法,例如修改類的字節(jié)碼、向classLoader的classpath下加入jar文件等,

PinpointBootStrap.premain()方法中,主要完成了相關(guān)jar包的查找和加載,然后將一系列配置以及instrumentation對象構(gòu)造成PinpointStarter對象,并執(zhí)行start()方法完成后續(xù)的啟動:

boolean start() {
    // 1.讀取agentId和applicationName
    final AgentIds agentIds = resolveAgentIds();
    final String agentId = agentIds.getAgentId();
    final String applicationName = agentIds.getApplicationName();
    final boolean isContainer = new ContainerResolver().isContainer();

    try {
        // 2.解析并加載配置
        final Properties properties = loadProperties();
        ProfilerConfig profilerConfig = new DefaultProfilerConfig(properties);

        // 3.設(shè)置日志路徑和版本信息到systemProperty
        saveLogFilePath(agentDirectory);
        savePinpointVersion();

        // 4.創(chuàng)建AgentClassLoader
        URL[] urls = resolveLib(agentDirectory);
        final ClassLoader agentClassLoader = createClassLoader("pinpoint.agent", urls, parentClassLoader);
        if (moduleBootLoader != null) {
            moduleBootLoader.defineAgentModule(agentClassLoader, urls);
        }
        final String bootClass = getBootClass();
        AgentBootLoader agentBootLoader = new AgentBootLoader(bootClass, agentClassLoader);

        final List<String> pluginJars = agentDirectory.getPlugins();

        // 5.構(gòu)建AgentOption,并作為參數(shù)通過反射機(jī)制構(gòu)建Agent(DefaultAgent)
        AgentOption option = createAgentOption(agentId, applicationName, isContainer, profilerConfig, instrumentation, pluginJars, agentDirectory);
        Agent pinpointAgent = agentBootLoader.boot(option);

        // 6.啟動死鎖監(jiān)控線程、agent數(shù)據(jù)上報線程、注冊ShutdownHook
        pinpointAgent.start();
        pinpointAgent.registerStopHandler();

    } catch (Exception e) {
        return false;
    }
    return true;
}

初始化上下文

上面過程其實(shí)還是加載配置并構(gòu)建一些對象,這里面最核心的邏輯是構(gòu)建Agent對象,執(zhí)行了DefaultAgent類的構(gòu)造器,初始化了上下文:

new DefaultAgent()

┆┈ DefaultAgent.newApplicationContext()

┆┈┈┈ new DefaultApplicationContext()

這里我們直接看DefaultApplicationContext類的構(gòu)造器中的關(guān)鍵邏輯:

public DefaultApplicationContext(AgentOption agentOption, ModuleFactory moduleFactory) {
    // 1.獲取Instrumentation對象
    final Instrumentation instrumentation = agentOption.getInstrumentation();

    // 2.構(gòu)建Guice ioc容器,用于依賴注入
    final Module applicationContextModule = moduleFactory.newModule(agentOption);
    this.injector = Guice.createInjector(Stage.PRODUCTION, applicationContextModule);

    // 3.通過Guice注入一系列對象
    this.profilerConfig = injector.getInstance(ProfilerConfig.class);
    this.interceptorRegistryBinder = injector.getInstance(InterceptorRegistryBinder.class);
    this.instrumentEngine = injector.getInstance(InstrumentEngine.class);
    this.classFileTransformer = injector.getInstance(ClassFileTransformer.class);
    this.dynamicTransformTrigger = injector.getInstance(DynamicTransformTrigger.class);

    // 4.通過instrumentation對象注冊類轉(zhuǎn)換器
    instrumentation.addTransformer(classFileTransformer, true);

    ...
}

綁定TransformCallback

Guice是谷歌開源的一個輕量級的依賴注入框架,pinpoint依靠Guice管理各種對象。

在初始化ioc容器的過程中,會遍歷plugin目錄下的所有插件對其進(jìn)行初始化,調(diào)用過程如下:

ApplicationServerTypeProvider.get()

|— PluginContextLoadResultProvider.get()

|—— new DefaultPluginContextLoadResult()

|——— DefaultProfilerPluginContextLoader.load()

|———— DefaultProfilerPluginContextLoader.setupPlugin()

|————— DefaultPluginSetup.setupPlugin()

|—————— XxxPlugin.setup()(具體Plugin實(shí)現(xiàn))

DubboPlugin為例,在setup()方法中主要對dubbo中的核心類進(jìn)行轉(zhuǎn)換器綁定:

@Override
public void setup(ProfilerPluginSetupContext context) {
    DubboConfiguration config = new DubboConfiguration(context.getConfig());
    ...
    this.addTransformers();
}

private void addTransformers() {
    // 為dubbo核心rpc調(diào)用類綁定Transform關(guān)系
    transformTemplate.transform("com.alibaba.dubbo.rpc.protocol.AbstractInvoker", AbstractInvokerTransform.class);
    transformTemplate.transform("com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker", AbstractProxyInvokerTransform.class);
}

再來看看其中一個Transform類都做了些什么:

public static class AbstractInvokerTransform implements TransformCallback {
   @Override
    public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
        // 指定目標(biāo)類(上一步綁定的類)
        final InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
        // 指定目標(biāo)方法(方法名、參數(shù))
        InstrumentMethod invokeMethod = target.getDeclaredMethod("invoke""com.alibaba.dubbo.rpc.Invocation");
        if (invokeMethod != null) {
            // 為此方法添加攔截器
            invokeMethod.addInterceptor(DubboConsumerInterceptor.class);
        }
        return target.toBytecode();
    }
}

可以看到,這個類實(shí)現(xiàn)了TransformCallback接口,這個接口從名字上可以看出是一個回調(diào)接口,而在其doInTransform()方法中,是通過字節(jié)碼增強(qiáng)的方式,為com.alibaba.dubbo.rpc.protocol.AbstractInvoker類的invoke()方法添加了一個攔截器DubboConsumerInterceptor。

DubboConsumerInterceptor實(shí)現(xiàn)了AroundInterceptor接口的before()after()方法,這里可以看出和Spring AOP很相似了,而在攔截器中,主要是對dubbo的RPC調(diào)用進(jìn)行trace、span等鏈路追蹤信息的記錄。

動態(tài)類加載

在上下文初始化時,Pinpointinstrumentation注冊了一個Transformer,該接口只定義個一個方法transform(),該方法會在加載新class類或者重新加載class類時調(diào)用,其調(diào)用路徑如下:

DefaultClassFileTransformerDispatcher.transform()

|— BaseClassFileTransformer.transform()

|—— MatchableClassFileTransformerDelegate.transform()

|——— TransformCallback.doInTransform()

可以看到,最后執(zhí)行的就是我們在上面執(zhí)行XxxPlugin.setup()方法時配置的回調(diào)接口,即對指定的方法進(jìn)行字節(jié)碼增強(qiáng)。而Java應(yīng)用啟動后,加載的就是我們增強(qiáng)后的類,從而實(shí)現(xiàn)鏈路監(jiān)控或其他的功能。

特別推薦一個分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒關(guān)注的小伙伴,可以長按關(guān)注一下:

分布式系統(tǒng)性能監(jiān)控工具,初探Pinpoint Agent啟動源碼

長按訂閱更多精彩▼

分布式系統(tǒng)性能監(jiān)控工具,初探Pinpoint Agent啟動源碼

如有收獲,點(diǎn)個在看,誠摯感謝

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉