分佈式調用鏈(一)

調用鏈的興起

  1. 分佈式遇到的問題:隨着微服務設計理念在系統中的應用,業務的調用鏈越來越複雜。一個請求可能會涉及到幾十個服務的協同操作,涉及到多個團隊的業務系統。當遇到問題需要定位時候,也會產生一系列的麻煩。
  2. 解決方案:通過調用連,把一次請求調用過程完整的串聯起來,實現了對請求調用路徑的監控,便於故障快速定位。
  3. 調用鏈顯示內容:各個調用環節的性能分析(如各個API使用時間、使用堆棧情況)、在調用連各個環節依賴關係還原、SQL語句打印、IP顯示等。

各大公司的調用鏈框架

  1. Google: Dapper
  2. 淘寶 鷹眼
  3. 京東 hyfra(九頭蛇) 希臘神話中的一種,京東開發平臺是宙斯,基於dubbo來實現。

調用鏈原理

  1. 請求到來生成一個全局TraceID,通過TraceID可以串聯起整個調用鏈,一個TraceID代表一次請求。
  2. 除了TraceID外,還需要SpanID用於記錄調用父子關係。每個服務會記錄下Parent id和Span id,通過他們可以組織一次完整調用鏈的父子關係。
  3. 一個沒有Parent id的span成爲root span,可以看成調用鏈入口。
  4. 所有這些ID可用全局唯一的64位整數表示;
  5. 整個調用過程中每個請求都要透傳TraceID和SpanID。
  6. 每個服務將該次請求附帶的TraceID和附帶的SpanID作爲Parent id記錄下,並且將自己生成的SpanID也記錄下。
  7. 要查看某次完整的調用則只要根據TraceID查出所有調用記錄,然後通過Parent id和Span id組織起整個調用父子關係。

調用鏈實現技術

採用字節碼插樁方式,監聽JVM虛擬機。好處是對代碼侵入爲零。

首先需要了解JVM的classLoader加載機制。

  1. JVM的classLoader主要分爲兩類,一種是初始加載器,用來加載lib下的所有後綴爲.jar的文件。另一種是所有其他類型的加載器,包括自定義的class Loader.
  2. 加載機制採用雙親委派模式,就是所有的加載器需要加載的時候都會先交給父類去加載,只有當父類加載不了,纔會使用自身的加載功能,如此一來,所有的加載都繞回了初始加載器。
  3. 例如object類定義在rt.jar中,所有的對象都是Object,都需要先加載Object類,進而都需要加載rt.jar文件,進而需要使用初始加載器來加載。

Javassist

  1.  Javassist是一個開源的分析、編輯和創建Java字節碼的類庫。其主要的優點,在於簡單,而 且快速。直接使用java編碼的形式,而不需要了解虛擬機指令,就能動態改變類的結構,或者動態生成。
  2. 作用:AOP動態代理。獲取訪問類結構信息,如參數名稱等。運行時監控插樁埋點。
  3. 使用流程:
  • 構建ClassPool對象,找到要插入類的路徑,insertClassPath().
  • 獲取CTclass, 找到已存在的類get,構建新類makeClass
  • 修改構造CTclass,添加屬性 addField,添加修改方法addMethod().
  • 將修改完成的class生成新的class toByteCode(),裝載該class toClass

 

多級嵌套事件

埋點就是事件捕獲,

字節碼插樁用到的技術:

javaagent 代理攔截 插樁的入口

javassit字節碼修改工具

java.java-->編譯-->class文件--->JVM--->字節碼

直接寫JVM 指令碼

 

 

 

JVM ClassLoader加載順序

 

 

1.整體採用雙親委派模式,從下往上開始依次check,如果父類存在就加載。所以最終加載順序如下:

  •     Bootstrap ClassLoader,引導類 , Jre_home下lib目錄下的幾個jar隨着JVM的啓動器先加載。就類似於下圖(1)。例如rt.jar,裏面存的是Object
  •     Ext ClassLoader 擴展類,Jre_home/lib/ext目錄下開始加載。就類似於下圖(2)。他們的啓動都依賴於圖1.
  •     App ClassLoader ,類似於下圖(3),容器基礎類,會加載容器的bin目錄,一般只加載兩個jar.
  •    Common ClassLoader 類似於圖(4),容器類
  •    Share ClassLoader ,容器下項目通用的類,
  •    WebApp ClassLoader 加載 項目/WEB-INF/lib下的jar,然後在加載classes/下的代碼。項目自定義類。

  圖(1)

圖(2)

  • 圖(3)圖(4)

 

在web項目中,自定義的jar包怎麼啓動

   自己打好的jar包怎麼啓動:

   在JVM參數中 -javaagent: 目錄/xx.jar。這種方式會將該jar加載到相當於圖3的位置。

  Servlet 的jar加載是在圖4的位置。

  這樣就涉及到一個問題,自定義的字節碼插裝類,會早於servlet的類加載,會出現class no found。

 解決方案: 

  改變加載順序,將自定義的DispatcherServletCollecct 類,填充到Common ClassLoader層級,讓其跟servlet處於同一層級。

pool.get("com.bit.javassist.DispatcherServletCollecct").toClass(loader,null);
		

  這樣,DispatcherServletCollecct會同時出現在圖4與圖3的位置。

  http協議會加載圖4位置的類,而不會去找圖3的,因爲 tomcat的加載機制與JDK加載機制不同,tomcat當看到圖3中出現了該類,就不管了,不會繼續向上請求加載。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章