消息隊列

消息隊列的應用場景

異步:不少場景下,系統不須要當即處理消息,此時能夠將消息存入隊列中,並在以後的適當時間再進行處理。數據庫

好比,在分佈式環境中,統計A服務調用B服務的次數。此時,可將調用日誌寫入消息隊列,由C服務讀取消息隊列的日誌消息來計算調用次數。以下圖:後端

解耦:不一樣系統甚至異構系統避免直接依賴耦合。服務器

好比,若是A服務直接依賴B服務,當B服務出現異常或者故障時,將影響A服務的穩定。網絡

引入消息隊列以後,A服務不直接依賴B服務,A服務發送的消息將保存在消息隊列中,B服務故障時不能處理消息,消息也不會丟失,不會對A服務形成影響,待B服務恢復以後再處理,這樣就實現了A服務和B服務的解耦。以下圖:多線程

流量控制:在高併發的環境中,服務請求瞬時大量增長,將對服務器形成極大的壓力,若是引入消息隊列,服務請求的大量增長將不會影響服務端的壓力,避免系統崩潰。架構

典型的場景如電商每一年的雙十一活動等,以下圖: 併發

用戶請求先寫入消息隊列而不是直接打到電商系統,若是隊列已滿,則拒絕後續的請求,如此就保護了後端電商系統不至於崩潰。負載均衡

消息隊列的架構圖

消息隊列從邏輯角度而言,能夠分爲四大模塊:生產者模塊、存儲模塊、消費者模塊和配置管理模塊,每一個模塊都可以集羣方式部署。以下圖所示:框架

生產者模塊:主要負責接收上游系統發送過來的數據。異步

生產者模塊主要解決的問題是,如何處理大量的鏈接請求,而且快速的處理髮送過來的數據,將數據以適當的形式進行組裝,而後發送給存儲模塊。

存儲模塊:主要負責存儲生產者模塊發送過來的數據,而後將存儲的數據傳遞給消費者模塊。

該模塊須要解決如何序列化數據並存儲,以及如何讀取序列化的數據,該模塊的性能對消息隊列總體的性能影響較大。一方面,若是序列化及存儲性能很高,那麼接收數據的性能也會很高。另外一方面,若是讀取序列化數據的性能很高,那麼發送的性能也會很高,因此,該模塊決定了消息隊列的服務能力。

消費者模塊:主要負責消費存儲模塊的數據。

該模塊主要解決的是消費邏輯,好比:是廣播消費仍是集羣消費等,也能夠簡單理解是廣播仍是單播。

Config Server:主要做爲註冊中心,存儲組件的元數據,以及維護髮送和消費關係等。

各個模塊的實現

生產者模塊

1)接收上游系統產生的數據

2)使用適當的協議,解析數據包格式,組裝數據

3)容災

該部分須要處理的是大量的網絡鏈接請求和協議選擇

對於網絡模型的選擇,目前有select、poll和epoll等,這些模型各有優缺點和使用場景。

目前應用比較普遍的當屬epoll模型,基於事件驅動的方式,典型的好比Mina框架、Netty框架,兩者均是基於事件驅動,屬於非阻塞的異步傳輸模式。

目前Netty社區很成熟,版本更新迅速,在互聯網公司裏應用很普遍,能夠選擇Netty。對於協議的選擇,目前也有很是多的協議可供選擇,好比:ProtoBuf、JSON、Thrift、Hessian等。

對於具體如何選擇哪一種協議,主要應該考慮兩點:序列化/反序列化的時間和字節的大小。

對於網絡傳輸而言,固然是字節越小越好,可是越小的字節,可能會致使壓縮耗時過長,也就是若是壓縮的越小,解壓縮消耗的時間也越長,因此須要在這二者之間尋求一個平衡。

在容災方面,對於Producer而言,其發送消息可能有默認的優先級,好比,默認優先發送到本地機房集羣,本地機房宕機後再向其餘機房發送。本地機房故障後,自動熔斷。咱們能夠直接選擇使用Netty做爲網絡框架,至於協議,則能夠根據已有的業務場景選擇合適的協議。

存儲模塊:

該模塊是存儲模塊,爲了保證數據不丟失,必須作到高可用,爲此必須在存儲模塊考慮常見的異常狀況,如:系統Crash,機器斷電死機等。

最簡單的方式就是全部操做都是同步方式,同步的狀況下,即使出現異常,使用方還能夠嘗試重試策略。根據上面的介紹,它須要實現以下功能:

數據接收處理:生產者模塊接收的數據通過處理以後會傳遞給存儲模塊,由上面的描述可知,須要將該部分接收到數據按時間順序排序進行串行化,這樣能保持數據的入隊和出隊的一致性。

數據標識生成:簡單的說就是爲數據作好標識,相似數據記錄的主鍵,該標識的做用主要是便於存儲管理以及以後發送時的快速尋址。

數據寫入和讀取:該模塊主要是將上述帶標識的數據序列化到存儲設備,考慮到寫入的數據以後還要被讀取,最好爲寫入的數據建立索引,這樣在讀取的時候將能快速尋址,快速讀取數據。

消息隊列的性能瓶頸主要取決於寫入的性能,這個性能將決定消息隊列的性能。

理論上,從速度上講,文件系統最快,其次是分佈式KV系統,最後是數據庫,而可靠性正相反。具體選擇哪一種存儲設備,要根據業務場景來作出合理的選擇。

若是須要支持金融支付交易類等對可靠性要求很高的業務,那麼可能數據庫是比較好的選擇;若是是支持日誌類等對可靠性要求不是很高的場景,則能夠選擇分佈式KV,如MongoDB、Hbase 及Redis,性能比數據庫要好。

消費者模塊

須要實現廣播、單播等功能。

對於互聯網的大部分應用來講,組間廣播,組內單播是很是常見的情形。

消息須要通知到多個業務集羣,而一個集羣內有多臺機器,只要一臺機器消費這個消息就能夠,這種方式就是屬於組間廣播,組內單播模式

考慮這些常見的業務場景,通常比較通用的設計是支持組間廣播,不一樣的組註冊不一樣的訂閱,組內的不一樣機器,若是註冊一個相同的ID,則屬於集羣消費模式(單播);若是註冊不一樣的ID,則屬於廣播消費模式(廣播)。

消息隊列不管是queue模式仍是topic模式,其消費模式可歸納爲兩種:競爭式消費和共享式消費。

點對點消費、集羣消費屬於競爭式消費,廣播消費屬於共享式消費。

對於集羣消費模式,一條消息只要被集羣內的任意一個消費者消費便可,而對於多條消息,集羣內的消費者將共同分擔消費。好比有6條消息,集羣內有3個消費者,那麼可能每一個消費者都消費2條,也多是3個消費者分別消費1條、2條、3條,總共6條。通常來講,消息隊列應儘量作到負載均衡,保證集羣內的消費者儘量均衡消費;

對於廣播消費模式,一條消息須要被集羣內全部的消費者至少消費一次。

在消費者模塊中,當消息隊列須要將數據發送給消費者的時候,就涉及到數據是由消息隊列推送給消費者,仍是由消費者主動去拉取,兩種方式各有優缺點。

推模式

該模式的優勢很明顯,就是消費者能實時的接收最新的消息,缺點也很明顯,若是消費者的消費速度比發送者的速度慢,將形成消息在存儲服務器上的堆積。

此時,服務器將推送給消費者的消息,消費者可能沒法及時消費處理,形成消費者要麼拒絕,要麼拋出消費異常,雖然消息隊列能夠提供重試/重投遞,但卻會形成帶寬的浪費。

拉模式

拉模式是由消費者主動向服務器發請求獲取消息,因爲主動權在消費方,因此,消費者能夠主動控制消息消費的速度,避免消費者由於消費能力不足而致使的消費處理異常。另外一方面,該模式下,消費方可能沒法準確的肯定什麼時候去拉取最新的消息,由於消費方沒法準確的肯定什麼時候有最新的消息,也就沒法及時的去拉取。目前業界比較通用的作法是設定一個初始時間,而後以指數級時間增加去等待,但這樣仍然沒法保證能實時獲取最新消息。在阿里雲的消息隊列MNS中,其提供了一種長輪詢方案來優化。

具體作法是:在大併發的線程同時訪問隊列的狀況下,若是隊列裏沒有新的消息,那麼其實不須要那麼多線程同時去輪詢,只須要有一個線程去輪詢,其餘線程等待,當輪詢的線程發現隊列裏有新消息時,能夠喚醒其餘線程一塊兒來獲取消息,從而達到快速響應的目的。

轉自:http://mp.weixin.qq.com/s?__biz=MzI2MzY5Mzk3Nw==&mid=2247483781&idx=1&sn=d1ced17c3b5277c3bb440eabec2d3b36&chksm=eab6b273ddc13b659c7717d8c42de97dc0b75491fa5f7b90bc4df4464999ac31e01eff0a6567&mpshare=1&scene=23&srcid=0927r8StfS8AQUfz8emAbtPH#rd

相關文章
相關標籤/搜索