SOFA
Scalable Open Financial Architecture
是螞蟻金服自主研發的金融級分散式中介軟體,包含了構建金融級雲原生架構所需的各個元件,是在金融場景裡錘煉出來的最佳實踐。
本文為《剖析 | SOFARPC 框架》第八篇,作者水寒,目前就職於網易。
《剖析 | SOFARPC 框架》系列由 SOFA 團隊和原始碼愛好者們出品,
專案代號:
,官方目錄目前已經全部認領完畢,文末提供了已完成的文章目錄。
前言
在《剖析 | SOFARPC 框架》系列之前的文章中,我們已經介紹了同步,非同步,泛化呼叫等,也介紹了鏈路追蹤的能力。
本篇,我們將介紹一下 SOFARPC 中另一種內建的資料透傳的能力。依次介紹,資料透傳的概念, SOFARPC 的設計原理,以及各種不同呼叫方式下的透傳使用和詳細說明,最後, 還會比較一下和 SOFATracer 的區別。歡迎大家與我們討論交流。
資料透傳介紹
首先,我們知道,在 RPC 呼叫中,資料的傳遞,是透過介面方法引數來傳遞的,需要介面方定義好一些引數允許傳遞才可以。在一些場景下,我們希望,能夠更通用的傳遞一些引數,比如一些標識性的資訊。業務方可能希望,在每一次呼叫請求中都能夠傳遞一些自定義的資訊到下游。甚至也希望下游能夠將一些資料傳遞迴來。
而資料透傳功能,就是指資料不需要以作為方法引數的形式在呼叫鏈路中進行傳遞,而是直接儲存到呼叫背景關係中,之後透過 RPC 的內建物件,進行傳遞,呼叫雙端可從背景關係中獲取資料而不需要去關註資料的傳輸過程。SOFARPC 提供的資料透傳支援請求資料透傳(客戶端向服務端)和響應資料透傳(服務端向客戶端)
SOFARPC 設計原理
這裡主要是介紹一下,實現的核心原理,更加具體的每種呼叫方式的透傳,在後文中都會詳細介紹。
-
使用者透過 SOFARPC 提供的 API 進行資料傳遞設定
-
SOFARPC 在呼叫傳輸前,將透傳的資料進行打包獲取
-
進行正常的序列化和反序列化
-
SOFARPC 在反序列化時將使用者設定的透傳資料寫回 Context
-
服務端使用者即可進行獲取使用
不同呼叫方式的透傳
我們知道,SOFARPC 目前支援四種呼叫樣式,如果沒有閱讀過之前文章的同學,可以閱讀一下 SOFARPC 同步非同步實現剖析 。四種呼叫樣式下,請求透傳資料的原理都是一樣的,服務端設定響應透傳資料的原理也是一樣的,只是客戶端獲取響應透傳資料的方式有所不同(後三種樣式只介紹客戶端獲取響應透傳資料的原理)。
因此我們會介紹下不同呼叫方式的透傳細節,並介紹其使用方式,方便大家理解。以下為了方便說明,我們會使用如下的介面示例
介面服務
public interface HelloService { String sayHello(String string); }
服務實現
public class HelloServiceImpl implements HelloService { @Override public String sayHello(String string) { // 獲取請求透傳資料並列印 System.out.println("service receive reqBag -> " + RpcInvokeContext.getContext().getRequestBaggage("req_bag")); // 設定響應透傳資料到當前執行緒的背景關係中 RpcInvokeContext.getContext().putResponseBaggage("resp_bag", "s2c"); return "hello " + string + " !"; } }
後續的所有呼叫樣式都使用HelloServiceImpl
這個服務實現。(示例程式碼在 SOFARPC 的測試 case 中都要對應的示例,大家可以對應閱讀)
對使用者可見的操作 API 只有一個就是 RpcInvokeContext
,在 SOFABoot 和 SOFARPC 下都適用,當然如果你瞭解 SOFARPC 的 Filter 機制,也可以透過擴充套件這個來實現。
一、sync 呼叫下的透傳
使用示例
原理剖析
請求透傳資料
-
客戶端首先在 main 執行緒(圖中的user thread)中設定請求透傳資料到其呼叫背景關係
RpcInvokeContext.requestBaggage
屬性中,之後在呼叫過程中從requestBaggage
中取出請求透傳資料並設定到SofaRequest.requestProps
屬性中。 -
服務端接收到請求
SofaRequest
物件後,在其呼叫鏈中的ProviderBaggageFilter#invoke
方法中會先從SofaRequest.requestProps
中取出請求透傳資料並設定到當前服務端執行緒的呼叫背景關係RpcInvokeContext.requestBaggage
屬性中,最後業務程式碼就可以從呼叫背景關係中獲取請求透傳資料了。
響應透傳資料
-
服務端設定響應透傳資料到其呼叫背景關係
RpcInvokeContext.responseBaggage
屬性中,之後在ProviderBaggageFilter#invoke
方法中先從responseBaggage
中取出響應透傳資料並設定到SofaResponse.responseProps
屬性中。 -
客戶端main執行緒被喚醒後,先從
SofaResponse.responseProps
中獲取響應透傳資料,之後將響應透傳資料設定到其呼叫背景關係RpcInvokeContext.responseBaggage
中,最後業務程式碼就可以從呼叫背景關係中獲取響應透傳資料了。
二、oneway 呼叫下的透傳
使用示例
原理剖析
在 oneway 樣式下,客戶端不接受服務端響應,也不會獲取響應透傳資料。
三、future 呼叫下的透傳
使用示例
原理剖析
客戶端獲取響應透傳資料
future 樣式在 SOFARPC 內部會被轉化為 callback 的方式進行呼叫,在 callback 物件中會儲存main執行緒的呼叫背景關係;當客戶端接收到響應時,會執行該 callback 物件的回呼函式,在其回呼函式中,對於響應透傳資料,會做如下操作:
-
從
SofaResponse.responseProps
中獲取響應透傳資料 -
從 callback 物件中獲取 main 執行緒的呼叫背景關係
-
設定響應透傳資料到 main 執行緒的呼叫背景關係
-
將 main 執行緒背景關係複製到當前的回呼執行緒中
實際上,第三步與第四步在 SOFARPC 原始碼中順序相反,本文這樣解讀是為了更容易理解。這樣無論是 future 樣式(從 main 執行緒的呼叫背景關係獲取響應透傳資料)還是 callback 樣式(從回呼執行緒的呼叫背景關係獲取響應透傳資料),都可以順利的獲取到響應透傳資料。
四、callback 呼叫下的透傳
使用示例
原理剖析
與future樣式原理一樣,只是最終業務程式碼中是從回呼執行緒而不是main執行緒的呼叫背景關係中獲取響應透傳資料。
與 SOFATracer 的比較
如果瞭解過 SOFATracer 的同學會有疑問,這個跟 Tracer 是不是有功能上的重疊呢?實際上 SOFATracer 是螞蟻開源的一個分散式鏈路追蹤系統,SOFARPC 目前已經和 Tracer 做了整合,預設開啟。
和 Tracer 進行資料傳遞不同的是
-
SOFARPC 的資料透傳更偏向業務使用,而且可以在全鏈路中進行雙向傳遞,呼叫方可以傳給服務方(請求透傳資料),服務方也可以傳遞資訊給呼叫方(響應透傳資料),SOFATracer 更加偏向於中介軟體和業務無感知的資料的傳遞,並且只能進行單向傳遞。也就是向下傳遞,呼叫方並不能獲取服務提供方的透傳資料。
-
SOFARPC 的透傳可以選擇性地不在全鏈路中透傳(主動清除呼叫背景關係資料),而 Tracer 中如果傳遞大量資訊,會在整個鏈路中傳遞。可能對下游業務會有影響。
所以整體來看,兩種方式各有利弊,在有一些和業務相關的透傳資料的情況下,可以選擇 SOFARPC 的透傳。
《剖析 | SOFARPC 框架》系列歷史文章
長按關註,獲取分散式架構乾貨
歡迎大家共同打造 SOFAStack https://github.com/alipay