1. 消息隊列
1.1 優缺點
答:總結爲:
優點:
- 解耦。系統生產消息後,直接給MQ不用關心其他事務。
- 異步。異步執行,提高吞吐量。發送者將消息發送給消息隊列後,不需要同步等待接收者處理完畢,而是可以進行其它操作。
- 削峯。請求在MQ中,Server根據處理能力處理消息,緩解服務器壓力。
缺點:
- 系統可用性降低。MQ掛了,整個系統通信GG。
- 系統複雜度增加。加入MQ,引出一致性、傳輸可靠性、消息不被重複消費等等問題。
- 一致性問題。A處理結束返回,BC寫庫成功,D失敗,數據不一致。
1.2 消息中間件
答:主要是ActiveMQ、RabbitMQ、RocketMQ和KafKa。
- ActiveMQ:老技術,現在用得不多。
- RabbitMQ:開源、社區活躍,中小型用這個。
- RocketMQ:阿里開發,和Dubbo RPC框架很像。
- Kafaka:專門做大數據。
1.3 MQ常見問題和解決思路
- 消息順序問題:讓消息按發送順序被消費。
- 解決方法:保證生產者-MQ-消費者,一一對應。合理設計規避。
- 缺陷問題:吞吐量不夠;耦合度太高。從業務層面保證消息順序。
- 消息重複問題:因爲網絡問題導致消費者收到兩條一樣的消息。
- 解決方法:保證冪等性,即不管多少重複消息,最後處理結果還是一樣。通過唯一編號標識消息或者日誌表記錄去重。
2. RabbitMQ
RabbitMQ是一款開源的、erLang編寫,基於AMQP(Advanced Message Queuing Protocol)的消息中間件。
2.1 基本概念
- Producer(生產者):生產消息的一方(郵件投遞者);
- Consumer(消費者):消費消息的一方(郵件收件人);
- Broker:MQ服務器實體,一般認爲一個Server就是一個Broker;
- Routing Key:路由鍵,指定消息的路由規則;
- Exchange:消息交換器,根據路由鍵把消息分發到隊列中;
- Queue:消息隊列容器,保存消息直到發送給消費者,每個消息可以投入到一個或多個隊列。;
- Binding:綁定,把exchange和queue按照路由規則綁定起來;
- VHost:理解爲虛擬broker(mini-RabbitMQ),擁有獨立的組件和權限系統,可以做到vhost範圍的用戶控制,所以一般應用於權限隔離。
- Channel:消息通道,在客戶端的每個連接裏,可建立多個channel,每個channel代表一個會話任務。
由Exchange、Queue、RoutingKey三個才能決定一個從Exchange到Queue的唯一的線路。
2.2 工作模式
2.2.1 Simple簡單收發
- 生產者生產消息,把消息放進隊列;
- 消費者監聽隊列消息,有就消費掉。
2.2.2 Work競爭資源
- 生產者生產消息,把消息放進隊列;
- 多個消費者監聽同一隊列,競爭消費,誰搶到誰就消費。
- 可能導致重複消費問題。
2.2.3 Publish/Subscribe共享資源
- 生產者將消息發給broker,由交換機轉發到隊列中;
- 每個消費者監聽自己的隊列。
2.2.4 routing路由模式
- 生產者將消息發給broker,指定路由規則,交換機根據路由key轉發到對於的消息隊列;
- 只有對應的消費者才能消費消息。
2.2.5 topic主題模式
- 基於路由模式的模糊匹配,*匹配多個單詞,#匹配一個單詞(類似sql的模糊查詢)
2.3 消息相關問題
2.3.1 消息順序性
答:通常可以用兩種方法:
- 拆分爲多個queue,queue和consumer一對一
- queue唯一consumer多個,consumer內部排隊分發
2.3.2 消息冪等性
答:解決思路就是,對消息做唯一標識,根據標識判斷是否被消費。
2.3.3 消息傳輸方式
答:RabbitMQ使用信道傳輸數據,信道基於TCP連接,但不受數量限制,一條TCP連接上信道能無上限。
2.3.4 消息確認模式
答:分爲兩種確認模式。
- 發送方確認模式
- 消息被分配唯一ID,當消息投遞到隊列後,信道發送ack給生產者,出錯就發送nack。
- 異步,在等待確認過程中仍能繼續發消息。
- 接收方確認模式
- 消費者每接收一條消息就確認一次。當消息被確認,才從隊列中刪除。
- 沒有超時機制。只要consumer連接不中斷,就認爲消費者一直在處理。
2.3.5 消息丟失
答:分爲三種情況。
- 生產者丟失消息
- transaction事務機制:把消息的發送作爲一個事務,過程中有異常就回滾,發送成功就提交。
- confirm模式:就是發送方消息確認模式。
- 消息隊列丟失消息
- 一般都是在開啓持久化時發生。
- 和confirm機制配合使用,在消息投遞隊列並持久化後,再返回ack。
- 消費者丟失消息
- 消費者接收消息後,處理消息前,回覆MQ已收到。這時異常會導致消息丟失。
- 修改爲手動確認消息。
2.3.6 消息積壓
答:處理方法是臨時擴容。將queue和consumer資源擴大10倍(申請10倍的空間建立queue和10倍的機器部署consumer),積壓消息消費完後,恢復原先架構。
2.3.7 消息失效
答:RabbitMQ能設置消息的TTL,一旦消息積壓過久到達TTL就會被自動清理。解決方案是手動批量重導,手動將丟失數據,查出來併發送到MQ中。
2.3.8 延遲隊列
消息/隊列 TTL + 死信隊列 DLX + Router轉發隊列
設置了TTL後,當消息在隊列中變成死信,就被轉發到其他隊列中。
2.4 集羣模式
答:RabbitMQ基於主從模式實現高可用,分爲普通集羣和鏡像集羣模式。
- 普通集羣模式
- 在多臺機器上啓動多個RabbitMQ實例。queue放在一個實例A上,但每個實例都同步queue的元數據。
- 消費時,若連接到另一個實例B,則實例B會從實例A上拉取數據。
總結:集羣的多個節點服務一個queue的讀寫操作。
- 鏡像集羣模式
- 每個RabbitMQ都有一個queue的完整鏡像。每次寫消息到queue時,自動把消息同步到多個實例上。
- 好處是單點宕機不怕,有備份。壞處是開銷大。
2.5 交換器類型
- fanout:把消息不做判斷全部放進隊列。用來廣播信息。
- direct:把消息放進路由完全匹配的隊列中。用來處理優先級任務。
- topic:路由模糊匹配。
- header:利用消息的header屬性進行匹配。基本不用。