想使用訊息佇列,先考慮下這些問題!
原創:Java派(微信公眾號:Java派),歡迎分享,轉載請保留出處。
訊息佇列優勢
訊息佇列(Message Queue,簡稱MQ),其主要用於在複雜的微服務系統中進行訊息通訊,它的優點可以大致整理成以下幾點:
- 服務間解耦
- 提高服務併發、效能
- 突發流量削峰
- ...
服務間解耦
微服務系統業務之間相互依賴,各種呼叫錯綜複雜,如果不能良好對服務進行解耦那一個服務的可用性、併發都會受到其他服務的影響。
在沒有引用MQ的之前服務呼叫大概是這些步驟:
圖上的A服務是直接呼叫的,這是沒啥問題的,但是服務上線後要迭代更新的麻,這個時候要是服務C的開發人員有點程式碼小潔癖說:我這個C服務介面命名不太好,我需要重新更新下,當A服務的小哥哥還戴著小耳機聽著小歌曲,突然就得改程式碼了~~。
後來負責服務C的那小哥哥也不好意思了,提出大家一起使用MQ吧,於是A、C的呼叫就變成下面這個樣子了:
服務A不直接呼叫C而是向訊息佇列中傳送訊息(生產者),另一邊的C取出佇列中的訊息(消費者)進行處理,這樣A、C就完成了解耦。
提高服務併發、效能
舉個例子,在沒引入MQ之前服務呼叫多個服務都是同步呼叫,比如像這樣:
服務A要順序的呼叫B、C服務來完成業務邏輯如果A->B
需要200ms,A->C
需要200ms,再加上自身業務邏輯處理可能需要花費500ms,其中有400ms是呼叫A和B的花費,明明自身100ms就能處理完還白白浪費400ms,不能忍啊於是可以引入MQ做一下改造:
這下有了MQ,A服務只需要發一條訊息比如花費50ms,再加上自身業務邏輯的100ms,那整個呼叫過程只需要花費150ms了,這樣對併發和效能都有一定的改善。
突發流量削峰
突發流量就是網際網路很常見的情況,有時候有熱點、突發事件,那平常QPS為100的介面,突然提升10-20倍這個時候沒有MQ所有流量直接進入服務,這對服務和資料庫都是很大的挑戰:
再次引入MQ就情況就不一樣了,服務A先將請求丟給MQ,然後可以慢慢消費掉:
訊息佇列帶來的一些問題
使用MQ還有很多好處,但是他也會帶一些麻煩事。首先就是會降低系統的可用性,比如MQ掛了怎麼辦呢?所以在引入MQ之前就需要考慮之後帶來的哪些問題,不能只看它的好處也需要考慮它不好的地方。比如下面列出的這些問題要如果解決:
- 如何保證訊息佇列的高可用?
- 如何保證訊息不被重複消費?
- 如何保證訊息不丟失?
- 如何保證訊息的消費順序?
下面我們來分析下這些問題。
如何保證訊息佇列的高可用?
如果是單機訊息佇列,一臺機器掛了訊息佇列都就不用了,這是不能接受的,如果是一個訊息佇列群集,一臺機器掛了還有其他機器能正常提供服務,所以要保證訊息佇列的高可用,我們就需要做訊息佇列叢集。
以RabbitMQ為例它有兩種叢集模式:
- 普通模式
- 映象模式
普通模式
普通模式,RabbitMQ會同步各個節點的資料/狀態,但不包括訊息佇列
,預設情況下,訊息佇列駐留在一個節點上,儘管它們在所有節點上都是可見且可訪問的。
在這種模式下,每個節點都有會所有節點的元資料資訊,所以當傳送訊息到佇列時,無論連線的是哪一個節點都能正確的傳送,但是節點只會同步其他節點的元資料,訊息佇列的資料還是在一個節點上,如果這個節點掛了那就意味著發訊息就會失敗,無法保證訊息佇列的高可用。
映象模式
預設情況下,RabbitMQ中Queue與Binding、Exchange不一樣,它只會存於宣告佇列的節點中,但是可以選擇使Queue跨多個節點進行映象。
每一個映象佇列由一個Master和一個或多個映象組成,任何佇列的的操作,都會先應用到Master節點上然後傳播到多個映象節點。如果Master節點掛了,最老的映象節點將會成為新的Master節點。
總結
RabbitMQ有兩種叢集方法:普通模式
、映象模式
,要實現訊息佇列的高可用可以選一種合適的叢集方式來達到,關於RabbitMQ的叢集搭建方式,由於篇幅有限這裡就不多說,可自行檢視 Distributed RabbitMQ文章。
如何保證訊息不被重複消費?
想象下消費者收到重複的訊息會發生什麼情況,比如訂單支付訊息,如果支付服務收到兩條重複的訊息讓使用者去支付兩次,那使用者肯定是不願意的,明明已經支付過了還要支付。
如上圖中第四步消費訊息B的時候失敗了,如果支付服務在做完業務之後,傳送ACK之前服務掛了,MQ沒有收到ACK,由於訊息還存在佇列中,服務恢復正常後會再次收到訊息,如果支付不做檢查那使用者就會發生兩次支付。
要避免這個重複消費的問題,可以在消費端引入記憶體、Redis、資料庫來儲存訊息消費記錄,根據訊息Id來判斷訊息是否已經被消費過。
如何保證訊息不丟失?
假設有訂單服務和支付服務,正常流程是使用者下單成功,然後向支付服務傳送支付訊息,這裡面就涉及訂單服務、支付服務、MQ的互動了,訊息丟失可以分為三種情況:
- 生產者訊息丟失
- MQ訊息丟失
- 消費者訊息丟失
生產者訊息丟失
生產者訊息丟失,可以使用本地訊息表解決、訊息確認/重發等方式來解決。以RabbitMQ為例,它有confirm
機制,發出去的訊息是否入佇列,會使用回撥的形式告知生產者,生產者收到訊息後判斷是Ack
還是Nak
,如果是Nak
則重發訊息。
此時還會有問題,如果極端情況下訂單服務掛了,再次重啟後訊息就真丟失了,所以最好還是在生產中對訊息做持久化,待訂單服務恢復後使用Job重新發送訊息。
MQ訊息丟失
MQ訊息丟失一般為未開啟持久化,MQ掛了再次重啟後訊息丟失,所以應當將訊息持久化到磁碟中。如果MQ收到訊息後在同步到磁碟之前MQ掛了,那磁碟中也沒有訊息,這樣還是會導致訊息丟失訊息,不過這只是小概率事件。
消費者訊息丟失
消費者訊息丟失,大都為開啟了autoAck
選項,消費者收到訊息後還未完成處理,此時服務掛了,由於開啟了autoAck
, MQ會以為此訊息已經被成功消費,將訊息從佇列中移除,而服務恢復過後也不會收到原來的訊息了。
如果保證訊息的消費順序?
有些場景下要保持訊息的順序消費怎麼辦?比如寫Log都是一條條打印出來,如果發到訊息佇列後出現消費順序不一致那訊息的那日誌就會亂掉,給看日誌的人帶來不必要的麻煩。比如為了加快日誌的處理速度使用三個消費都處理日誌:
按圖上的流程,消費者A、B、C可能分別消費日誌1、2、3,這時候就無法保證訊息的處理順序。要保證訊息的消費順序,首先讓訊息都發送到同一個佇列,然後使用一個消費者去處理訊息:
這樣訊息的處理速度就大大降低,要保持訊息的順序,則又想讓訊息的處理速度不至於太慢,可以引用本地佇列:
相關推薦
想使用訊息佇列,先考慮下這些問題!
原創:Java派(微信公眾號:Java派),歡迎分享,轉載請保留出處。 訊息佇列優勢 訊息佇列(Message Queue,簡稱MQ),其主要用於在複雜的微服務系統中進行訊息通訊,它的優點可以大致整理成以下幾點: 服務間解耦 提高服務併發、效能 突發流量削峰 ... 服務間解耦 微服務系統業務之間相互
很多人很想知道怎麼掃一掃二維碼就能開啟網站,就能新增聯絡人,就能連結wifi,今天說下這些格式,明天做個demo
有些功能部分手機不能使用,網站,通訊錄,wifi基本上每個手機都可以使用。 在看之前你可以掃一掃下面幾個二維碼先看看效果: 1.二維碼生成 網址 (URL) 包含網址的 二維碼生成 是大家平時最常接觸到的(例如:http://dnt.dkill.net),二維碼識別軟體能夠通過 http:/
成為大數據頂尖程序員,先過了這些Hadoop面試題!(附答案解析)
大禮包 雲計 default blank mas 阻止 launcher inpu 建立 導讀:在大數據開發崗位的需求下,工資待遇水漲船高,不少編程人員在面對職業瓶頸期的時候,會選擇轉編程方向發展。你是否已經意識這是你人生中的一個重要轉機?能不能抓住這個時代的機遇,就在於你
訊息佇列,不懂你就Out啦!
為什麼要懂訊息佇列 在程式設計師的工作和學習中,如果是比較成熟的專案,基本上都會涉及到分散式啊、訊息佇列啊、高併發啊、高可用啊、高效能啊、快取啊等各種相對來說比較高階的技術點。 關於訊息佇列,這個東西是大家一定要懂的,不懂行不行?如果對技術有追求,還是得好好研究下,最好在專案中用到
如果你想學習程式設計,不妨嘗試下JAVA?
一.JAVA是什麼? Java是一種可以撰寫跨平臺應用程式的面向物件的程式設計語言。Java 技術具有卓越的通用性、高效性、平臺移植性和安全性,廣泛應用於PC、資料中心、遊戲控制檯、科學超級計算機、行動電話和網際網路,同時擁有全球最大的開發者專業社群。 二.什麼樣的人適合學習JAV
Linux:程序間通訊(匿名管道命名管道)(共享記憶體,訊息佇列,訊號量)
目錄 程序間通訊的介紹 管道 匿名管道 原理: 程式碼實現 匿名管道特性 實現管道符 | 命名管道 命名管道特性 程式碼實現 管道讀寫規則 作業系統中ipc的相關命令 共享記憶體(重點) 生命週期: 程式碼實現 程式碼實現獲
Windows訊息佇列、執行緒訊息佇列,視窗訊息的概念與關係
1.視窗 Windows程式是由一系列的視窗構成的,每個視窗都有自己的視窗過程,視窗過程就是一個擁有有固定 Signature 的 C函式,具體格式如下: LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wPa
為什麼需要訊息佇列,及使用訊息佇列的好處?
一、訊息佇列的特性 業務無關,一個具有普適性質的訊息佇列元件不需要考慮上層的業務模型,只做好訊息的分發就可以了,上層業務的不同模組反而需要依賴訊息佇列所定義的規範進行通訊。 FIFO,先投遞先到達的保證是一個訊息佇列和一個buffer的本質區別。 容災,對於普適
嵌入式Linux併發程式設計,程序間通訊方式,System V IPC,訊息佇列,開啟/建立msgget(), 傳送訊息msgsnd(),格式,接收訊息msgrcv(),控制訊息佇列 msgctl()
文章目錄 1,訊息佇列 2,訊息佇列結構 3,訊息佇列使用步驟 3.1,開啟/建立訊息佇列 msgget() 3.1.1,開啟/建立訊息佇列---示例msgget() 3.2,向訊息佇列傳送訊息 msgs
想做好app測試,只需要做好這些!
測試人員常被看作bug尋找者,但你曾想過他們實際是如何開展測試的嗎?你是否好奇他們究竟都做些什麼,以及他們如何在一個典型的技術專案中體現價值? 作者將帶你經歷測試人員的思維過程,探討他們測試移動app時的各種考慮。本文的目的在於揭示測試人員的這一思維過程,並展示他們通常所考慮內容
boost程序間通訊常用開發一篇全(訊息佇列,共享記憶體,訊號)
本文概要: 敏捷開發大家想必知道而且評價甚高,縮短開發週期,提高開發質量。將大工程獨立為不同的小app開發,整個開發過程,程式可用可測,所以提高了整體的質量。基於這種開發模式和開發理念,程序間通訊必然是童鞋們必掌握技能之一了,而boost庫是眾多庫中平臺支援
springboot整合rabbitmq,根據查詢的資訊建立多個訊息中心和訊息佇列,並實現不同的訊息傳送到不同的訊息中心
今天接到一個需求,就是在傳送訊息到rabbitmq訊息中心的時候,需要根據裝置型別,將訊息傳送到不同的訊息佇列,因此要建立不同的訊息佇列。 修改之前是把配置資訊寫在配置文中,專案啟動時,獲取配置檔案中的配置資訊,建立訊息佇列。 修改後的邏輯
Linux程序間通訊--訊號,管道,訊息佇列,訊號量,共享記憶體,socket
Linux 傳統的程序間通訊有很多,如各類管道、訊息佇列、記憶體共享、訊號量等等。但它們都無法介於核心態與使用者態使用,原因如表 通訊方法 無法介於核心態與使用者態的原因 管道(不包括命名管道) 侷限於父子程序間的通訊。 訊息佇列 在硬、軟中斷中無法無阻塞地接收資料。 訊號量 無法介於核
程序間通訊——管道,訊息佇列,共享記憶體
程序間通訊的本質是讓兩個不相干的程序看到同一份資源。這個資源是由作業系統提供的一個檔案。程序間通訊的目的:1.資料傳輸:一個程序需要將它 的資料傳送給另一個程序。2.資源共享:多個程序之間共享同樣的資源。3.通知事件:一個程序需要向另一個(組)程序傳送訊息,通知它們發生了
建立一個訊息佇列,OSQCreate()
程式清單 L6.21是OSQCreate()函式的原始碼。該函式需要一個指標陣列來容納指向各個訊息的指標。該指標陣列必須聲名為void型別。 OSQCreate()首先從空閒事件控制塊連結串列中取得一個事件控制塊(見圖F6.3)[L6.21(1)],並對剩下的空閒事件控制塊
Java程式猿想超神,我來回答這些問題(java基礎)
1、例項方法和靜態方法有什麼不一樣? 例項方法是物件方法,由物件呼叫,在使用使用時方法才會被載入進記憶體 靜態方法是在類被載入是被載入進記憶體,由類名直接進行呼叫 所以在靜態的方法中只可以呼叫靜態的方法或成員,因為靜態方法的載入時間早於物件建立,所以在靜態
Linux:使用多執行緒程式設計和訊息佇列,實現兩個程序之間的聊天
思路: 一個檔案:建立一個執行緒和主函式,或者建立兩個執行緒主函式呼叫(我用這種)。 建立兩個訊息佇列, 一共兩個檔案,兩個佇列,四個程序 a.c 一個程序寫(訊息型別為1) ---->>佇列 一個程序讀(訊息型別為2) b.c 一
管道,訊息佇列,共享記憶體之間的區別和聯絡
程序間通訊的目的: 資料傳輸:一個程序需要將它的資料傳送給另一個程序,傳送的資料量在一個位元組到幾兆位元組之間。 共享資料:多個程序想要操作共享資料,一個程序對共享資料的修改,別的程序應該立刻看到。 通知事件:一
Android Studio:想要事半功倍,你需要記住這些快捷鍵
恩,我這個人有個癖好,就是愛收集各種快捷鍵,office,ps一類的快捷鍵收集了好多。原因嘛,還是那句話,工欲善其事,必先利其器。能有事半功倍的辦法,何樂而不為呢? 我這裡只是總結一下經常會
資料庫雜記篇(MySql,個人觀點,不一定正確,先寫下自己研究的,接下來再不斷補充)
僅代表個人觀點,並不一定正確。 支援技術分享,轉載或複製,請指出文章來源 此部落格