上篇文章分享了一下調用鏈的模型設計及模型時序圖。相信你們經過上一篇文章對調用鏈有了一個總體上的瞭解,如:調用鏈是什麼、能作什麼及總體實現策略。git
這篇文章咱們繼續介紹調用鏈的服務端信息收集以及服務間上下文傳遞。github
服務端信息收集總體流程以下圖所示,經過在應用容器(tomcat等)啓動過程當中植入切點從而實如今應用邏輯執行以前和以後對請求進行劫持。segmentfault
在介紹切點以前咱們應該對servlet容器(本文以tomcat爲例)處理一次請求的大體流程有一個總體的瞭解。tomcat
圖片來源於網絡網絡
在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對外提供各類切點能力。app
有了中間件加強技術,在應用邏輯執行以前和以後的切點就有了,接下來就是在這些切點位置執行咱們本身的調用鏈邏輯了。框架
上文介紹的間件加強技術是一種經過使用javaagent方式動態地在tomcat代碼中植入切點代碼並以UAVServer的形式對外提供能力的框架(具體能力後續文章會詳細介紹)。輕調用鏈實現正是使用了UAVServer對外提供的GlobalFilterHandler能力。spa
GlobalFilterHandler: 這裏的GlobalFilterHandler是中間件加強技術中的一種能力,與傳統的filter沒有任何關係。它對外提供了四個能力:
調用鏈藉助於GlobalFilterHandler提供的前兩個能力,實現了在應用處理請求以前和以後執行調用鏈邏輯的功能。
具體UML圖以下:
從UML圖中能夠清晰地看到, InvokeChainSupporter(調用鏈實現邏輯入口和調用鏈所需資源初始化實現類)將中間件加強技術進行了二次加強。它容許使用者在其中註冊不一樣的handler,而且在handler的preCap和doCap(中間件加強技術中的邏輯執行以前和以後的切點術語)方法以前和以後動態織入adapter,從而可以執行更多的定製化適配和個性化邏輯。全部supporter和adapter均採用反射調用方式,最大程度上減小了中間件加強技術的依賴。
有了二次加強技術,咱們就能夠開始下面的調用鏈繪製工做了。
輕調用鏈繪製實現主要依賴於註冊在InvokeChainSupporter上的ServiceSpanInvokeChainHandler。主要繪製過程以下:
✔mq邏輯
✔http邏輯
✔dubbo邏輯
下面來看一下具體每一步都作了什麼。
對於像tomcat這類中間件容器,全部進入tomcat的請求都會被封裝成HttpServletRequest和HttpServletResponse(後面簡稱request和response)最終進入用戶的servlet中。調用鏈藉助於中間件加強技術會在用戶邏輯處理以前將request和response進行一次攔截,並解析其中是否含有調用鏈信息。若是有則將調用鏈信息進行封裝放入上下文中。
因爲不一樣協議對應的調用鏈繪製邏輯也不一樣,此處調用鏈會根據協議類型進行一次分發。
將調用鏈上下文中的信息進行解析:
main span:在服務內可能會進行屢次客戶端通信或服務間通信,須要一個main span來記錄當前服務內調用鏈最後一個節點的信息。
在用戶邏輯處理結束以後,調用鏈記錄器會從上下文中取出當前服務的調用鏈信息並將其輸出到指定日誌路徑。
對於不一樣協議調用鏈傳遞信息方式也略有不一樣,具體實現方式藉助了中間件加強技術提供的另外一個能力:AppFrkHook(簡稱hook,此功能在客戶端調用鏈實現時會進行具體介紹)。它可以對用戶使用的客戶端技術進行劫持,如用戶使用了httpclient進行通信,則對httpclient進行劫持並動態織入代碼,從而達到在http通信的過程當中注入調用鏈上下文信息的效果。目標服務在解析請求信息時,將調用鏈上下文進行解析;在初始化調用鏈上下文邏輯時,使用傳遞過來的信息初始化目標服務的調用鏈上下文,實現跨系統調用時調用鏈鏈接。
讀完本文以後讀者應該對中間件加強技術的實現有了一個大概的瞭解,而且對其提供的GlobalFilterHandler能力有了必定的認識。對於調用鏈應明白了服務端和服務間調用鏈的繪製全過程。
開源地址:https://github.com/uavorg/uav...
做者:李崇
來源:宜信技術學院