rabbitmq在藝龍業務系統中的實踐

來源:互聯網
上載者:User

標籤:

rabbitmq作為成熟的企業訊息中介軟體,實現了應用程式間介面調用的解耦,提高系統的輸送量。

下面介紹下rabbitmq的一些基本概念:

  • message acknowledgment: 訊息確認,解決訊息確認問題,只有收到ack之後才能從訊息系統中刪除。
  • message durability: 消 息持久化,當rabbitmq退出或崩潰後,會把queue中的訊息持久化。但注意,RabbitMQ並不能百分之百保證訊息一定不會丟失,因為為了提 升效能,RabbitMQ會把訊息暫存在記憶體緩衝中,直到達到閥值才會批量持久化到磁碟,也就是說如果在持久化到磁碟之前RabbitMQ崩潰了,那麼就 會丟失一小部分資料,這對於大多數情境來說並不是不可接受的,如果確實需要保證任務絕對不丟失,那麼應該使用事務機制
  • exchange: 映射關係,實現訊息名和隊列之間的映射,根據訊息名將訊息發送到相應的隊列中。
  • 常見的映射模式:
  • direct:轉寄訊息到routigKey指定的隊列
  • topic:按規則轉寄訊息(最靈活)
  • headers:
  • fanout:轉寄訊息到所有綁定隊列
  •  
  • routing:exchange和queue之間綁定的媒介,成為routing key

在elong,我們開發了一套基於rabbitmq的訊息系統,可以實現訊息的可靠傳輸,提供了簡單的restful api, 減少業務使用rabbitmq的學習成本。

 下面說下這套系統 jmsg的主要組成部分,在說之前,需要首先串連資料庫結構:  1.MessageConfig 發送端配置,訊息->Queue映射關係 CREATE TABLE `MessageConfig` (  `ID` int(11) NOT NULL AUTO_INCREMENT,  `MessageName` varchar(200) NOT NULL,  --訊息名稱  `ExchangeName` varchar(200) NOT NULL, --訊息名和隊列的映射關係  `Priority` varchar(50) DEFAULT NULL,  -- exchange與queue之前綁定的媒介  `UseDelayRetry` bit(1) DEFAULT NULL, — 是否使用重試  `DelayTime` int(11) DEFAULT NULL,   —延遲多長時間重試   `MaxRetryCount` int(11) DEFAULT ‘3’,  —最大重試次數  `_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  PRIMARY KEY (`ID`),  UNIQUE KEY `IX_MessageName` (`MessageName`)) ENGINE=InnoDB AUTO_INCREMENT=409 DEFAULT CHARSET=utf8;  欄位解釋:MessageName: 訊息名稱ExchangeName: exchange名稱Priority: 優先順序,一個業務線可以根據不同優先順序有多個隊列UseDelayRetry:是否使用重試DelayTime: 延遲多長時間重試MaxRetryCount: 最大重試次數 表資料    2.MessageConsumersConfig 表: 消費端配置,訊息->接收方配置 CREATE TABLE `MessageConsumersConfig` (  `ID` int(11) NOT NULL AUTO_INCREMENT,   `MessageName` varchar(200) NOT NULL, — 訊息名  `Url` varchar(400) NOT NULL,  — 訊息消費的url  `TimeOut` int(11) DEFAULT ‘10’,    PRIMARY KEY (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=266 DEFAULT CHARSET=utf8; MessageName: 訊息名Url: 訊息消費urlTimeout: 消費逾時時間   CREATE TABLE `QueueSetting` (  `ID` bigint(20) NOT NULL AUTO_INCREMENT,  `QueueName` varchar(50) DEFAULT NULL,  `QOS` int(11) DEFAULT NULL,  `ParallelCount` int(11) DEFAULT NULL,  `LastUpdateTime` datetime DEFAULT NULL,  `LastUpdateUserName` varchar(50) DEFAULT NULL,  PRIMARY KEY (`ID`)) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=utf8;   rabbimq 配置

serverIP : 伺服器ip

Port:服務連接埠號碼

UserName: 使用者名稱

PassWord: 密碼

MaxPoolSize: 最大串連池大小

RequestedHeartbeat: 請求心跳檢查時間(s)

RequestedConnectionTimeout: 請求連線逾時時間

FailedLogBaseDir: 失敗日誌儲存目錄

ConnectionTimeOut: 串連保持時間(ms)

SendTimeOut: 發送逾時(s)

ReceiveTimeOut: 接收逾時時間(s)

SendLogBaseDir(發送日誌目錄)

1  jmsg-client

訊息發送用戶端,提供發送訊息的介面

流程圖:

其中比較重要的是RabbitConnectPool(單例建立串連池),該類中比較重要的屬性和方法

_max: //可以建立的最大串連數

_created: 已經使用的串連數

_used: 已經使用的串連數

_sendTimeOut: 發送串連請求逾時時間

_receiveTimeOut: 接收串連成功的逾時時間

_clientExpires: 串連到期時間

_connectionTimeOut: 連線逾時

_qos:

 

重要的方法:

getSendingConnection(): 擷取一個發送端的串連, 如果不是強制,就從串連池中擷取串連,否則強制建立一個串連

getNextProxy:() 從串連池中過去串連(返回RabbitSendProxy), 如果超過最大串連數,則建立新串連, 否則加鎖擷取 proxy(pollProxy),如果返回為空白,這等待,直到擷取串連為止

pollProxy(): 擷取串連, 從proxyqueue中poll,如果串連不可用,這_created–, 然後_used++, 如果建立條數 < 最大數, 這擷取新串連(newProxy(), create++, _used++

returnToPool(): 返回到串連池,

getNewProxy(): 三次重試, getProxy(), 稍候再試0.1s

getProxy(): 通過原廠模式產生串連

 

   RabbitProxy: 用戶端串連rabbitmq 代理介面,做為串連池中的單元串連代理,可以由發送端和接收端繼承

主要屬性:

isAvailable: 是否可用,預設true

createTime: 建立時間,

DisposeListener: 串連池關閉需要執行的介面

connectionTimeout: 連線逾時時間, 目前時間-createTime <= connectionTimeout可用

receiveTimeOut: 接收逾時時間

Connection: 最主要的類,com.rabbitmq.client.Connection 串連

qos: 伺服器一次可以傳輸的訊息條數

Channel : 管道,串連建立管道,進行資料轉送

ConnectionFactory: 串連工廠,建立rabbitmq串連

主要操作:

isAvailable(): 串連是否可用

 dispose(): 關閉串連 需要關閉channel和connection   RabbitSendProxy 發送端代理, 預設開通channel confirsSelect,即確認機制

send(): 發送方法

流程:轉換成byte數組->檢查訊息長度(小於64K) -> 快取資料,等待確認->發送(basicPublish) -> 在接收到後刪除快取資料

 

下面說下如何保證資料一定能發送到rabbit queue中:

為瞭解決發送失敗的問題,解決的思路無非是訊息持久化,採用檔案做持久化是比較好的選擇。

具體的實現是訊息失敗後,放入blockingqueue作為資料換出的地方,定期從queue中讀取資料存放區檔案,開啟定時任務讀取資料,重新send到queue中。

2 jmsg-server

作用: 從rabbitmq中讀取訊息,通過http介面調用消費者

資料庫

jmg-server的流程:

  • 從資料庫拿到該機器需要處理的queue,初始化rabbitmq串連池
  •   遍曆queuelist,註冊監聽器,對每個queue擷取的訊息處理
  •  對每個queue開啟MessageReceiver線程,監聽該queue資料
  •  messageReceiver 開啟線程池,qos是線程池大小
  •  messageReceiver是一個迴圈,不斷擷取rabbitmq server串連
  •  擷取到資料後,開啟線程進行處理MessageProcessTask, 該任務主要是尋找ImessageListener的實作類別,調用receive方法
  • 接收到訊息處理:

消 息校正 -> 擷取訊息配置,找到消費者-> 判斷沒有正在處理 -> 訊息還沒有處理成功or 沒有達到最大處理失敗次數 – > 首次接收的訊息入庫- > 廣播訊息到接收方 -> 處理成功,記錄messageLog,修改狀態; 處理失敗,發送到rabbitmq-server,等待下次處理.

 

 

 

3  rabbitmq-server

採用叢集的方式搭建, 通過nginx對外提供統一的url

叢集中一些重要的概念:

network partition: 網路中斷,一般是子網之間的裝置中斷,這樣在不同子網的裝置通訊會出現問題

搭建叢集:

abbitmq的叢集是依附於erlang的叢集來工作的,所以必須先構建起erlang的叢集景象。Erlang的叢集中各節點是經由過程一個magic cookie來實現的,這個cookie存放在 $home/.erlang.cookie 中(像我的root使用者安裝的就是放在我的root/.erlang.cookie中),檔案是400的許可權。所以必須包管各節點cookie對峙一致,不然節點之間就無法通訊。

方案1: 普通叢集

erlang 通過cookie來決定是否能和另外一個節點通訊,通常的做法是在一個機器上產生cookie檔案,拷貝到叢集中的其他機器。

叢集可以通過單邏輯broker的方式來串連多個機器。各機器間通過Erlang訊息傳遞來通訊,因此,叢集內所有節點都必須有相同的Erlang cookie。叢集內機器間的網路連接必須是可信的,且所有機器必須運行相同版本的Erlang和RabbitMQ。

虛擬機器、交換器、使用者和許可權會自動鏡像到叢集內所有節點。隊列可能位於單節點上,或者鏡像到多個節點上。用戶端串連到叢集內任何節點都能看到叢集內所有隊列。

步驟

1

rabbit1$ rabbitmq-server -detachedrabbit2$ rabbitmq-server -detachedrabbit3$ rabbitmq-server -detached

2 加入以rabbit3為叢集,叢集名為[email protected],則需要在rabbit1和rabbit2上執行下面操作,加入[email protected],

rabbit2$ rabbitmqctl stop_appStopping node [email protected] ...done.rabbit2$ rabbitmqctl join_cluster [email protected]Clustering node [email protected] with [[email protected]] ...done.rabbit2$ rabbitmqctl start_appStarting node [email protected] ...done.

3 同樣在rabbit3,上操作,加入[email protected]

rabbit3$ rabbitmqctl stop_appStopping node [email protected] ...done.rabbit3$ rabbitmqctl join_cluster [email protected]Clustering node [email protected] with [email protected] ...done.rabbit3$ rabbitmqctl start_appStarting node [email protected] ...done.

方案2:鏡像隊列

上述配置的RabbitMQ預設叢集模式,但並不包管隊列的高可用性,儘管互換機、綁定這些可以複製到 叢集裡的任何一個節點,然則隊列內容不會複 制,固然該模式解決一項目組節點壓力,但隊列節點宕機直接導致該隊列無法應用,只能守候重啟,所以要想在隊列節點宕機或故障也能正常應用,就要複製隊列內 容到叢集裡的每個節點,須要建立鏡像隊列

Federation允許一個broker上的交換器接收發布到另一個broker(這個broker可能是單獨的機器或者叢集)上的交換器的訊息。為了節點間能夠通過AMQP(帶上SSL選項)通訊,組成federation的兩個交換器之間必須授予適當的使用者和許可權。

組成federation的交換器之間通過單向點對點連接。預設情況下,在federation串連上,訊息僅僅被轉寄一次,但是這樣可增加更多、更複雜的路由拓撲。

在federation串連上,有些訊息可能不會被轉寄;如果一條訊息到達federated交換器後不能被路由到某個隊列,則它不會被轉寄。

你可以在Internet上通過federation串連各個broker來pub/sub訊息。

 

方案3: shovel

相比federation,工作在更低一層,shovel簡單從一個broker的一個queue中消費訊息,並傳遞到下一個broker的exchange上

the shovel simply consumes messages from a queue on one broker, and forwards them to an exchange on another.

參考資料:

 1 http://lynnkong.iteye.com/blog/16996842 http://blog.chinaunix.net/topic/surpershi/

3 http://www.rabbitmq.com/documentation.html

   

rabbitmq在藝龍業務系統中的實踐

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.