訊息佇列
RabbitMQ、RocketMQ、Kafka 區別?
RabbitMQ的延時最低,微秒級別,單機吞吐量不好,高可用為主從,請求可以請求從機,但是從機上并沒有訊息資料,需要根據從主機同步過來的queue配置資訊去主機上拉取過來回傳給請求端,
RocketMQ延時毫秒級別,吞吐量高,topic幾百到幾千時,吞吐量也不會下降太多,分布式架構可用性高,
Kafka延時毫秒以內級別,吞吐量高,topic幾十到幾百時,吞吐量下降很多,分布式架構,一個資料多份副本集,
為什么使用訊息佇列?
解耦:生產者沒必要去關心到底有哪些消費者需要消費,他可以將訊息寫入到mq中,有需要的對接系統自己來MQ中取就可以了
異步:如果一個功能處理起來耗時很長,這樣會給用戶很不好的體驗,所以可以將需要做的處理先寫入mq,成功寫入mq后,將成功的結果回傳給用戶,后續對mq中的訊息進行處理,
削峰:這個可以和異步結合起來理解,比如高并發場景下,大資料大流量直接訪問資料庫,會造成資料庫的壓力過大,這個時候我們就可以先將訊息寫入mq中,后續再進行資料的處理操作,
重復消費問題?
為什么會有重復消費問題?
比如Kafka,每個資料都會有一個offset來標記,類似序號,當訊息被消費者消費后,kafka會定時來提交offset,下次kafka重啟時,就會根據offset的標記順序來繼續提供訊息,但是系統宕機時,offset還沒提交,那么下次系統重啟時,就會產生一部分訊息的重復消費,
解決方法
保持冪等性就可以了,就是說比如訊息是需要向資料庫中添加資料,如果重復消費兩次了,但是你要保證資料庫里只有一條資料就可以,
結合業務考慮:
可以根據某些條件去查詢下庫里是否有這條資料了,如果有的話,就放棄處理,或者進行update處理,
如果是存盤redis的話,那就更好辦了,redis的set 天然冪等操作
更復雜的情況也可以在訊息中攜帶一個全域唯一性的ID,根據ID來進行是否重復消費的校驗操作,
訊息丟失問題
RabbitMQ
對于rabbitmq的話,生產者丟失訊息,沒有將訊息成功寫入MQ,這種情況的話,可以開啟rabbitmq帶的事務,也就是在生產者寫入訊息之前就開始事務,如果訊息沒有成功寫入MQ,MQ會回傳一個例外資訊,可以進行回滾,再重試發送訊息;成功寫入則提交事務,
還有一種類似ack應答機制,開啟confirm模式,生產者寫入rabbitmq都會有一個唯一性的ID,成功寫入MQ后,會回傳一個ack訊息,告訴你成功寫入了,如果寫入失敗,則會回呼nack介面,告訴你訊息失敗了,你可以選擇重試發送訊息,
上述兩種都是生產者訊息丟失,兩者的區別在于,事務是同步性的,如果卡在這里,就會一直卡下去,confirm模式則是異步的,
如果是mq本身自己訊息丟失怎么辦,這種情況的話,rabbitMQ可以開啟持久化,將資料持久化到磁盤,
如果是消費者弄丟訊息呢?回顧上面的confirm模式,我們可以關閉自動的ack回復,只有在消費者消費成功后,再手動的回復ack訊息給生產者,
Kafka
消費者成功獲取到了訊息,此時kafka提交了offset,但是消費者拿到后還沒來得及處理,就掛了,而kafka的offset也變了,所以這條訊息也就丟失了,解決辦法可以是關掉kafka的自動提交offset,只有當訊息成功消費后再手動提交offset,
kafka本身自己丟失訊息的情況,也就是leader資料還沒同步給follower的時候就掛了,這個時候重新從follower選舉出的leader或有資料的缺失,這種情況的解決辦法是通過更改配置引數
- 給 topic 設定
replication.factor引數:這個值必須大于 1,要求每個 partition 必須有至少 2 個副本, - 在 Kafka 服務端設定
min.insync.replicas引數:這個值必須大于 1,這個是要求一個 leader 至少感知到有至少一個 follower 還跟自己保持聯系,沒掉隊,這樣才能確保 leader 掛了還有一個 follower 吧, - 在 producer 端設定
acks=all:這個是要求每條資料,必須是寫入所有 replica 之后,才能認為是寫成功了, - 在 producer 端設定
retries=MAX(很大很大很大的一個值,無限次重試的意思):這個是要求一旦寫入失敗,就無限重試,卡在這里了,
生產者丟失資料的情況,只要在上面設定了acks=all就不會丟資料了,它保證必須寫入成功,不然就會重試,
訊息的有序性問題
保證訊息的有序性很重要,比如一條資料進行了刪增改操作,依次寫入了mq,但是如果消費者拿到然后消費順序是增改刪,那不就把資料洗掉了嗎
對于rabbit的話,可以多個queue佇列,每個佇列對應一個消費者;或者一個queue一個消費者,消費者內部自己維護一個記憶體佇列保證訊息的有序性,
對于kafka的話,可以單執行緒消費,一個topic,一個consumer,一個partition,但是吞吐量很低;可以多個queue,相同的key存入一個queue,然后多個消費者,每個執行緒只消費一個queue,這樣就可以多執行緒作業,提高吞吐量,
訊息堆積問題
如果訊息長時間沒有消費,產生了堆積怎么辦?這種場景可以使,消費者拉取到訊息后需要寫入到資料庫,但是如果此時資料庫掛了,消費端掛在這里不動了,那訊息就會慢慢積壓,
處理方法:擴容,新建一個topic,partition設定為之前的10倍大小,再建好之前10倍大小的queue,自己寫一個consumer消費者程式消費這些訊息,消費的操作就是將這些訊息輪詢均勻的寫入建好的10倍大小的queue,然后使用10倍的機器來部署消費者程式,每批機器消費一個queue,這相當于將消費者和queue都提高了10倍的效率,
對于RocketMQ,官方給出了訊息堆積的解決辦法:1.增加消費并行度,也就是增加消費者實體(超過訂閱的comsumer是無效的),2.rocketMQ支持批量消費,3.跳過不重要的訊息,實作就是更改offset,
訊息丟失
找個不重要的時間,一點一點自己查詢恢復吧,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/279231.html
標籤:其他
