RPC是指遠端過程調用,也就是說兩台伺服器A,B,一個應用部署在A伺服器上,想要調用B伺服器上應用提供的函數/方法,由于不在一個記憶體空間,不能直接調用,需要通過網絡來表達調用的語義和傳達調用的資料。
為什麼RPC呢?就是無法在一個程序内,甚至一個計算機内通過本地調用的方式完成的需求,比如不同的系統間的通訊,甚至不同的組織間的通訊。由于計算能力需要橫向擴充,需要在多台機器組成的叢集上部署應用,
RPC的協定有很多,比如最早的CORBA,Java RMI,Web Service的RPC風格,Hessian,Thrift,甚至Rest API。
一般在RabbitMQ中做RPC是很簡單的。用戶端發送請求消息,伺服器回複響應的消息。為了接受響應的消息,我們需要在請求消息中發送一個回調隊列。可以使用預設的隊列(which is exclusive in the java client.):
AMQP協定為消息預定義了一組14個屬性。
大部分的屬性是很少使用的。除了以下幾種(其餘有興趣可以自行檢視):
deliveryMode: 标記消息傳遞模式,2-消息持久化,其他值-瞬态。
contentType:内容類型,用于描述編碼的mime-type. 例如經常為該屬性設定JSON編碼。
replyTo:應答,通用的回調隊列名稱,
correlationId:關聯ID,友善RPC相應與請求關聯。
在上述方法中為每個RPC請求建立一個回調隊列。這是很低效的。幸運的是,一個解決方案:可以為每個用戶端建立一個單一的回調隊列。
新的問題被提出,隊列收到一條回複消息,但是不清楚是那條請求的回複。這是就需要使用correlationId屬性了。我們要為每個請求設定唯一的值。然後,在回調隊列中擷取消息,檢視這個屬性,關聯response和request就是基于這個屬性值的。如果我們看到一個未知的correlationId屬性值的消息,可以放心的無視它——它不是我們發送的請求。
你可能問道,為什麼要忽略回調隊列中未知的資訊,而不是當作一個失敗?這是由于在伺服器端競争條件的導緻的。雖然不太可能,但是如果RPC伺服器在發送給我們結果後,發送請求回報前就挂掉了,這有可能會發送未知correlationId屬性值的消息。如果發生了這種情況,重新開機RPC伺服器将會重新處理該請求。這就是為什麼在用戶端必須很好的處理重複響應,RPC應該是幂等的。

RPC的處理流程:
當用戶端啟動時,建立一個匿名的回調隊列。
用戶端為RPC請求設定2個屬性:replyTo,設定回調隊列名字;correlationId,标記request。
請求被發送到rpc_queue隊列中。
RPC伺服器端監聽rpc_queue隊列中的請求,當請求到來時,伺服器端會處理并且把帶有結果的消息發送給用戶端。接收的隊列就是replyTo設定的回調隊列。
用戶端監聽回調隊列,當有消息時,檢查correlationId屬性,如果與request中比對,那就是結果了。
這裡采用官網的一個例子來說明,RPC用戶端通過RPC調用伺服器來計算斐波那契額值。
首先是服務端的代碼:
RPC用戶端:
<a href="http://www.rabbitmq.com/tutorials/tutorial-six-java.html" target="_blank">Remote procedure call (RPC)</a>
<a href="http://blog.csdn.net/xiaoxian8023/article/details/48826857" target="_blank">輕松搞定RabbitMQ(七)——遠端過程調用RPC</a>