服務框架多形式的服務呼叫:同步、非同步、並用、泛化
服務框架支援多種形式的服務呼叫,我們對下面這幾種服務呼叫的原理和設計進行講解。
同步服務呼叫
同步服務呼叫是最常用的一種服務呼叫方式,它的工作原理和使用都非常簡單,分散式服務框架預設都需要支援這種呼叫形式。
它的工作原理如下:客戶端發起遠端服務呼叫請求,使用者執行緒完成訊息序列化之後,將訊息投遞到通訊框架,然後同步阻塞,等待通訊執行緒傳送請求並接收到應答之後,喚醒同步等待的使用者執行緒,使用者執行緒獲取到應答之後返回。
它的工作原理圖如圖。
1)消費者呼叫服務端釋出的介面,介面呼叫由分散式服務框架包裝成動態代理,發起遠端服務呼叫。
2)消費者執行緒呼叫通訊框架的訊息傳送介面之後,直接或者間接呼叫 wait()方法,同步阻塞等待應答。
3)通訊框架的 I/O執行緒通過網路將請求訊息傳送給服務端。
4)服務端返回應答訊息給消費者,由通訊框架負責應答訊息的反序列化。 5)I/O執行緒獲取到應答訊息之後,根據訊息上下文找到之前同步阻塞的業務執行緒, notify()阻塞的業務執行緒,返回應答給消費者,完成服務呼叫。
為了防止服務端長時間不返回應答訊息導致客戶端使用者執行緒被掛死,使用者執行緒等待的時候需要設定超時時間,這個超時時間與服務端或者客戶端配置的超時時間對應。
非同步服務呼叫
基於 JDK的 Future機制,可以非常方便地實現非同步服務呼叫, JDK的 Future介面定義如圖 。
JDK Future Doc
JDK原生的 Future主要用於非同步操作,它代表了非同步操作的執行結果,使用者可以通過呼叫它的 get方法獲取結果。如果當前操作沒有執行完, get操作將阻塞呼叫執行緒。
在實際專案中,往往會擴充套件 JDK的 Future,提供 Future-Listener機制,它支援主動獲取和被動非同步回撥通知兩種模式,適用於不同的業務場景。
以Netty的 Future介面定義為例,新增了監聽器管理介面,監聽器主要用於非同步通知回撥,它的介面定義如圖 。
非同步服務呼叫的工作原理如圖 。
非同步服務呼叫的工作流程如下:
1)消費者呼叫服務端釋出的介面,介面呼叫由分散式服務框架包裝成動態代理,發起遠端服務呼叫。
2)通訊框架非同步傳送請求訊息,如果沒有發生 I/O異常,返回。
3)請求訊息傳送成功後, I/O執行緒構造 Future物件,設定到 RPC上下文中。
4)使用者執行緒通過 RPC上下文獲取 Future物件。
5)構造 Listener物件,將其新增到 Future中,用於服務端應答非同步回撥通知。
6)使用者執行緒返回,不阻塞等待應答。
7)服務端返回應答訊息,通訊框架負責反序列化等。 8)I/O執行緒將應答設定到 Future物件的操作結果中。
9)Future物件掃描註冊的監聽器列表,迴圈呼叫監聽器的operationComplete方法,將結果通知給監聽器,監聽器獲取到結果之後,繼續後續業務邏輯的執行,非同步服務呼叫結束。
需要指出的是,還有另外一種非同步服務呼叫形式,就是不新增 Listener,使用者連續發起 N次服務呼叫,然後依次從 RPC上下文中獲取 Future物件,昀終再主動 get結果,業務執行緒阻塞,相比於老的同步服務呼叫,它的阻塞時間更短,其工作原理如圖。
非同步服務呼叫的程式碼示例如下:
假如 xxxService1和 xxxService2釋出成非同步服務,則呼叫xxxMethod之後當前業務執行緒不阻塞,立即返回 null。使用者不能直接使用它的返回值,而是通過當前執行緒上下文RPCContext獲取非同步操作結果 Future。獲取到 Future之後繼續發起其他非同步服務呼叫,然後獲取另一個 Future……昀後,通過 Future的 get方法集中獲取結果。無論有多少個 Future,採用此種方式使用者執行緒昀長阻塞時間為耗時昀長的 Future,即 T = Max t(future1....N)。如果採用同步服務呼叫,使用者執行緒的阻塞時間T = t(future1) + t(future2) + ……+ t(futureN)。
非同步服務呼叫相比於同步服務呼叫有兩個優點:
◎化序列為並行,提升服務呼叫效率,減少業務執行緒阻塞時間。
◎化同步為非同步,避免業務執行緒阻塞。
序列到並行的優化原理如圖 。
由於每次服務呼叫都是同步阻塞,三個服務呼叫總耗時為T = T1 + T2 + T3。下面我們看下采用非同步服務呼叫之後的優化效果,如圖。
採用非同步服務呼叫模式,昀後呼叫三個服務非同步操作結果 Future的 get方法同步等待應答,它的總執行時間 T = Max(T1, T2, T3),相比於同步服務呼叫,效能提升效果非常明顯。
第二種基於 Future-Listener的純非同步服務呼叫,它的程式碼示例如下:
xxxService1.xxxMethod(Req);
Future f1 =RpcContext.getContext().getFuture();
Listener l = new xxxListener();f1.addListener(l); ......後續程式碼省略 }
基於 Future-Listener的非同步服務呼叫相比於 Future-get模式更好,但是在實際使用中有一定的侷限性,具體的使用限制留給讀者自己思考。
並行服務呼叫
在大多數業務應用中,服務總是被序列地呼叫和執行,例如 A呼叫 B服務,B服務呼叫C服務,昀後形成一個序列的服務呼叫鏈: A→B服務→C服務→……
序列服務呼叫比較簡單,但在一些業務場景中,需要採用並行服務呼叫來降低 E2E的時延:
◎多個服務之間邏輯上不存在互相依賴關係,執行先後順序沒有嚴格的要求,邏輯上可以被並行執行。
◎長流程業務,呼叫多個服務,對時延比較敏感,其中有部分服務邏輯上無上下文關聯,可以被並行呼叫。
並行服務呼叫的目標主要有兩個:
1)降低業務 E2E時延。
2)提升整個系統的吞吐量。我們以手遊購買道具流程為例,對並行服務呼叫進行說明,如圖。
在購買道具時,三個鑑權流程實際可以並行執行,昀終執行結果做個 Join即可。如果採用傳統的序列服務呼叫,耗時將是三個鑑權服務時延之和,顯然是沒有必要的。計費之後的通知類服務亦如此(注意:通知服務也可以使用MQ做訂閱/釋出),單個服務的序列呼叫會導致購買道具時延比較長,影響遊戲玩家的體驗。
要解決序列呼叫效率低的問題,有兩個解決對策:
◎非同步服務呼叫。
◎並行服務呼叫。在上一節中已經對非同步服務呼叫進行了講解,下面我們對並行服務呼叫進行詳細介紹。並行服務呼叫的原理:一次同時發起多個服務呼叫,先做流程的 Fork,再利用 Future
等主動等待獲取結果,進行結果匯聚( Join)。實現並行服務呼叫的幾種技術方案:
◎ JDK 7的 Fork/Join,可以實現子任務的並行執行和結果匯聚。
◎ BPM的 Parallel Gateway。
◎批量序列服務呼叫。
JDK7的 Fork/Join底層會開啟多個執行緒來分解任務,在服務框架中使用會導致依賴執行緒上下文傳遞的變數丟失、執行緒膨脹不可控等問題,因此在並行服務呼叫時不適合使用 JDK的 Fork/Join並行執行框架。
BPM流程引擎支援並行流程(子流程)呼叫,它的執行示意圖如圖。
Parallel Gateway(並行閘道器)能在一個流程裡用來對併發建模。在一個流程模型裡引入併發昀直接的閘道器就是並行閘道器( Parallel Gateway),它允許 Fork執行多個路徑,或者 Join多個執行的到達路徑。
並行閘道器的功能基於即將到達的和即將離開的流程順序流。
◎ Fork:所有即將離開的順序流將以並行方式,為每個順序流程建立一個併發執行器。
◎ Join:所有的併發執行到達並行閘道器,在閘道器裡面等待直到每個來到的順序流的執行到達,條件滿足後流程繼續通過合併閘道器。
從技術上看,不同的 BPM流程引擎具體實現細節也不同,但大多數都支援:通過建立子執行緒的方式實現並行呼叫、通過批量呼叫的方式實現偽非同步並行呼叫。對於服務框架而言,BPM Parallel Gateway的功能可以滿足需求,但是為了並行服務呼叫引入 BPM流程引擎顯然是得不償失,我們可以參考 Parallel Gateway的偽非同步並行呼叫來實現服務框架的並行服務呼叫。
下面我們對批量序列服務呼叫實現並行服務呼叫的原理進行講解,如圖。
1)服務框架提供批量服務呼叫介面供消費者使用,它的定義樣例如下:
2)平臺的並行服務呼叫器建立並行 Future,快取批量服務呼叫上下文資訊。
3)並行服務呼叫器迴圈呼叫普通的 Invoker,通過迴圈的方式執行單個服務呼叫,獲取到單個服務的 Future之後設定到 Parallel Future中。
4)返回 Parallel Future給消費者。
5)普通 Invoker呼叫通訊框架的訊息傳送介面,發起遠端服務呼叫。
6)服務端返回應答,通訊框架對報文做反序列化,轉換成業務物件更新 Parallel Future的結果列表。
7)消費者呼叫 Parallel Future的 get(timeout)方法, 同步阻塞,等待所有結果全部返回。
8) Parallel Future通過對結果集進行判斷,看所有服務呼叫是否都已經完成(包括成功、失敗和異常)。
9)所有批量服務呼叫結果都已經返回, Notify消費者執行緒,消費者獲取到結果列表,完成批量服務呼叫,流程繼續執行。
通過批量服務呼叫 + Future機制,我們實現了並行服務呼叫,而且沒有建立新的執行緒,使用者不用擔心依賴執行緒上下文的功能出異常。該方案唯一的缺點就是使用者需要呼叫平臺提供的並行服務呼叫介面,這個會導致 API層面的依賴,對於努力構建零依賴的服務框架而言不是昀優的選擇。但事實上完全的零依賴是不存在的,即便 100% XML配置也是一種配置依賴,所以在設計過程中要能夠識別並抓主要矛盾點,做到有所舍,否則設計工作將步履維艱。
泛化呼叫
泛化呼叫通常包含兩種模式:泛化引用和泛化實現。泛化引用主要用於客戶端沒有 API介面及資料模型的場景,引數及返回值中的所有 POJO均用 Map表示,通常用於框架整合,比如實現一個通用的服務測試框架。泛化實現主要用於伺服器端沒有 API介面及資料模型的場景,引數及返回值中的所有 POJO均用 Map表示,通常用於框架整合,比如實現一個通用的遠端服務Mock框架。泛化呼叫的設計要點如下。
1)分散式服務框架提供泛化介面,供服務提供者實現和消費者引用,它的參考定義如下:
2)消費者如果引用泛化介面,則直接將請求引數轉換成 Map,應答訊息也自動轉換成 Map。
3)服務提供者如果使用泛化實現釋出服務,則自動將請求引數轉換成 Map,呼叫GenService的泛化實現類,應答訊息自動包裝成 Map返回。
泛化呼叫由於比較靈活,沒有服務契約,因此在實際專案中慎用,它通常用於測試整合、系統上線之後的回聲測試等。
相關推薦
服務框架多形式的服務呼叫:同步、非同步、並用、泛化
服務框架支援多種形式的服務呼叫,我們對下面這幾種服務呼叫的原理和設計進行講解。 同步服務呼叫 同步服務呼叫是最常用的一種服務呼叫方式,它的工作原理和使用都非常簡單,分散式服務框架預設都需要支援這種呼叫形式。 它的工作原理如下:客戶端發起遠端服務呼叫請求,使用者執行緒完成訊息序列化之後,將訊息投遞
深入淺出微服務框架dubbo(四):設計篇
四、 設計篇本篇是《深入淺出微服務框架dubbo》的終篇4.1執行緒模型netty+zookeeper+curator+dubboProtocol+hession2seralization組合4.2協議資料格式這裡引用官網的一張圖:第三行代表了協議頭,Magic,serial
Java多執行緒10:同步不具有繼承性
父類的同步操作子類是不可以繼承獲得的 package unit2; public class Demo8_tongbubujujichengxing { public static void m
分散式服務框架中的服務優先順序排程
學個名詞吧,SLA(Service Level Agreement)服務級別協議 ^^ 系統資源有限時,為了保證高優先順序的服務可以正常執行,保障服務SLA,需要降低一些非核心服務的排程頻次,釋放部分資源佔用,保障系統的整體平穩執行 優先順序排程的策略很多,對分散式框
Dubbo Ecosystem - 從微服務框架到微服務生態
從微服務框架到微服務生態,這是微服務發展的必然趨勢,也是Dubbo社群滿足開發者更高效的構建微服務體系期望的使命和擔當。 近期,Apache Dubbo PPMC 望陶(社群暱稱:ralf0131)做了主題為《首次直播揭祕 Apache Dubbo Ecosystem:從微服務框架到微服務生態》的直播分
IOS 呼叫WebService 同步和非同步
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
吳恩達機器學習程式設計題ex1下 多變數線性迴歸: (python版含題目要求、程式碼、註解)
在這部分中,你將使用多變數線性迴歸去預測房屋價格,假設你要賣掉房子而且你想知什麼是一個好的市場價格,去做的一個方式就是首先收集最近出售的房子資訊並製作房屋價格的模型,檔案ex1data2/txt包含了一個房屋價格在Portland的訓練集,第一列是房子大小,第二列是臥室的
IO模型:同步與非同步,阻塞與非阻塞
Unix下的IO可以區分為5種I/O模型: 阻塞式I/O非阻塞式I/OI/O複用(select和poll)訊號驅動式I/O(SIGIO)非同步I/O Unix下一個輸入操作可分為兩個步驟: 等待資料準備好從核心向程序複製資料 對於一個網路I/O的輸入操作也是一樣:
原生JavaScript實現Ajax(二):同步,非同步,GET,POST
上文使用同步方式實現了ajax,本文使用非同步的方式,因為非同步才是我們的目的,也是真正常用的手段,使用非同步需要觸發readystatechange事件,然後檢測readyState這個屬性就行。不同的瀏覽器,這裡略有不同,但大致分為下面5種狀態值:
Boost.Asio C++ 網路程式設計之二:同步和非同步
首先,非同步程式設計和同步程式設計是截然不同的。在同步程式設計中,所有的操作都是順序執行的,比如從socket中讀取(請求),然後寫入(迴應)到socket中。每一個操作都是阻塞的。因為操作是阻塞的,所以為了不影響主程式,當在socket上讀寫時,通常會建立一個
花擦節 dubbo非同步呼叫變同步,解決非同步呼叫返回值null的問題
花擦節 閃電購拼團狂歡節微信中開啟:http://www.52shangou.com/buyer/pintuan/index.html dubbo非同步呼叫變同步 當consumer或provider配置async屬性時,會有傳遞性,後面呼叫都會變非同步,如果鏈路
iOS開發之網路程式設計篇三:同步,非同步請求差異及用法
在網路請求方式上,有同步和非同步之分,相關內容涉及到執行緒部分知識,這一節咱們需要知道如何去傳送一個同步或者非同步的請求,以及它們二者的區別。 一、同步請求 在網路程式設計第二篇,咱們寫的get,post請求使用的都是同步請求,那結合同步非同步、get/post組
zookeeper學習心得二:同步與非同步
上一節中,我們看到很多操作zk節點的方式有同步和非同步兩種方式,那麼問題來了: (1)兩種方式有什麼區別? (2)哪種方式更好?應該用那種方式來寫程式碼? (3)最好的方式有哪些其他方面的知識? 本節我們從這三個角度來分析這個問題,畢竟基礎得好才可以
多線程學習:Volatile與Synchronized的區別、什麽是重排序
art 不可 順序 經典的 排序 傳遞 -s style family java線程的內存模型 java的線程內存模型中定義了每個線程都有一份自己的共享變量副本(本地內存),裏面存放自己私有的數據,其他線程不能直接訪問,而一些共享變量則存在主內存中,供所有線
同步、非同步與阻塞、非阻塞
UNIX下可用的I/O模型: 阻塞式I/O; 非阻塞式I/O; I/O複用(select,poll,epoll…); 訊號驅動式I/O(SIGIO); 非同步I/O(POSIX的aio_系列函式); 阻塞式I/O模型:預設情況下,所有套接字都是阻
同步、非同步與阻塞、非阻塞的辨別理解
所謂同步非同步,只是對於水壺而言,即應用程式。 雖然都能幹活,但響水壺可以在自己完工之後,提示老張水開了。這是普通水壺所不能及的。 同步只能讓呼叫者去輪詢,造成老張效率的低下。 所謂阻塞非阻塞,僅僅對於老張而言。 立等的老張,阻塞;看電視的老張,非阻塞。 情況1和情況3中老張就是阻塞的。雖然3中響水
Java 同步和 非同步 的區別、聯絡
對於我們開發的網站,如果網站的訪問量非常大的話,那麼我們就需要考慮相關的併發訪問問題了。而併發問題是絕大部分的程式設計師頭疼的問題, 但話又說回來了,既然逃避不掉,那我們就坦然面對吧~今天就讓我們一起來研究一下常見的併發和同步吧。 為了更好的理解併發和同步,我們需要先明白
easyui中最新版本的TreeGrid同步樹形表格、同步加非同步樹形表格、樹形表格分頁且非同步檢視子節點
最近做一個專案,專案中開始使用的TreeTable的一個純js外掛。也許是對這個封裝的js不熟悉,不管怎麼除錯,出來的效果總是不太理想。沒得辦法,最後想起來easyUI對樹形表格的展示效果還不錯。 於是就根據easyUI官方最新的Demo做了下面的案例:
關於同步、非同步與阻塞、非阻塞的理解
1、前言 前一段時間出去面試,被問到同步、非同步與阻塞、非阻塞的區別。我一時半會沒有想出來,作為一個工作三年的人來說,實在很慚愧。我當時理解同步、非同步屬於兩個程序中間的協作關係,例如使用瀏覽器訪問一個網站,需要多次請求服務端,才能載入完整個頁面的內容。同步的操作如
SpringBoot2.0高階案例(08):整合 Dubbo框架 ,實現RPC服務遠端呼叫
一、Dubbo框架簡介 1、框架依賴 圖例說明: 1)圖中小方塊 Protocol, Cluster, Proxy, Servi