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

一週一更,UAVStack又來例行推新啦~~~在上週的推送中,咱們介紹了調用鏈技術中的日誌聚合、分佈式跟蹤及兩者的關聯運用,相信你們已經對調用鏈有了基本瞭解。本週,咱們將繼續介紹調用鏈的模型設計與模型時序圖,小夥伴們上車啦html


在分佈式在線服務中,一個請求須要通過多個系統中的多個模塊,可能須要多達上百臺機器的協做才能完成單次請求。在這種場景下,單靠人力已經沒法掌握整個請求中各個階段的性能開銷,更沒法快速定位系統中的性能瓶頸。發生故障時,一般須要多個團隊合做,查看大量日誌才能肯定問題。git

舉個栗子github

做爲一個在職場摸爬滾打不少年的資深工程師,程序猿小亮面對的系統設計多是這個樣子的:web

1
藉助良好的系統設計和編碼規範,對於通常有問題的請求處理,小亮可以憑藉對多個系統的瞭解,在翻閱大量日誌文件(前提是日誌輸出也是規範的)後定位到問題。隨着用戶數量的增長,系統複雜度也愈來愈高,小亮的大部分時間都花費在團隊溝通工做上了。

這時,小亮可能會想,若是有一個工具可以把每次請求通過的系統都記錄下來,並把每一個節點的消耗時間和處理類等信息也抓取出來,那這個世界該多麼美好啊。tomcat

一個偶然的機會,小亮瞭解到了UAVStack中的調用鏈功能,可以在對業務代碼沒有任何侵入的前提下輕鬆解決他的難題。下面就讓咱們一塊兒開啓神奇的調用鏈探索之旅吧。網絡

UAVStack調用鏈技術棧支持架構

2

效果展現框架

輕型調用鏈展現詳情: 分佈式

3
重調用鏈開啓之後請求報文體抓取視圖:
4
更多使用說明請參閱官網: 用戶指南

具體實現函數

UAVStack調用鏈實現分爲模型設計、服務端信息收集(輕/重)、方法級信息收集(輕/重)、客戶端信息收集(輕/重)、調用鏈協議設計(輕/重)、調用鏈上下文傳遞、調用信息記錄及傳遞、調用數據統計處理等。因爲篇幅限制,本期暫時只分享其中的模型設計及實現調用鏈模型時序圖。

在參考現有經驗並結合具體業務場景需求的基礎上,咱們抽象出了以下調用鏈模型:

調用鏈元數據:

  1. SpanEndpointType:調用類型(Root(「E」),Service(「S」), Client(「C」), Method(「M」))。

    ☆ Root指本條調用鏈中的第一個節點,即一條調用鏈的開始位置,能夠是一個服務請求,一次httpclient調用等;

    ☆ Service指當前調用鏈中非第一個節點且是系統對外提供的服務,如用戶登陸服務;

    ☆ Client指當前調用鏈中非第一個節點且是當前系統與外部溝通的一種途徑,如httpclient、mongoclient等;

    ☆ Method值當前調用鏈中非第一個節點且是系統中的一個函數,如日誌數出函數等。

  2. traceId:調用鏈惟一標識符。

  3. spanId:一條調用鏈中當前節點的調用順序(與SpanEndpointType 結合惟一);spanId採用分層設計,形如1.2.1,既能表示調用順序同時又能反應所才調用鏈層級。

  4. parentId:一條調用鏈中當前節點的父調用節點。

調用鏈繪製規則:

  1. 調用者(服務、web)最初調用(無父調用)記爲開始節點E,並生成惟一調用鏈ID,traceID;
  2. 系統內應用組件調用(如httpclient,方法調用等),spanId末尾數字加1(若爲第一個則末尾加.1);
  3. 系統間調用(如A服務調用B服務),A服務與B服務span信息只有SpanEndpointType不一樣(分別對應span的兩個端)。

舉個栗子

用戶小明想經過網絡獲取一些知識,經過網絡,他進入了系統O。服務O中部署了服務A和B,A服務使用httpclient與B通信,B服務先會與Redis交互而後和MySQL交互,最後系統O將小明感興趣的內容返回給小明。

在完成這次請求的過程當中,UAVStack抽象出以下調用鏈模型:

  1. 小明(下圖中的調用方)經過門戶訪問了A服務,此時調用鏈生成惟一traceId並將當前節點的SpanEndpointType置爲N(第一個節點的意思),spanId置爲1(當前調用層中的第一個節點),parentId置爲E(沒有父節點的意思);
  2. A服務經過httpclient向B服務發起一次http請求,此時調用鏈元數據以下traceId(沿用父節點id);1.1(spanId末尾加.1,由於爲第一次調用);1(parentId父節點的spanId);C(調用類型記錄爲C客戶端調用);
  3. B服務接收到來自於A服務經過httpclient的調用,此時調用鏈元數據以下traceId(沿用初始調用時id);1.1(spanId沿用傳遞過來的spanId);1(parentId沿用傳遞過來的parentId);S(調用類型記錄爲S服務端處理請求);
  4. B服務先查詢Redis,此時調用鏈元數據以下traceId(沿用初始調用時id);1.1.1(spanId末尾加.1,由於爲第一次調用);1.1(parentId父節點的spanId);C(調用類型記錄爲C客戶端調用);
  5. B服務又發起對MySQL的查詢,此時調用鏈元數據以下traceId(沿用初始調用時id);1.1.2(spanId末尾數字加1,由於爲非第一次調用);1.1(parentId父節點的spanId);C(調用類型記錄爲C客戶端調用);
  6. 處理結束,調用鏈記錄下了整個過程當中的調用信息。

5
調用鏈時序圖

6

  1. UAVServer:中間件加強框架,提供在中間件的不一樣生命週期進行劫持的能力,即中間件劫持技術,如tomcat webcontainer啓動開始時刻等;
  2. JEEServiceRunGlobalFilterHandler:藉助中間件劫持技術延伸出的全局filter,可以攔截全部通過中間件(tomcat等)的請求;
  3. ServiceSpanInvokeChainHandler:調用鏈中專一處理歸爲Service類型節點的handler; ClientSpanInvokeChainHandler:調用鏈中專一處理歸爲Client類型節點的handler;
  4. XXAdapter:泛指調用鏈中全部的adapter,提供在handler(分爲Service、Client、Method三種handler,圖中省略了Method類型)執行動做before和after時刻操做數據的能力。

如此,在對用戶代碼無任何」侵入」的前提下便完成了調用鏈的生成,生成過程大體以下:

  1. 在JEEServiceRunGlobalFilterHandler的doRepuest中包裝解析請求;
  2. xxAdapter中的before對數據進行適配;
  3. xxHandler處理對應範圍內(Service、Client和Method)內請求數據;
  4. xxAdapter中的after對數據進行整理或記錄;
  5. 在JEEServiceRunGlobalFilterHandler的doResponse中返回處理事後請求。

本文的主要目的是讓你們初步瞭解一條調用鏈繪製的大體生命週期,具體實現將在下期分享中詳細介紹,歡迎你們繼續關注碼完代碼還要辛苦碼字的技術小哥哥~~~

官方網站

開源地址

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

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

相關文章
相關標籤/搜索