至于為什么叫做削峰填谷呢?來看看這個圖:

如果沒有用MQ的情況下,并發量高峰期的時候是有一個“頂峰”的,然后高峰期過后又是一個低并發的“谷”,
但是使用了MQ之后,限制消費訊息的速度為1000,但是這樣一來,高峰期產生的資料勢必會被積壓在MQ中,高峰就被“削”掉了,
但是因為訊息積壓,在高峰期過后的一段時間內,消費訊息的速度還是會維持在1000QPS,直到消費完積壓的訊息,這就叫做“填谷”
通過上面的分析,大家就可以知道為什么要使用MQ,以及使用了MQ有什么好處,知其所以然,明白了自己的系統為什么要使用MQ,
這樣以后別人問你為啥要用MQ,就不會出現 “我們組長要用MQ我們就用了” 這樣尷尬的回答了,
使用了MQ之后有什么優缺點?
看到這個問題蒙圈了,用了就用了嘛!優點上面已經說了,但是這個缺點是啥啊,好像沒啥缺點啊,
如果你這樣想,就大錯特錯了,在設計系統的程序中,除了要清楚的知道為什么要用這個東西,還要思考一下用了之后有什么壞處,這樣才能心里有底,防范于未然,
接下來我們就討論一下,用MQ會有什么缺點把?
系統可用性降低
大家想想一下,上面的說解耦的場景,本來A系統的哥們要把系統關鍵資料發送給BC系統的,現在突然加入了一個MQ了,現在BC系統接收資料要通過MQ來接收,
但是大家有沒有考慮過一個問題,萬一MQ掛了怎么辦?這就引出一個問題,加入了MQ之后,系統的可用性是不是就降低了?
因為多了一個風險因素:MQ可能會掛掉,只要MQ掛了,資料沒了,系統運行就不對了,
系統復雜度提高
本來我的系統通過介面呼叫一下就能完事的,但是加入一個MQ之后,需要考慮訊息重復消費、訊息丟失、甚至訊息順序性的問題
為了解決這些問題,又需要引入很多復雜的機制,這樣一來是不是系統的復雜度提高了,
資料一致性問題
本來好好的,A系統呼叫BC系統介面,如果BC系統出錯了,會拋出例外,回傳給A系統讓A系統知道,這樣的話就可以做回滾操作了
但是使用了MQ之后,A系統發送完訊息就完事了,認為成功了,而剛好C系統寫資料庫的時候失敗了,但是A認為C已經成功了?這樣一來資料就不一致了,
通過分析引入MQ的優缺點之后,就明白了使用MQ有很多優點,但是會發現它帶來的缺點又會需要你做各種額外的系統設計來彌補
最后你可能會發現整個系統復雜了好幾倍,所以設計系統的時候要基于這些考慮做出取舍,很多時候你會發現該用的還是要用的,,,
怎么保證MQ訊息不丟失?
使用了MQ之后,還要關心訊息丟失的問題,這里我們挑RabbitMQ來說明一下吧,
生產者弄丟了資料
RabbitMQ生產者將資料發送到rabbitmq的時候,可能資料在網路傳輸中搞丟了,這個時候RabbitMQ收不到訊息,訊息就丟了,
RabbitMQ提供了兩種方式來解決這個問題:
事務方式:
在生產者發送訊息之前,通過channel.txSelect開啟一個事務,接著發送訊息
如果訊息沒有成功被RabbitMQ接收到,生產者會收到例外,此時就可以進行事務回滾channel.txRollback然后重新發送,假如RabbitMQ收到了這個訊息,就可以提交事務channel.txCommit,
但是這樣一來,生產者的吞吐量和性能都會降低很多,現在一般不這么干,
另外一種方式就是通過confirm機制:
這個confirm模式是在生產者哪里設定的,就是每次寫訊息的時候會分配一個唯一的id,然后RabbitMQ收到之后會回傳一個ack,告訴生產者這個訊息ok了,
如果rabbitmq沒有處理到這個訊息,那么就回呼一個nack的介面,這個時候生產者就可以重發,
事務機制和cnofirm機制最大的不同在于事務機制是同步的,提交一個事務之后會阻塞在那兒
但是confirm機制是異步的,發送一個訊息之后就可以發送下一個訊息,然后那個訊息rabbitmq接收了之后會異步回呼你一個介面通知你這個訊息接收到了,
所以一般在生產者這塊避免資料丟失,都是用confirm機制的,
Rabbitmq弄丟了資料
RabbitMQ集群也會弄丟訊息,這個問題在官方檔案的教程中也提到過,就是說在訊息發送到RabbitMQ之后,默認是沒有落地磁盤的,萬一RabbitMQ宕機了,這個時候訊息就丟失了,
所以為了解決這個問題,RabbitMQ提供了一個持久化的機制,訊息寫入之后會持久化到磁盤
這樣哪怕是宕機了,恢復之后也會自動恢復之前存盤的資料,這樣的機制可以確保訊息不會丟失,
設定持久化有兩個步驟:
第一個是創建queue的時候將其設定為持久化的,這樣就可以保證rabbitmq持久化queue的元資料,但是不會持久化queue里的資料
第二個是發送訊息的時候將訊息的deliveryMode設定為2,就是將訊息設定為持久化的,此時rabbitmq就會將訊息持久化到磁盤上去,
但是這樣一來可能會有人說:萬一訊息發送到RabbitMQ之后,還沒來得及持久化到磁盤就掛掉了,資料也丟失了,怎么辦?
對于這個問題,其實是配合上面的confirm機制一起來保證的,就是在訊息持久化到磁盤之后才會給生產者發送ack訊息,
萬一真的遇到了那種極端的情況,生產者是可以感知到的,此時生產者可以通過重試發送訊息給別的RabbitMQ節點
消費端弄丟了資料
RabbitMQ消費端弄丟了資料的情況是這樣的:在消費訊息的時候,剛拿到訊息,結果行程掛了,這個時候RabbitMQ就會認為你已經消費成功了,這條資料就丟了,
對于這個問題,要先說明一下RabbitMQ消費訊息的機制:在消費者收到訊息的時候,會發送一個ack給RabbitMQ,告訴RabbitMQ這條訊息被消費到了,這樣RabbitMQ就會把訊息洗掉,
但是默認情況下這個發送ack的操作是自動提交的,也就是說消費者一收到這個訊息就會自動回傳ack給RabbitMQ,所以會出現丟訊息的問題,
所以針對這個問題的解決方案就是:關閉RabbitMQ消費者的自動提交ack,在消費者處理完這條訊息之后再手動提交ack,
這樣即使遇到了上面的情況,RabbitMQ也不會把這條訊息洗掉,會在你程式重啟之后,重新下發這條訊息過來,
怎么保證MQ的高可用性性?
使用了MQ之后,我們肯定是希望MQ有高可用特性,因為不可能接受機器宕機了,就無法收發訊息的情況,
這一塊我們也是基于RabbitMQ這種經典的MQ來說明一下:
RabbitMQ是比較有代表性的,因為是基于主從做高可用性的,我們就以他為例子講解第一種MQ的高可用性怎么實作,
rabbitmq有三種模式:單機模式,普通集群模式,鏡像集群模式
單機模式
單機模式就是demo級別的,就是說只有一臺機器部署了一個RabbitMQ程式,
這個會存在單點問題,宕機就玩完了,沒什么高可用性可言,一般就是你本地啟動了玩玩兒的,沒人生產用單機模式,
普通集群模式
這個模式的意思就是在多臺機器上啟動多個rabbitmq實體,類似的master-slave模式一樣,
更多:Java進階核心知識集
包含:JVM,JAVA集合,網路,JAVA多執行緒并發,JAVA基礎,Spring原理,微服務,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,設計模式,負載均衡,資料庫,一致性哈希,JAVA演算法,資料結構,加密演算法,分布式快取等等

**[CodeChina開源專案:【一線大廠Java面試題決議+核心總結學習筆記+最新講解視頻】](
)
網盤:pan.baidu.com/s/1MtPP4d9Xy3qb7zrF4N8Qpg
提取碼:2p8n
**
高效學習視頻
ka,RabbitMQ,Hbase,MongoDB,Cassandra,設計模式,負載均衡,資料庫,一致性哈希,JAVA演算法,資料結構,加密演算法,分布式快取等等
[外鏈圖片轉存中…(img-AqrdQjQu-1631366949316)]
**[CodeChina開源專案:【一線大廠Java面試題決議+核心總結學習筆記+最新講解視頻】](
)
網盤:pan.baidu.com/s/1MtPP4d9Xy3qb7zrF4N8Qpg
提取碼:2p8n
**
高效學習視頻
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299624.html
標籤:其他
上一篇:程式員提升學歷有必要嗎?
