.Net下RabbitMQ的使用(8) -- 遠程過程調用RPC


 

RPC是在計算中是一種常見的模式,是通常我要用消息隊列來實現RPC有3個關鍵點:

1. 服務的尋址

2. 消息的接收

3. 消息的關聯

 

在RabbitMQ的.net客戶端里,提供了2個類:SimpleRpcClient 和 SimpleRpcServer 來讓我們方便的開發RPC應用。

因為RabbitMQ的RPC一定是基於隊列的,所以在客戶端和服務端都需要要一個各自的隊列,客戶端的隊列用來接收服務回復的數據,服務端的隊列用來緩存需要調用的服務的Request。這些請求一定不單單從一個客戶端而來。

服務的地址是公開的,地址也就是一個隊列,客戶端只要把參數放進這個服務端監控的隊列中就可以了。服務端每次從隊列中獲得的一個數據即是一次調用。

服務不單單為一個客戶端服務,所以在客戶端調用的參數里面,每次都需要加上需要回復的隊列名字,也就是要告訴服務端方法調用結果需要放在這個隊列里。客戶端不僅可以直接把隊列的名字放在參數里面還可以給出一個路由,例如這樣的格式:exchangeType://exchangeName/routingKey。 exchangeType就是exchange 的類型,四選一。這個隊列里面的數據就是我調用服務的返回值。每一個客戶端都有一個這樣的返回值隊列。你可以用如下命令查看隊列的情況。

 

image

 

客戶端也許調用比較頻繁,或者是不是調用一個方法,返回值不同,又或者服務端每次返回的時間都不一樣,不能保證回復的順序和客戶端調用的順序一致。那么程序是怎么保證這個返回值就是這次調用的結果呢?RabbitMQ使用了CorrelationId,他是一個屬性,在每次調用的時候,客戶端會生成一個這樣的屬性來代表這次調用,Id唯一的。當然服務端也會把這個Id放在返回值里面一同返回,這個客戶端就可用這個CorrelationId來配對一次調用。

如果在調用過程中,CorrelationId沒有被匹配到,那么返回值這個消息就會被丟棄,而不會出拋出異常。

一個服務端往往不只提供一個服務(方法),在一個隊列中也許會有不同方法的Request,這種就需要根據每次Request里面帶的參數來判斷是調用具體哪個方法的。一個服務提供多個方法常見也有顯而易見的弊端也,如果某些方法服務處理的時間比較長的話就需要其他調用等待。如果服務端采用多線程處理,那么在客戶端調用的時候,每個服務端的方法都要一個專門的SimpleRpcClient 去調用。也就是說,不同的方法需要有不同的callback隊列,這樣才能避免客戶端會猶豫匹配CorrelationId不對而丟棄消息。

 

RPC調用的順序如下:

1. 在客戶端初始化的時候,也就是SimpleRpcClient類初始化的時候,它會隨機的創建一個callback隊列,用於存放服務的返回值,這個隊列是exclusive的。連接斷開就沒有了。

2. 客戶端在發送Request的時候,會加上兩個參數:ReplyTo和CorrelationId,前者用於告訴服務返回值放在哪個隊列里面(callback的隊列名)或路由,后者用於配對每次的Request。這兩個屬性都放在客戶端發送消息的附帶的IBasicProperties字典中。

3. 把消息放入服務的監控隊列里,消息里面自然有調用方法的參數。

4. 服務在所監控的隊列中收到數據后,進行運算,並把返回值放入到客戶端指定的callback隊列中去。

5. 客戶端在發送完Request后,便去自己創建的callback隊列監聽,如果獲得到數據,則查看里面的CorrelationId,如果和調用Request一致,則返回結果。

 

SimpleRpcClient 和 SimpleRpcServer 只是RabbitMQ .net客戶端的一個實現。知道了原理,我們也可以自己實現RPC的功能。

 

服務的負載均衡

服務端往往有一個隊列來接收客戶端的請求,我們記得在這一篇中,我們看到了RabbitMQ內置的消費者負載均衡功能,那么對於RPC的服務端,我們是不是也適合呢?答案是肯定的。因為我們RPC服務端其實也就是一個Worker,我們只要運行多個監控同一個隊列的服務端就可以了。所有的被監控隊列中的請求都平均的分配到不同的服務端去了。

 

您可以點擊這里下載RPC示例代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM