天天看點

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

一、Pinpoint 是什麼

Pinpoint 是一款全鍊路分析工具,提供了無侵入式的調用鍊監控、方法執行詳情檢視、應用狀态資訊監控等功能。基于Google Dapper論文進行的實作。

核心思想就是在服務各節點彼此調用的時候,記錄并傳遞一個應用級别的标記,這個标記可以用來關聯各個服務節點之間的關系。

比如兩個節點之間使用 HTTP 作為請求協定的話,那麼這些标記就會被加入到HTTP頭中,各應用的Agent在進行上報的時候,将該标記以及對應的上下級應用上報到Pinpoint collector中,通過該标記辨別請求,并将各個應用串聯成完整的調用鍊路。

Pinpoint的特點如下:

  • 分布式事務跟蹤,跟蹤跨分布式應用的消息;
  • 自動檢測應用拓撲,幫助你搞清楚應用的架構;
  • 水準擴充以便支援大規模伺服器叢集;
  • 提供代碼級别的可見性以便輕松定位失敗點和瓶頸;
  • 使用位元組碼增強技術,添加新功能而無需修改代碼。

Pinpoint針對不同的元件提供了豐富的插件,其支援以下子產品:

  • JDK 6+
  • Tomcat 6/7/8, Jetty 8/9, JBoss EAP 6, Resin 4, Websphere 6/7/8, Vertx 3.3/3.4/3.5
  • Spring, Spring Boot (Embedded Tomcat, Jetty)
  • Apache HTTP Client 3.x/4.x, JDK HttpConnector, - GoogleHttpClient, OkHttpClient, NingAsyncHttpClient
  • Thrift Client, Thrift Service, DUBBO PROVIDER, DUBBO CONSUMER
  • MySQL, Oracle, MSSQL, CUBRID,POSTGRESQL, MARIA
  • Arcus, Memcached, Redis, CASSANDRA
  • iBATIS, MyBatis
  • DBCP, DBCP2, HIKARICP
  • gson, Jackson, Json Lib
  • log4j, Logback

二、插件知識和相關的資料結構

pinpoint插件能夠在代碼級别對感興趣的方法進行攔截,可以針對業務代碼,第三方包等,如記錄方法的執行時間,參數,方法傳回結果,在RPC調用中插入辨別ID以記錄調用關系等, pinpoint插件很容易擴充,官方也提供了很多插件,基本覆寫了常用的元件,如hystrix,dubbo等,部署即可用。

1、插件結構

Pinpoint 插件由TraceMetadataProvider 和 ProfilerPlugin 的實作組成。TraceMetadataProvider 實作給 pinpoint agent, collector, web元件提供 ServiceType 和 AnnotationKey,ProfilerPlugin 實作用于agent轉換目标類以記錄追蹤資料。

Pinpoint 插件以 jar 檔案的形式部署。Agent 在 plugin 目錄下用 ServiceLoader 搜尋TraceMetadataProvider 和 ProfilerPlugin 的實作,web 和 collector 在 WEB-INF/lib目錄下搜尋,ServiceLoader 要求 provider 配置檔案存在于 META-INF/services 目錄下,是以在 plugin jar 中必須放置以下檔案,實作類通過 Java 的服務發現機制進行加載。

2. 介紹下幾種關鍵的類

2.1 TraceMetadataProvider

TraceMetadataProvider 實作類中提供 ServiceTypes 和 AnnotationKeys。

2.1.1 ServiceTypes

每個 Span 和 SpanEvent 都包含一個 ServiceType,這個ServiceType表示跟蹤方法所屬的庫,以及跟蹤它的Span和spanevent應該如何處理。

下表顯示ServiceType包含哪些屬性:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

Pinpoint 為了盡量壓縮 Agent 到 Collector 資料包的大小,ServiceType 被設計成不是以序列化字元串的形式發送的,而是以整形數字發送的 (code 字段),這就需要建立一個映射關系,将 code 轉換成對應的 ServiceType 執行個體。

這個映射機制就是由 TraceMetadataProvider 負責的。

ServiceType code必須是惟一的。如果要編寫一個将被公開共享的插件,就必須聯系pinpoint團隊來獲得配置設定的ServiceType code。

如果所開發的插件是私有的,那可以從下面的表格中選擇一個ServiceType code,如一會我們要展示的示例中一樣。

公開的ServiceType Code範圍:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

私有的ServiceType Code範圍:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

ServiceType 還有一些屬性:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

2.1.2、AnnotationKey

Annotation 是包含在 Span 和 SpanEvent 中的更詳盡的資料,以鍵值對的形式存在,鍵就是 AnnotationKey,值是基本類型,String或者byte[]。

Pinpoint 内置了很多的 AnnotationKey,如果不夠用的話也可以通過 TraceMetadataProvider 來自定義。AnnotationKey 的資料結構如下:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的
應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

2.2、ProfilerPlugin

ProfilerPlugin修改目标庫的類來收集跟蹤資料。插件的工作原理:

  1. Pinpoint Agent 随 JVM 一起啟動;
  2. Agent 加載所有 plugin 目錄下的插件;

    Agent 調用已加載的插件的; ProfilerPlugin.setup(ProfilerPluginSetupContext) 方法;

  3. 在 setup 方法中,插件定義那些需要被轉換的類并注冊回調TransformerCallback;
  4. 目标應用啟動;
  5. 每當類被加載的時候,Pinpoint Agent 會尋找注冊到該類的回調 TransformerCallback;
  6. 如果 TransformerCallback 被注冊,Agent; 就調用它的 doInTransform 方法;
  7. TransformerCallback 修改目标類的位元組碼 (例如添加攔截器、字段等);
  8. 修改後的代碼傳回到; JVM,類被加載的時候使用修改後的位元組碼;
  9. 應用程式繼續;
  10. 當調用到被修改的方法的時候,已注入的攔截器的 before 和 after 方法會被調用;
  11. 攔截器記錄追蹤資料.

最重要的幾點可以歸結為:

1)找出哪些方法值得跟蹤。

2)注入攔截器來實際跟蹤這些方法。

這些攔截器用于提取、存儲和傳遞跟蹤資料,然後将其發送給收集器。攔截器甚至可以互相協作,在它們之間共享上下文。

插件還可以通過向目标類添加getter或定制字段來幫助跟蹤,以便攔截器在執行期間可以通路它們。

三、位元組碼注入怎麼工作的

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

由于位元組碼技術必須處理java位元組碼,它會增加開發的風險而降低生産效率。此外,研發人員容易犯錯誤。在Pinpoint中,通過攔截器抽象提高了生産力和可通路性。

Pinpoint中注入必要的代碼,通過在類裝入時插入應用程式代碼來跟蹤分布式事務和性能資訊。由于跟蹤代碼直接注入到應用程式代碼中,是以提高了性能。

在 Pinpoint中,API截取和資料記錄是分離的。如上圖,攔截器被注入到我們希望跟蹤的方法中,在該方法前後調用before()和after()處理資料記錄。

通過位元組碼指令, Pinpoint Agent可以僅從必要的方法記錄資料,進而使分析資料的大小變得緊湊。

下面就根據以上原理來實作一個插件,該插件能夠攔截配置的方法。

先定義些常量類型, 設定ServiceType 和 相應的code,AnnotationKey 和相應的code:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

定義資料類型類用于讀取配置檔案中的配置,檔案中的配置規則為:

有參數方法

package.Clazz.MethodArgs=arg1,arg2
           

無參數方法

package.Clazz.MethodArgs
           

每行一個配置項:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

定義 GeneralConfigMetadataProvider 提供 ServiceType 中繼資料:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

定義針對方法的攔截器 GeneralConfigInterceptor 繼承自 SpanEventSimpleAroundInterceptorForPlugin,這裡在方法執行後簡單記錄方法的名稱,參數,傳回值

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

最後重要的是我們的插件,傳入配置和轉換模闆 transformTemplate:

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

META-INF/services目錄下添加插件和中繼資料檔案:

com.navercorp.pinpoint.plugin.ProfilerPlugin
    --com.navercorp.pinpoint.plugin.general.config.GeneralConfigPlugin
           
com.navercorp.pinpoint.common.trace.TraceMetadataProvider
    --com.navercorp.pinpoint.plugin.general.config.GeneralConfigMetadataProvider
           

當以上核心的代碼寫完後,将插件以jar的形式部署在準備好的 agent 目錄中,啟動項目,在 project.propertie 中配置要攔截的方法如 com.bestpay.middleware.service.StudentManagerImpl.getAllStudents。在請求的路徑中能看到以下的資訊。配置我們配置的方法被攔截到了。

應用監控利器:Pinpoint 全鍊路監控部署實踐一、Pinpoint 是什麼二、插件知識和相關的資料結構三、位元組碼注入怎麼工作的

至此,我們的小插件講解就結束了,此為抛磚引玉,Pinpoint 提供了豐富的插件開發 API,如攔截異步方法、調用鍊跟蹤、攔截器之間共享資料等,有興趣的同學可進一步探索。

原文釋出時間為:2018-08-01

本文作者:吳振

本文來自雲栖社群合作夥伴“

高效運維

”,了解相關資訊可以關注“