[Erlang 0084] RabbitMQ: fire-and-forget and RPC


  在項目中引入RabbitMQ通常會考慮它會帶來的好處:解耦應用程序,實現不同編程語言之間的互通,解除對特定通信協議的依賴,解除應用程序在時序上執行的依賴(異步).落實到代碼層面就是兩種常用應用模式:"發后即忘"(fire-and-forget)和RPC.

 

fire-and-forget 

 

  之前提到過[ 鏈接],RabbitMQ解決的是應用程序之間互聯(connect)和規模(scale)的問題,消息發送和接收是隔離,發送方不知道消息最終由誰接收,接收方也不必關心消息是誰步發出的;發送和接收是隔離的,消息本質上就是異步的.這種隔離也就解耦了應用程序之間的依賴.RabbitMQ的角色就是應用程序中間的路由器.對於消息的發布方來講這是一種"發后即忘"(fire-and_forget)的發布方式.
  
  fire-and-forget模式發送消息,消息的發送方和接收方彼此隔離,但是如果是RPC調用,如何實現呢?!
  

RPC

 
    RPC需要雙向通信,或者說RPC Server需要明確知道要把消息發送給誰.我們可以在payload的數據部分附加 "發給誰" 這種EndPoint信息. RabbitMQ提供的解決方案:在每一個AMQP的消息頭上有一個reply_to字段.這樣消息的producer就可以指定Queue name,RPC Server接受到消息檢查reply_to字段,創建一個消息包含Response並把queue name作為routing key,訂閱了這個隊列的Client就拿到了消息.

    這里有兩件事情要保證:1.要為隊列創建隨機Name 2.即使Name隨機還是有可能沖突,還需要保證消息通信的獨占性,看看RabbitMQ是怎么滿足這兩點的:

 [1] 之前提到過,如果創建的隊列不指定queue name,RabbitMQ就會創建一個隨機的Name.

 [2] 獨占只需要exclusive參數即可

   總而言之,需要做的就是Client創建一個temporary,exclusive,anonymou的queue,並把queue name設置在RPC 消息的reply_to字段即可.注意這里RPC Server已經知道要投遞到哪個Queue,所以不需要指定Exchange(后面我們會提到在實現層面Queue和Exchange的不同,簡單講queue會有對應的Erlang進程,而exchang只是執行一些模式匹配的檢查並沒有進程實體對應).看下圖:

 

 

略有不同

 

  傳統的RPC調用Client和Server緊密依賴,客戶端連接上服務器,發送一個請求然后阻塞等待服務器響應.這樣的做的特點是客戶端和服務器端是知道對方的.如果RPC Server崩潰掉,客戶端需要重連,如果Server徹底崩掉就要重新找一個提供同樣服務的Server,然后客戶端重連過去.

 

   用RabbitMQ來實現RPC,依然保持Client Server信息隱藏的特點,Client依賴的不是特定的Server而是特定的消息,在有多個等效Server的情況下,一個Server的狀態是否正常不會影響到客戶端的狀態.

  總結一下,使用RabbitMQ是先RPC,客觀上還實現了下面的效果:

  1. 容錯 一個Server崩潰不影響 Client
  2. 解耦了對特定通信協議和接口的依賴,統一走AMQP消息.
  3. 在多個RPC Server之間的負載均衡由RabbitMQ完成

 

RabbitMQ 入門文檔中專門提到了RPC的場景,Python和Java版本的代碼都有,很容易寫一個.net版本這里不再堆疊,請移步這里:

 http://www.rabbitmq.com/tutorials/tutorial-six-python.html

 

 

  

插播幾條關於技術選型,有幾個Nosql相關的舊聞,值得借鑒:

 

 NoSQL不是萬能的,Twitter重新審視Cassandra使用策

 

 Hadoop不是萬能的

 

 Basho:少一些謊言,多一些實踐

 

 

最后貼小圖一張,電影 柔道龍虎榜 里面的采兒

 

 


免責聲明!

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



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