“RabbitMQ?”“Kafka?”“RocketMQ?”...在日常學(xué)習(xí)與開發(fā)過程中,我們常常聽到消息隊(duì)列這個(gè)關(guān)鍵詞。
“RabbitMQ?”“Kafka?”“RocketMQ?”...在日常學(xué)習(xí)與開發(fā)過程中,我們常常聽到消息隊(duì)列這個(gè)關(guān)鍵詞。
現(xiàn)在只要是稍大的平臺(tái)都要考慮大數(shù)據(jù)高并發(fā)的問題、集群的問題、
負(fù)載均衡的問題;那么消息隊(duì)列在解決這類問題上占著舉足輕重的地位;比方說小伙伴們常常使用的火車票購(gòu)票軟件
12306就使用到了消息隊(duì)列;所以消息隊(duì)列的學(xué)習(xí)和掌握是作為一個(gè)高級(jí)開發(fā)者必備的技能了。
如果你是老手,你可能從本文學(xué)到你之前不曾注意的一些關(guān)于消息隊(duì)列的重要概念,如果你是新手,相信本文將是你打開消息隊(duì)列大門的一板磚。
什么是消息隊(duì)列
“消息隊(duì)列”是在消息的傳輸過程中保存消息的容器。
當(dāng)一大批客戶端同時(shí)產(chǎn)生大量的網(wǎng)絡(luò)請(qǐng)求(消息)時(shí)候,服務(wù)器的承受能力肯定是有一個(gè)限制的。這時(shí)候要是有個(gè)容器,先讓這些消息排隊(duì)就好了,還好有個(gè)叫隊(duì)列的數(shù)據(jù)結(jié)構(gòu),通過有隊(duì)列屬性的容器排隊(duì)(先進(jìn)先出),把消息再傳到我們的服務(wù)器,壓力減小了好多,這個(gè)很棒的容器就是消息隊(duì)列。
消息隊(duì)列優(yōu)勢(shì)
· 應(yīng)用解耦
消息隊(duì)列可以使消費(fèi)者和生產(chǎn)者直接互不干涉,互不影響,只需要把消息發(fā)送到隊(duì)列即可,而且可獨(dú)立的擴(kuò)展或修改兩邊的處理過程,只要能確保它們遵守同樣的接口約定,可以生產(chǎn)者用Node.js實(shí)現(xiàn),消費(fèi)者用python實(shí)現(xiàn)。
· 靈活性和峰值處理能力
當(dāng)客戶端訪問量突然劇增,對(duì)服務(wù)器的訪問已經(jīng)超過服務(wù)所能處理的最大峰值,甚至導(dǎo)致服務(wù)器超時(shí)負(fù)載崩潰,使用消息隊(duì)列可以解決這個(gè)問題,可以通過控制消費(fèi)者的處理速度和生產(chǎn)者可進(jìn)入消息隊(duì)列的數(shù)量等來避免峰值問題排序保證消息隊(duì)列可以控制數(shù)據(jù)處理的順序,因?yàn)橄㈥?duì)列本身使用的是隊(duì)列這個(gè)數(shù)據(jù)結(jié)構(gòu),FIFO(先進(jìn)選出),在一些場(chǎng)景數(shù)據(jù)處理的順序很重要,比如商品下單順序等。
· 異步通信
消息隊(duì)列中的有些消息,并不需要立即處理,消息隊(duì)列提供了異步處理機(jī)制,可以把消息放在隊(duì)列中并不立即處理,需要的時(shí)候處理,或者異步慢慢處理,一些不重要的發(fā)送短信和郵箱功能可以使用。
· 可擴(kuò)展性
前面提到了消息隊(duì)列可以做到解耦,如果我們想增強(qiáng)消息入隊(duì)和出隊(duì)的處理頻率,很簡(jiǎn)單,并不需要改變代碼中任何內(nèi)容,可以直接對(duì)消息隊(duì)列修改一些配置即可,比如我們想限制每次發(fā)送給消費(fèi)者的消息條數(shù)等。
RabbitMQ 特點(diǎn)
· RabbitMQ 是一個(gè)由 Erlang 語言開發(fā)的 AMQP 的開源實(shí)現(xiàn)。
· AMQP :Advanced Message Queue,高級(jí)消息隊(duì)列協(xié)議。它是應(yīng)用層協(xié)議的一個(gè)開放標(biāo)準(zhǔn),為面向消息的中間件設(shè)計(jì),基于此協(xié)議的客戶端與消息中間件可傳遞消息,并不受產(chǎn)品、開發(fā)語言等條件的限制。
· RabbitMQ 最初起源于金融系統(tǒng),用于在分布式系統(tǒng)中存儲(chǔ)轉(zhuǎn)發(fā)消息,在易用性、擴(kuò)展性、高可用性等方面表現(xiàn)不俗。具體特點(diǎn)包括:
· 可靠性(Reliability)RabbitMQ 使用一些機(jī)制來保證可靠性,如持久化、傳輸確認(rèn)、發(fā)布確認(rèn)。
· 靈活的路由(Flexible Routing)在消息進(jìn)入隊(duì)列之前,通過 Exchange 來路由消息的。對(duì)于典型的路由功能,RabbitMQ 已經(jīng)提供了一些內(nèi)置的 Exchange 來實(shí)現(xiàn)。針對(duì)更復(fù)雜的路由功能,可以將多個(gè) Exchange 綁定在一起,也通過插件機(jī)制實(shí)現(xiàn)自己的 Exchange 。
· 消息集群(Clustering)多個(gè) RabbitMQ 服務(wù)器可以組成一個(gè)集群,形成一個(gè)邏輯 Broker 。
· 高可用(Highly Available Queues)隊(duì)列可以在集群中的機(jī)器上進(jìn)行鏡像,使得在部分節(jié)點(diǎn)出問題的情況下隊(duì)列仍然可用。
· 多種協(xié)議(Multi-protocol)RabbitMQ 支持多種消息隊(duì)列協(xié)議,比如 STOMP、MQTT 等等。
· 多語言客戶端(Many Clients)RabbitMQ 幾乎支持所有常用語言,比如 Java、.NET、Ruby 等等。
· 管理界面(Management UI)RabbitMQ 提供了一個(gè)易用的用戶界面,使得用戶可以監(jiān)控和管理消息 Broker 的許多方面。
· 跟蹤機(jī)制(Tracing)如果消息異常,RabbitMQ 提供了消息跟蹤機(jī)制,使用者可以找出發(fā)生了什么。
· 插件機(jī)制(Plugin System)RabbitMQ 提供了許多插件,來從多方面進(jìn)行擴(kuò)展,也可以編寫自己的插件。
RabbitMQ 中的概念
· 消息模型
所有 MQ 產(chǎn)品從模型抽象上來說都是一樣的過程:消費(fèi)者(consumer)訂閱某個(gè)隊(duì)列。生產(chǎn)者(producer)創(chuàng)建消息,然后發(fā)布到隊(duì)列(queue)中,最后將消息發(fā)送到監(jiān)聽的消費(fèi)者。
· RabbitMQ 基本概念
上面只是最簡(jiǎn)單抽象的描述,具體到 RabbitMQ 則有更詳細(xì)的概念需要解釋。上面介紹過 RabbitMQ 是 AMQP 協(xié)議的一個(gè)開源實(shí)現(xiàn),所以其內(nèi)部實(shí)際上也是 AMQP 中的基本概念:
· Message消息,消息是不具名的,它由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對(duì)于其他消息的優(yōu)先權(quán))、delivery-mode(指出該消息可能需要持久性存儲(chǔ))等。
· Publisher消息的生產(chǎn)者,也是一個(gè)向交換器發(fā)布消息的客戶端應(yīng)用程序。
· Exchange交換器,用來接收生產(chǎn)者發(fā)送的消息并將這些消息路由給服務(wù)器中的隊(duì)列。
· Binding綁定,用于消息隊(duì)列和交換器之間的關(guān)聯(lián)。一個(gè)綁定就是基于路由鍵將交換器和消息隊(duì)列連接起來的路由規(guī)則,所以可以將交換器理解成一個(gè)由綁定構(gòu)成的路由表。
· Queue消息隊(duì)列,用來保存消息直到發(fā)送給消費(fèi)者。它是消息的容器,也是消息的終點(diǎn)。一個(gè)消息可投入一個(gè)或多個(gè)隊(duì)列。消息一直在隊(duì)列里面,等待消費(fèi)者連接到這個(gè)隊(duì)列將其取走。
· Connection網(wǎng)絡(luò)連接,比如一個(gè)TCP連接。
· Channel信道,多路復(fù)用連接中的一條獨(dú)立的雙向數(shù)據(jù)流通道。信道是建立在真實(shí)的TCP連接內(nèi)的虛擬連接,AMQP 命令都是通過信道發(fā)出去的,不管是發(fā)布消息、訂閱隊(duì)列還是接收消息,這些動(dòng)作都是通過信道完成。因?yàn)閷?duì)于操作系統(tǒng)來說建立和銷毀 TCP 都是非常昂貴的開銷,所以引入了信道的概念,以復(fù)用一條 TCP 連接。
· Consumer消息的消費(fèi)者,表示一個(gè)從消息隊(duì)列中取得消息的客戶端應(yīng)用程序。
· Virtual Host虛
擬主機(jī),表示一批交換器、消息隊(duì)列和相關(guān)對(duì)象。
虛擬主機(jī)是共享相同的身份認(rèn)證和加密環(huán)境的
獨(dú)立服務(wù)器域。每個(gè)
vhost 本質(zhì)上就是一個(gè) mini 版的 RabbitMQ 服務(wù)器,擁有自己的隊(duì)列、交換器、綁定和權(quán)限機(jī)制。vhost 是 AMQP 概念的基礎(chǔ),必須在連接時(shí)指定,RabbitMQ 默認(rèn)的 vhost 是 / 。
· Broker表示消息隊(duì)列服務(wù)器實(shí)體。
AMQP 中的消息路由
· AMQP 中消息的路由過程和 Java 開發(fā)者熟悉的 JMS 存在一些差別,AMQP 中增加了 Exchange 和 Binding 的角色。生產(chǎn)者把消息發(fā)布到 Exchange 上,消息最終到達(dá)隊(duì)列并被消費(fèi)者接收,而 Binding 決定交換器的消息應(yīng)該發(fā)送到那個(gè)隊(duì)列。
AMQP 的消息路由過程
· Exchange 類型
· Exchange分發(fā)消息時(shí)根據(jù)類型的不同分發(fā)策略有區(qū)別,目前共四種類型:direct、fanout、topic、headers 。headers 匹配 AMQP 消息的 header 而不是路由鍵,此外 headers 交換器和 direct 交換器完全一致,但性能差很多,目前幾乎用不到了,所以直接看另外三種類型:
· directdirect 交換器消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致,交換器就將消息發(fā)到對(duì)應(yīng)的隊(duì)列中。路由鍵與隊(duì)列名完全匹配,如果一個(gè)隊(duì)列綁定到交換機(jī)要求路由鍵為“dog”,則只轉(zhuǎn)發(fā) routing key 標(biāo)記為“dog”的消息,不會(huì)轉(zhuǎn)發(fā)“dog.puppy”,也不會(huì)轉(zhuǎn)發(fā)“dog.guard”等等。它是完全匹配、單播的模式。
· fanoutfanout 交換器每個(gè)發(fā)到 fanout 類型交換器的消息都會(huì)分到所有綁定的隊(duì)列上去。fanout 交換器不處理路由鍵,只是簡(jiǎn)單的將隊(duì)列綁定到交換器上,每個(gè)發(fā)送到交換器的消息都會(huì)被轉(zhuǎn)發(fā)到與該交換器綁定的所有隊(duì)列上。很像子網(wǎng)廣播,每臺(tái)子網(wǎng)內(nèi)的主機(jī)都獲得了一份復(fù)制的消息。fanout 類型轉(zhuǎn)發(fā)消息是最快的。
· topictopic 交換器topic 交換器通過模式匹配分配消息的路由鍵屬性,將路由鍵和某個(gè)模式進(jìn)行匹配,此時(shí)隊(duì)列需要綁定到一個(gè)模式上。它將路由鍵和綁定鍵的字符串切分成單詞,這些單詞之間用點(diǎn)隔開。它同樣也會(huì)識(shí)別兩個(gè)通配符:符號(hào)“#”和符號(hào)“”。#匹配0個(gè)或多個(gè)單詞,匹配不多不少一個(gè)單詞。
RabbitMQ 安裝
· 一般來說安裝 RabbitMQ 之前要安裝 Erlang ,可以去Erlang官網(wǎng)下載。接著去RabbitMQ官網(wǎng)下載安裝包,之后解壓縮即可。根據(jù)操作系統(tǒng)不同官網(wǎng)提供了相應(yīng)的安裝說明:Windows、Debian / Ubuntu、RPM-based Linux、Mac
· 如果是Mac 用戶,個(gè)人推薦使用 HomeBrew 來安裝,安裝前要先更新 brew:
· brew update
· 接著安裝 rabbitmq 服務(wù)器:
· brew install rabbitmq
· 這樣 RabbitMQ 就安裝好了,安裝過程中會(huì)自動(dòng)其所依賴的 Erlang 。