調用鏈系列二:解讀UAVStack中的調用鏈技術

在上週的推送中,咱們介紹了調用鏈的模型設計與模型時序圖,本週將爲你們繼續介紹調用鏈是如何在中間件加強技術的賦能之下實現服務端信息收集以及服務間上下文傳遞的。java

服務端信息收集

服務端信息收集流程以下圖所示,經過在應用容器(Tomcat等)啓動過程當中植入切點,實如今應用邏輯執行以前和以後對請求進行劫持。git

  • 應用邏輯執行以前:解析request中的調用鏈信息,並初始化調用鏈上下文;github

  • 應用邏輯執行以後:解析response中的調用鏈信息,並將本次請求處理的全部調用鏈信息輸出到日誌文件。tomcat

1

切點植入架構

在介紹切點以前,咱們應該總體瞭解Servlet容器(本文以Tomcat爲例)處理一次請求的基本流程。app

2

Connector接收到一次鏈接並轉化成請求(Request)後,會將請求傳遞到Engine管道(Pipeline)的閥(ValveA)中。請求經過Engine的管道傳遞到Engine Valve,而後經由Engine Valve傳遞到一個Host的管道中,並在該管道中傳遞到Host Valve這個閥裏;接着從Host Valve傳遞到一個Context的管道中,並在該管道中傳遞到Context Valve中;最後傳遞到Wrapper C內管道所包含的閥Wrapper Valve中,在這裏通過過濾器鏈(Filter Chain)最終送到一個Servlet中。根據Tomcat的這種架構設計特色,咱們能夠在Tomcat處理一次請求的生命週期過程當中植入本身的邏輯,從而加強Tomcat對外提供的能力,即UAV的中間件加強技術框架

中間件加強技術除了巧妙運用了tomcat容器的架構設計以外還藉助了java Instrumentation(它給咱們提供了一種可以在對象第一次加載時動態修改字節碼的能力,因爲篇幅緣由在此不進行詳細講解)。在UAV中經過UAVServer對外提供各類切點能力。網站

有了中間件加強技術,就有了在應用邏輯執行以前和以後的切點,接下來就是在這些切點位置執行咱們本身的調用鏈邏輯了。spa

中間件加強技術在調用鏈中的使用架構設計

上文介紹的間件加強技術是一種經過使用javaagent方式動態地在Tomcat代碼中植入切點代碼並以UAVServer的形式對外提供能力的框架(具體能力後續文章會詳細介紹)。輕調用鏈正是依賴於UAVServer對外提供的GlobalFilterHandler能力。 GlobalFilterHandler:這裏的GlobalFilterHandler是中間件加強技術中的一種能力,與傳統的filter沒有任何關係。它對外提供了四種能力:

  1. doRequest:在全部應用處理請求以前進行劫持;
  2. doResponse:在全部應用處理請求以後進行劫持;
  3. BlockHandlerChain:阻塞自當前handler之後的全部handler,此處的handler爲註冊在當前;
  4. BlockFilterChain阻塞自當前Filter之後的全部Filter。 調用鏈藉助GlobalFilterHandler提供的前兩個能力,實現了在應用處理請求以前和以後執行調用鏈邏輯的功能。

輕調用鏈實現

UML圖以下:

3

從UML圖中能夠清晰地看到,InvokeChainSupporter(調用鏈實現邏輯入口和調用鏈所需資源初始化實現類)將中間件加強技術進行了二次加強。它容許使用者在其中註冊不一樣的handler,而且在handler的preCap和doCap(中間件加強技術中的邏輯執行以前和以後的切點術語)方法以前和以後動態植入adapter,從而執行更多的定製化適配和個性化邏輯。全部supporter和adapter均採用反射調用方式,最大程度上減小了中間件加強技術的依賴。

有了二次加強技術,咱們就能夠開始下面的調用鏈繪製工做了。

輕調用鏈繪製實現主要依賴於註冊在InvokeChainSupporter上的ServiceSpanInvokeChainHandler。主要繪製過程以下:

  1. 解析請求信息,從中提取調用鏈關心的信息,並將解析出來的信息放入上下文中;
  2. 對解析出來的請求頭信息進行邏輯分流,根據不一樣的協議類型進行不一樣的邏輯處理(MQ邏輯、Http邏輯、Dubbo邏輯);
  3. 初始化調用鏈上下文,並初始化main span上下文;
  4. 在應用處理完請求以後,統一輸出調用鏈信息。

下面來看一下具體每一步都作了什麼。

解析請求信息

對於像Tomcat這樣的中間件容器,進入Tomcat的全部請求都會被封裝成HttpServletRequest和HttpServletResponse(後文簡稱request和response)最終進入用戶的Servlet中。藉助中間件加強技術,調用鏈在用戶邏輯處理以前將request和response進行一次攔截,並解析其中是否含有調用鏈信息。若是有,則將調用鏈信息進行封裝放入上下文中。

邏輯分流

因爲不一樣協議對應的調用鏈繪製邏輯也不一樣,此處調用鏈會根據協議類型進行一次分發。

初始化調用鏈上下文

解析調用鏈上下文中的信息:

  1. 若沒有父節點則以當前節點爲初始化節點,並初始化記錄當前服務內調用鏈信息的main span;
  2. 如有父節點則根據父節點信息初始化當前節點,並初始化記錄當前服務內調用鏈信息的main span。 main span:在服務內可能會進行屢次客戶端通信或服務間通信,須要一個mainspan來記錄當前服務內調用鏈最後一個節點的信息。

調用鏈信息輸出

在用戶邏輯處理結束以後,調用鏈記錄器會從上下文中取出當前服務的調用鏈信息並將其輸出到指定日誌路徑。

服務間上下文傳遞

針對不一樣協議,調用鏈傳遞信息的方式也略有不一樣,具體實現方式藉助了中間件加強技術提供的另外一個能力:AppFrkHook(簡稱hook,此功能在客戶端調用鏈實現時具體介紹)。Hook可以對用戶使用的客戶端技術進行劫持,如用戶使用了Httpclient進行通信,則對Httpclient進行劫持並動態植入代碼,從而實如今Http通信的過程當中注入調用鏈上下文信息。目標服務在解析請求信息時,對調用鏈上下文進行解析;在初始化調用鏈上下文邏輯時,使用傳遞過來的信息初始化目標服務的調用鏈上下文,實現跨系統調用時的調用鏈鏈接。

讀完本文,你們應該瞭解了服務端和服務間調用鏈的繪製全過程;對中間件加強技術的實現及其提供的GlobalFilterHandler能力有了初步認識。下篇文章咱們將向你們介紹如何從Http(HyperTextTransferProtocol) 即超文本傳輸協議中獲取request和response的body和header。

官方網站

開源地址

UAVStack已在Github上開放源碼,並提供了安裝部署、架構說明和用戶指南等雙語文檔,歡迎訪問-給星-拉取~~~

掃一掃下方二維碼 關注一個不會讓你失望的公衆號

相關文章
相關標籤/搜索