1. 程式人生 > >分散式之RPC的協議以及錯誤處理

分散式之RPC的協議以及錯誤處理

本文主要內容來自於
用慣了Web Services,但是很少知道RPC和RMI,更不用說它們之間的區別了,所以先總結一下RPC以及RMI到底是什麼東西!!

在分散式系統通訊中有兩個最基本的遠端呼叫技術,分別是:

  • RPC:一個對遠端節點上的過程的呼叫就像呼叫本地節點那樣完成;
  • RMI:與特定的Java RMI要進行區分,與RPC最大區別在於使用了面向物件的概念,那麼在遠端呼叫時可以把物件應用作為引數傳遞,它的實現最典型的就是Java RMI,但不限於Java RMI;

1、互動協議

遠端呼叫允許客戶端透明地呼叫在伺服器程式中的過程,而這些伺服器程式在不同的程序中,並且通常在不同於客戶端的計算機中。如果要完成遠端呼叫,必然要設計出一種協議讓客戶端和服務端來遵守,這樣才能讓呼叫者和提供呼叫過程者協同完成工作。其實我們對這種“協議”也不陌生,比如熟知的TCP/IP協議和Http協議等等。在遠端呼叫過程中有多種互動協議,如下:

  • 請求協議:可以用在不需要從遠端操作中返回值或者客戶端不需要得到遠端操作執行確認的場景中,請求傳送後客戶端不需要等待應答訊息而可以繼續執行;
  • 請求-應答協議:這種方式使我們最常見的,伺服器的應答訊息可以看做是客戶端請求訊息的一個確認;
  • 請求-應答-確認應答協議

這三種協議傳遞訊息的方式如下:

協議 客戶端 服務端 客戶端
請求協議 請求 XX XX
請求-應答協議 請求 應答 XX
請求-應答-確認協議 請求 應答 確認應答

這裡著重瞭解一下請求-應答協議。在請求-應答協議中訊息可以是同步的也可以是非同步的。

  • 同步:來自伺服器的應答到達客戶端之前客戶端的程序是阻塞的,如果寫過socket程式的人一定深有體會;
  • 非同步:可以用在客戶端對服務端返回的結果允許延遲的情況下,例如執行該過程需要消耗很長的時間,這樣就避免了客戶端程序的堵塞,但是如果服務端執行完則可以通過回撥的方式來通知客戶端執行結果;

在通訊過程中涉及到三個原語,關於原語可以理解為不可分割的部分,在執行原語過程中不可以被打斷,可以類似理解為一個事務。該通訊同步過程如下:

  • doOperation:呼叫遠端操作,方法引數包括遠端伺服器的地址、埠以及待呼叫的操作和需要的引數,返回的結果可以是一個位元組陣列,然後根據協議使用的編碼方式解碼該陣列得出結果,傳送請求之後,程序開始阻塞來接收應答訊息。
  • getRequest:伺服器程序通過該方法獲取請求資訊,當確定操作後開始執行,完成之後通過sendReply方法向客戶端傳送應答訊息,這是客戶端接收訊息後才解除阻塞繼續執行。

下面的偽碼可以大致描述上述的三個方法:

//doOperation()
public byte[] doOperation(Remote remote, int operationId, byte[] arguments)

在該方法的引數中,Remote描述了遠端的伺服器,裡面可以包含伺服器的地址和埠以及對應的一些處理的方法;第二個引數operationId用來標識要呼叫哪個操作,用來確定操作過程;第三個引數就是用來傳遞引數。

//getRequest()
public void getRequest()

該方法只是用來從伺服器的一個埠上獲取客戶端的請求。

//sendReply()
public void sendReply(byte[] reply, Remote client)

在該方法的引數中,client引數和remote引數類似是用來描述客戶端的,包括地址和埠號,reply是需要返回給客戶端的資料。
就像在傳送Http請求和接收響應時的Headers一樣,請求訊息和應答訊息中也有傳遞資訊的格式,如下所示:

資訊頭 資料形式
messageType int
requestId int
remoteRef 遠端物件引用
operationId int/String
arguments byte[]
  • messageType表明該訊息是請求訊息還是應答訊息;
  • requestId是用來標明一個請求訊息的,在每個doOperation()方法中都會為一條請求訊息生成一個RequestId,這樣在該請求訊息傳遞到伺服器端時,伺服器端的程式就會將該Id複製到對應的應答訊息上,這樣在客戶端才能檢查返回的應答資訊是否和發出的請求資訊相對應;
  • remoteRef用來定位客戶端或者伺服器,包括ip和埠號等;
  • operationId用來標識要呼叫哪項操作,可以通過索引將所有的操作編號;
  • arguments則是要使用到的引數;

其實在上述的requestId是有缺陷的,由於傳送請求訊息的程序可能不止一個,而且這些程序可能不在同一臺電腦上,那麼這些訊息的requestId不會重複嗎?當然會了,那麼怎樣解決這個問題?可以加上該程序所在的主機的ip地址和相應的埠號就能區分出這些requestId是從哪些程序傳送出來的。
對於請求-應答協議可以從Http協議中深入瞭解,因為這就是一個典型的請求-應答協議的例子。

2、故障處理

在遠端過程呼叫時不可避免的會出現各種各樣的問題,比如由於網路傳輸的問題導致的資訊傳遞中斷,或者當伺服器出現故障時不能及時返回應答資訊等等。想想如果在傳送Http請求時出現這樣的問題我們會看到什麼,網路錯誤!!Time Out!!通常就是幾種方式,如果使用了瀏覽器,不同的瀏覽器可能會建議我們去檢查什麼東西。那麼在遠端呼叫時一樣要考慮這種問題,這裡使用超時來暗示這種問題的存在。但是當超出我們設定的時間之後會發生什麼,其實是由我們來處理的,比如:

  • 最簡單的但是也是最懶的方法,直接將這種超時的資訊拋給客戶端呼叫者,由他來決定下一步幹什麼,但是這就顯得我們的方法太不“智慧”了;
  • 另外一種方法可以通過程式設計來實現,如果這次超時,可以進行重試,重試的次數可以程式設計決定,多長時間重試一次亦可以程式設計決定;
  • 或者在客戶端通過非同步的方式來呼叫該過程,那麼我們在客戶端就不用考慮超時的問題了,這樣請求訊息和應答訊息就有足夠的時間進行傳遞,而當應答訊息返回時,可以通過回撥的方法來通知客戶端,這種可以設計成基於事件的,類似於AngularJs中的onSuccess()和onError()等,但是這樣做的前提是客戶端對該應答訊息的延遲有相當的容忍程度;

上面提到可以通過重試來解決超時的問題,但是別的問題又來了,當在伺服器端對客戶端呼叫的操作的處理的時間和返回結果的時間總和大於我們在客戶端設定的超時時間,就會產生請求訊息重複傳送的問題,但是本來執行該項請求就很費時間,所以絕不能夠再讓伺服器重複執行該操作,所以在服務端應該能夠識別requestId連續且來自同一個客戶端的訊息並且過濾掉重複的訊息。

對於重複的請求訊息,其中還有一些細節可以體會一下。

  • 如果服務端接收到重複訊息時還沒有發回應答訊息,這樣就比較簡單了,等待服務端執行完畢然後返回該應答訊息即可;
  • 但是如果接到重複訊息之後發現應答訊息已經發送出去,不可否認,這種情況是存在的,這時服務端就不能區分該重複的請求資訊是客戶端故意重新發的,還有由於超時程式自己重試的。
    • 我的想法是,如果客戶端和服務端可以溝通就好了,可以彼此設定超時時間是多少,這樣在服務端那就可以根據超時時間來判斷自己識別重複請求訊息的策略。
    • 但是如果彼此不能協商,那麼必須要做的就是每一個請求訊息都要做出應答,如果對於不耗時的操作可以這麼做,是沒有問題的,這可以看做是一個冪等操作,這種操作執行一次的效果與執行多次的效果是相同的;但是對於耗時的操作,可以通過在服務端使用快取儲存上次操作的結果來說減少執行的時間,但是這也有問題,如果儲存在快取中的資料與實際儲存在伺服器後臺的資料不一致時就會返回錯誤的資訊,這種問題可以通過在更新伺服器的資料時也同時更新快取或者清除相關的快取來保持資料的一致性;

相關文章:

相關推薦

分散式RPC協議以及錯誤處理

本文主要內容來自於 用慣了Web Services,但是很少知道RPC和RMI,更不用說它們之間的區別了,所以先總結一下RPC以及RMI到底是什麼東西!! 在分散式系統通訊中有兩個最基本的遠端呼叫技術,分別是: RPC:一個對遠端節點上的過程的呼叫就像呼

關於debug.keystore文件用法以及錯誤處理

如果 androidd 生產 java 選擇 use run cts sdn 在開發過程中需要頻繁的為測試的同事簽名apk,非常很麻煩,把默認debug.keystore文件替換成發布用(生產環境)的簽名文件,不用頻繁地簽名apk文件了。 如果直接使用生產keys

Python學習筆記面對象與錯誤處理

實現 單繼承 父類 成對 數據類型 itl 同時 屬性 子類 反射 __import__()函數用於加載類和函數 __import__(name[, globals[, locals[, fromlist[, level]]]]) 參數說明: n

Androidcardview屬性以及陰影處理

Android之cardview屬性以及陰影處理 開發中,專案會含有大量的圖片需要展示,需要圓角圖片,帶圓角的組合控制元件等.本文對cardview使用,以及屬性做開發記錄,方便後來者查閱(博主也容易忘東西) 先看效果圖(博主開發的一個VR中控平板端截圖) 一

【SpringBoot學習路】15.錯誤處理機制

轉載宣告:商業轉載請聯絡作者獲得授權,非商業轉載請註明出處.原文來自 © 呆萌鍾【SpringBoot學習之路】15.錯誤處理機制  SpringBoot預設的錯誤處理機制 預設效果 瀏覽器,返回一個預設的錯誤頁面 瀏覽器傳

【WIN32旅】WINDOWS錯誤處理與參考(四)

    上一篇,我們說到了GetLastError()函式,可是它返回的是一個DWORD(雙字型)的錯誤程式碼,如果我們並不清楚FormatMessage()函式或者就只想快速簡單地得到錯誤

kaldi安裝以及錯誤處理

首先下載kaldi包 git clone https://github.com/kaldi-asr/kaldi.git 然後安裝依賴庫 進  cd tools  tools檔案 執行  ./extras/check_dependencies.sh 根據它要求安裝

Centos下vsftp的配置以及錯誤處理

    學習linux也有一段時間了,以前都是開個虛擬機器在虛擬機器下全屏搞學習,不過工作中貌似是沒有給我們在伺服器上寫程式碼的條件吧,所以決定模擬實際環境,配置一下學習環境     首先是安裝SecureCRT 我安裝的是7.0。 破解什麼的大家自己懂得。     然後是

nginx安裝以及錯誤處理

nginx下載 nginx的官方下載地址為:http://nginx.org/en/download.html,選擇相應的版本進行下載,其中 nginx-x.x.x(1.12.1)是對應的linux版本,nginx、Windows-x.x.x(1.12.1)

JmeterRPC協議指令碼開發實現

1、首先通過本文是通過jmeter的java請求方式實現RPC協議指令碼請求,具體關於java請求如果基於jmeter實現見:jmeter之java請求;如果還想了解rpc指令碼開發詳細見:rpc協議之hprose介面測試  。 2、分別需要建立兩個類 send類、Ap

Golang核心程式設計(4)-函式以及錯誤處理

可能很多習慣用C或Java的朋友發現,Add方法是以大寫開頭的,這並不符合駝峰式方法命名的規範,但在Go語言中,**以名字以大寫開頭的函式表示可被包之外的程式碼去呼叫,而以小寫開頭的函式則表明只能被本包呼叫,相當於Java中的private關鍵字的作用

SpringBoot錯誤處理機制以及定製錯誤資訊

一、SpringBoot預設的錯誤處理機制 預設效果: 1)、瀏覽器,返回一個預設的錯誤頁面 瀏覽器傳送請求的請求頭: 2)、如果是其他客戶端,預設響應一個json資料 原理: 可以參照ErrorMvcAutoConfigurat

Laravel加密解密/日誌/異常處理及自定義錯誤

文件中 例如 tom 處理器 crypt return cat 情況 而不是 一.加密解密 1.加密Crypt::encrypt($request->secret) 2.解密try {   $decrypted = Crypt::decrypt($encryptedV

PHP錯誤處理

php錯誤報告  PHP程序的錯誤發生一般歸屬於下列三個領域:  1、語法錯誤  語法錯誤最常見,並且也容易修復。如:代碼中遺漏一個分號。這類錯誤會阻止腳本的執行  2、運行時錯誤  這種錯誤一般不會阻止PHP腳本的執行,但會阻止當前要做的事情。輸出一條錯誤,但php腳本繼續執行  3、邏輯錯誤  這種錯誤最

Lighttpd1.4.20源代碼分析 筆記 狀態機錯誤處理和連接關閉

全部 階段 內存 and ces ons keep ren log 這裏所說的錯誤有兩種: 1.http協議規定的錯誤,如404錯誤。 2.server執行過程中的錯誤。如write錯誤。 對於http協議規定的錯誤,這裏的“錯誤”是針對clien

oracle學習多表查詢,子查詢以及事務處理

color 1-1 註意事項 員工 列數 .com 外連接 分析 top-n分析 多表查詢的基礎是采用笛卡爾集: 最終的行數 = 表1的行數 * 表2的行數 最終的列數 = 表1的列數 + 表2的列數 過濾笛卡爾集的關鍵是寫連接條件,N張表至少需要N-1個條件。 多表

mqtt協議-brokermoqutte源碼研究五UNSUBSCRIBE與DISCONN報文處理

mqtt broker moquette 本文講解moquette對UNSUBSCRIBE和DISCONNECT的處理 先說UNSUBSCRIBE,代碼比較簡單 public void processUnsubscribe(Channel channel, MqttUnsubscribeM

Windows核心編程核心總結(第一章 錯誤處理)(2018.5.26)

Windows核心編程之核心總結前沿 學習Windows核心編程是步入Windows編程殿堂的必經之路,2018年寒假重溫了計算機操作系統知識,前陣子又過學習Windows程序設計方面的基礎,正所謂打鐵要乘熱,所以我又入了Windows核心編程的坑啦,哈哈~ 學習目標 每一章的學習都要明確一個目標,就是你學完

RPC機制AMQP協議

引用 inter nsf -a pointer sdn 提交 中間件 發送消息 openstack RPC通信Openstack 的主要組件有 Nova、Cinder、Neutron、Glance 等,分別負責雲平臺的計算、存儲、網絡資源管理。OpenStack 各組件之間

微信公眾號:JSSDK接入以及invalid signature等常見錯誤問題

平臺 不存在 頹廢 字段名 UNC src 拍照 signature 唯一標識 最近在搞微信公眾號開發,進行到網頁開發部分被坑了一天,最坑的問題就是invalid signature,而網上大部分解答這個問題的都沒有說清楚,都直接丟文檔。博主認為這樣很不好。本文是博主結合自