你們好,我是小羽java
今天給你們帶來的的是關於小兔RabbitMQ的養成攻略,RabbitMQ
中的 Rabbit
是兔子的意思,就是形容跑的和兔子同樣快。是一款輕量級的,支持多種消息傳遞協議的高可用的消息隊列。RabbitMQ 是由 Erlang
語言編寫的,而 Erlang 語言就是一款天生適合高併發的語言。面試
是否是都對小兔很喜歡呢,可愛的小兔在咱們工做中但是扮演者大哥大的角色,說它是阿里如今的寵兒一點不爲過了。RabbitMQ 前面小兔我介紹過了,那麼MQ表明的是什麼意思呢?其實瞭解的都知道,Message Queue
的簡寫,用官方的話說 RabbitMQ 是一款開源的消息隊列系統。下面跟着小羽一塊兒來看看這隻小兔是如何養成的吧。spring
如今市場上主流的MQ有不少,好比 ActiveMQ、RabbitMQ、RocketMQ、Kafka、ZeroMQ
等。數據庫
阿里巴巴最初也是使用 ActiveMQ ,不過隨着業務的不斷髮展,ActiveMQ IO 模塊出現瓶頸,後來阿里巴巴經過一系列優化可是仍是不能很好的解決,以後阿里巴巴把注意力放到了主流消息中間件 kafka
上面,可是 kafka 並不能知足他們的要求,尤爲是低延遲和高可靠性。vim
因此 RobbitMQ 是站在巨人的肩膀上(kafka),又對其進行了優化讓其更知足互聯網公司的特色。安全
RabbitMQ 做爲一款很是流行的消息中間件,其有着很是豐富的特性和優點:高可靠性、路由靈活、集羣擴張性高、高可用、支持多種協議、支持多種客戶端和有着豐富的插件系統。springboot
RabbitMQ 目前在阿里集團被普遍應用於交易、充值、流計算、消息推送、日誌流式處理、binglog分發等場景。服務器
RabbitMQ 是一個由 Erlang 語言開發的 AMQP
的開源實現。網絡
AMQP :Advanced Message Queue,高級消息隊列協議。它是應用層協議的一個開放標準,爲面向消息的中間件設計,基於此協議的客戶端與消息中間件可傳遞消息,並不受產品、開發語言等條件的限制。架構
RabbitMQ 最初起源於金融系統,用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。
應用解耦
拿咱們常常說的訂單系統來舉例,通常都會訂單系統調用庫存系統的接口。以下:
這種處理方案會引起不少問題,當庫存系統沒法訪問,咱們訂單系統的減庫存就會失敗。
當咱們使用了消息隊列後,用戶下單後,訂單系統進行持久化處理,將消息寫入消息隊列,返回用戶訂單下單成功;訂閱下單的消息,採用拉/推的方式,獲取下單信息,庫存系統根據下單信息,進行庫存操做。
這樣的即便下單時庫存系統出現問題,也不影響正常下單,由於下單後,訂單系統已經寫入消息隊列,其餘操做就不關心了,實現訂單系統與庫存系統的應用解耦。
異步處理
拿咱們的用戶註冊來舉例,用戶註冊以後須要發註冊郵件和註冊短信。以下:
串行模式:
並行模式:
當咱們使用了消息隊列,就再也不是必須的業務邏輯,只需進行異步處理。以下:
流量削峯
拿咱們常常提到的秒殺來舉例,想必你們都經歷過天貓淘寶的雙11吧,當這個時候,咱們會在特定的那個時間,好比晚上凌晨0點的每秒需求會忽然增大,若是不進行系統結構升級,是經不起這麼多的請求的,直接會系統崩潰。
當咱們使用了消息隊列以後,在這個高峯期的時候,不少用戶進來,好比每秒有 5
千個請求,咱們只須要將這 5
千個請求放在消息隊列裏,系統每秒處理 2
千個請求,會從消息隊列里拉取出對應的數量,每秒只會處理這 2
千個請求。這樣在秒殺持續的這個時間段內,會有幾十萬或者更多的請求都放在消息隊列裏。由於畢竟秒殺只是會在短暫的那一段時間,等它過去以後,每秒可能就只有幾十,幾百個請求進入消息隊列。可是系統還會按照每秒 2
千個請求的速度去處理。因此,秒殺結束,系統會把那些剩下的消息都消費掉。
可靠性(Reliability):RabbitMQ 使用一些機制來保證可靠性,如持久化、傳輸確認、發佈確認。
靈活的路由(Flexible Routing):在消息進入隊列以前,經過 Exchange 來路由消息的。對於典型的路由功能,RabbitMQ 已經提供了一些內置的Exchange
來實現。針對更復雜的路由功能,能夠將多個 Exchange 綁定在一塊兒,也經過插件機制實現本身的 Exchange 。
消息集羣(Clustering):多個 RabbitMQ 服務器能夠組成一個集羣,造成一個邏輯 Broker
。
高可用(Highly Available Queues):隊列能夠在集羣中的機器上進行鏡像,使得在部分節點出問題的狀況下隊列仍然可用。
多種協議(Multi-protocol):RabbitMQ 支持多種消息隊列協議,好比 STOMP、MQTT
等等。
多語言客戶端(Many Clients):RabbitMQ 幾乎支持全部經常使用語言,好比 Java、.NET、Ruby
等等。
管理界面(Management UI):RabbitMQ 提供了一個易用的用戶界面,使得用戶能夠監控和管理消息 Broker 的許多方面。
跟蹤機制(Tracing):若是消息異常,RabbitMQ 提供了消息跟蹤機制,使用者能夠找出發生了什麼。
插件機制(Plugin System):RabbitMQ 提供了許多插件,來從多方面進行擴展,也能夠編寫本身的插件。
Message
消息,消息是不具名的,它由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括 routing-key
(路由鍵)、priority
(相對於其餘消息的優先權)、delivery-mode
(指出該消息可能須要持久性存儲)等。
Publisher
消息的生產者,也是一個向交換器發佈消息的客戶端應用程序。
Exchange
交換器,用來接收生產者發送的消息並將這些消息路由給服務器中的隊列。
Binding
綁定,用於消息隊列和交換器之間的關聯。一個綁定就是基於路由鍵將交換器和消息隊列鏈接起來的路由規則,因此能夠將交換器理解成一個由綁定構成的路由表。
Queue
隊列,是RabbitMQ的內部對象,用於存儲消息消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列裏面,等待消費者鏈接到這個隊列將其取走。
Connection
網絡鏈接,好比一個 TCP
鏈接。
Channel
信道,多路複用鏈接中的一條獨立的雙向數據流通道。信道是創建在真實的 TCP
鏈接內地虛擬鏈接,AMQP
命令都是經過信道發出去的,不論是發佈消息、訂閱隊列仍是接收消息,這些動做都是經過信道完成。由於對於操做系統來講創建和銷燬 TCP
都是很是昂貴的開銷,因此引入了信道的概念,以複用一條 TCP
鏈接。
Consumer
消息的消費者,表示一個從消息隊列中取得消息的客戶端應用程序。
Virtual Host
虛擬主機,表示一批交換器、消息隊列和相關對象。虛擬主機是共享相同的身份認證和加密環境的獨立服務器域。
Broker
表示消息隊列服務器實體。
Exchange 分發消息時根據類型的不一樣分發策略有區別,目前共四種類型:direct、fanout、topic、headers
。headers 匹配 AMQP
消息的 header
而不是路由鍵,此外 headers 交換器和direct 交換器徹底一致,但性能差不少,目前幾乎用不到了,因此直接看另外三種類型:
Direct 鍵分佈
Direct:消息中的路由鍵(routing key)若是和 Binding 中的 binding key
一致,交換器就將消息發到對應的隊列中。它是徹底匹配、單播的模式。
咱們以 routingKey=」error」 發送消息到 Exchange ,則消息會路由到 Queue1
(amqp.gen-S9b…,這是由RabbitMQ自動生成的Queue名稱)和 Queue2(amqp.gen-Agl…);若是咱們以 routingKey=」info」或routingKey=」warning」 來發送消息,則消息只會路由到 Queue2。若是咱們以其餘 routingKey 發送消息,則消息不會路由到這兩個 Queue 中。
Fanout
Fanout:每一個發到 fanout 類型交換器的消息都會分到全部綁定的隊列上去。很像子網廣播,每臺子網內的主機都得到了一份複製的消息。fanout 類型轉發消息是最快的。
生產者 Publisher 發送到 Exchange 的全部消息都會路由到圖中的兩個 Queue
,並最終被兩個消費者(Consumer1與Comsumer2)消費。
topic 交換器
topic 交換器:topic 交換器經過模式匹配分配消息的路由鍵屬性,將路由鍵和某個模式進行匹配,此時隊列須要綁定到一個模式上。它將路由鍵和綁定鍵的字符串切分成單詞,這些單詞之間用點隔開。它一樣也會識別兩個通配符:符號 「#
」 和符號 「」 。# 匹配 0
個或多個單詞,匹配很少很多一個單詞。
咱們 routingKey=」quick.orange.rabbit」 的消息會同時路由到Q1
與Q2
,routingKey=」lazy.orange.fox」 的消息會路由到Q1
,routingKey=」lazy.brown.fox」 的消息會路由到Q2
,routingKey=」lazy.pink.rabbit」 的消息會路由到Q2
(只會投遞給Q2一次,雖然這個 routingKey 與Q2
的兩個 bindingKey 都匹配);routingKey=」quick.brown.fox」、routingKey=」orange」、routingKey=」quick.orange.male.rabbit」 的消息將會被丟棄,由於它們沒有匹配任何 bindingKey
。
通常來講安裝 RabbitMQ 以前要安裝 Erlang
,能夠去 Erlang 官網下載。接着去 RabbitMQ 官網下載安裝包,以後解壓縮便可。根據操做系統不一樣官網提供了相應的安裝說明:Windows、Debian / Ubuntu、RPM-based Linux、Mac
下載地址
https://www.rabbitmq.com/releases/rabbitmq-server/
下載
wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.15/rabbitmq-server-generic-unix-3.6.15.tar.xz
安裝
tar -xvf rabbitmq-server-generic-unix-3.6.15.tar.xz
配置
vim /etc/profile
最後加上 export PATH=$PATH:/opt/rabbitmq/rabbitmq_server-3.6.15/sbin 根據本身的安裝路徑來
使修改生效
source /etc/profile
修改 hosts
vim/etc/hosts
啓動
cd /opt/rabbitmq/rabbitmq_server-3.6.15/sbin/
./rabbitmq-server -detached 注意需root用戶啓動
查看是否啓動成功
./rabbitmqctl status
出現這個就成功了,若是想遠程訪問
./rabbitmq-plugins enable rabbitmq_management
就能夠訪問了(非本機訪問請關閉防火牆)
訪問
springboot 集成 RabbitMQ 很是簡單,若是隻是簡單的使用配置很是少, springboot 提供了 spring-boot-starter-amqp
對消息各類支持。
配置 pom
文件,主要是添加 spring-boot-starter-amqp 的支持
代碼演示:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
配置 application.properties
文件,配置 rabbitmq 的安裝地址、端口以及帳戶信息
代碼演示:
spring.application.name=spirng-boot-rabbitmq spring.rabbitmq.host=127.0.0.1 spring.rabbitmq.port=5672 spring.rabbitmq.username=admin spring.rabbitmq.password=admin
配置隊列
代碼演示:
package com.zpc.rabbitmq import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration @Configuration public class RabbitConfig { @Bean public Queue queue() { return new Queue("q_hello"); } }
發送者
代碼演示:
package com.zpc.rabbitmq import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component import java.text.SimpleDateFormat; import java.util.Date @Component public class HelloSender { @Autowired private AmqpTemplate rabbitTemplate public void send() { String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//24小時制 String context = "hello " + date; System.out.println("Sender : " + context); //簡單對列的狀況下routingKey即爲Q名 this.rabbitTemplate.convertAndSend("q_hello", context); } }
接收者
代碼演示:
package com.zpc.rabbitmq import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component @Component @RabbitListener(queues = "q_hello") public class HelloReceiver @RabbitHandler public void process(String hello) { System.out.println("Receiver : " + hello); } }
測試
代碼演示:
package com.zpc.rabbitmq import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner @RunWith(SpringRunner.class) @SpringBootTest public class RabbitMqHelloTest @Autowired private HelloSender helloSender @Test public void hello() throws Exception { helloSender.send(); } }
RabbitMQ 最爲出色的功能之一就是內建集羣,這個功能設計的目的是容許消費者和生產者在節點崩潰的狀況下繼續運行,以及經過添加更多的節點來線性擴展消息通訊吞吐量。RabbitMQ 內部利用 Erlang 提供的分佈式通訊框架 OTP
來知足上述需求,使客戶端在失去一個 RabbitMQ 節點鏈接的狀況下,仍是可以從新鏈接到集羣中的任何其餘節點繼續生產、消費消息。
RabbitMQ 集羣中經常使用概念:
隊列元數據:包括隊列名稱和它們的屬性,好比是否可持久化,是否自動刪除
交換器元數據:交換器名稱、類型、屬性
綁定元數據:內部是一張表格記錄如何將消息路由到隊列
vhost 元數據:爲 vhost 內部的隊列、交換器、綁定提供命名空間和安全屬性
在咱們平時開發中對各類消息隊列 MQ 選型的思考:
若是用戶訪問量在 ActiveMQ 的可承受範圍內,並且確實主要是基於解耦和異步來用的,能夠考慮 ActiveMQ
,也比較貼近 Java 工程師的使用習慣,可是ActiveMQ 如今中止維護了,同時ActiveMQ 併發不高,因此業務量必定的狀況下能夠考慮使用。
RabbitMQ 做爲一個純正血統的消息中間件,有着高級消息協議 AMQP
的完美結合,在消息中間件中地位無可取代,可是 erlang 語言阻止了咱們去深刻研究和掌控,對公司而言,底層技術沒法控制,可是確實是開源的,有比較穩定的支持,活躍度也高。
對本身公司技術實力有絕對自信的,能夠用 RocketMQ
,可是 RocketMQ 誕生比較晚,而且更新迭代很快,這個意味着在使用過程當中有可能會遇到不少坑,因此若是大家公司 Java 技術不是很強,不推薦使用。
中小型公司,技術實力較爲通常,技術挑戰不是特別高,用 ActiveMQ、RabbitMQ
是不錯的選擇;大型公司,基礎架構研發實力較強,用 RocketMQ
是很好的選擇
若是是大數據領域的實時計算、日誌採集等場景,用 Kafka
是業內標準的,絕對沒問題,社區活躍度很高,幾乎是全世界這個領域的事實性規範。
從性能上來看,使用文件系統的消息中間件(Kafka、RokcetMq)性能是最好的,因此基於文件系統存儲的消息中間件是發展趨勢。(從存儲方式和效率來看文件系統>KV存儲>關係型數據庫)
消息隊列呢,其實都大同小異,用法基本都是同樣的,只是各個開源消息隊列的側重點稍有不一樣,咱們應該根據咱們本身的項目需求來決定咱們應該選取什麼樣的消息隊列來爲咱們的項目服務,這個項目選型的工做通常都是研發前期,組長就已經決定好了用哪一個來作,通常是輪不到咱們來作的,可是面試的時候可能會考察相關知識,因此這幾種消息隊列咱們都應該對其瞭解並能靈活使用。