消息中間件設(shè)計(jì)——解耦業(yè)務(wù)系統(tǒng)與核心系統(tǒng)
同步和異步
什么是同步迈套?什么是異步?
同步與異步指的是消息通信機(jī)制
同步 在發(fā)出一個(gè)調(diào)用后 沒有得到的結(jié)果之前,該調(diào)用不返回,即調(diào)用者主動(dòng)等待這個(gè)調(diào)用的結(jié)果岸浑。
異步 與同步相反,在調(diào)用發(fā)出后直接返回結(jié)果瑰步。即在一個(gè)異步調(diào)用發(fā)出后矢洲,調(diào)用者立刻去做其他事情。
為什么需要消息中間件缩焦?
業(yè)務(wù)系統(tǒng)和核心系統(tǒng)的交互比較頻繁读虏,系統(tǒng)之間耦合度太高。核心系統(tǒng)和業(yè)務(wù)系統(tǒng)有很多重復(fù)的開發(fā)工作袁滥。所以此時(shí)需要對(duì)它們進(jìn)行解耦掘譬,讓各個(gè)業(yè)務(wù)系統(tǒng)能健康的發(fā)展。
- 什么是消息中間件呻拌,有什么作用?
- 消息中間件就是一個(gè)開發(fā)好的系統(tǒng)睦焕,可以獨(dú)立部署藐握,業(yè)務(wù)系統(tǒng)通過它來發(fā)消息和收消息。以達(dá)到異步調(diào)用的效果垃喊。
- 消息中間件 可以提升系統(tǒng)性能猾普。
- 系統(tǒng)解耦
- 大流量消峰
生產(chǎn)級(jí)消息中間件的選型?
kafka的優(yōu)缺點(diǎn)
- 支持高吞吐量
- 性能較高
- 支持集群部署
- 有可能丟失數(shù)據(jù)
- 功能比較單一
RabbitMQ的優(yōu)缺點(diǎn)
- 能保證不丟失數(shù)據(jù)
- 能保證高可用
- 支持很多高級(jí)功能 如重試本谜、死信隊(duì)列初家。
- 吞吐量比較低
- 集群線性擴(kuò)展比較麻煩
- 開發(fā)語言是Erlang
RocketMq的優(yōu)缺點(diǎn)
- 吞吐量很高
- 能保證高可用、高性能
- 保證數(shù)據(jù)絕對(duì)不丟失
- 支持大規(guī)模集群部署乌助,線性擴(kuò)展方便
- 支持各種高級(jí)功能溜在,如延遲消息,消息回溯等
- 支持各種高級(jí)功能他托,如延遲消息掖肋,消息回溯等
- 基于Java語言的開發(fā),能滿足 國內(nèi)絕大部分公司技術(shù)棧赏参。
RocketMQ架構(gòu)原理
NameServer 和bROKER
NameServer是RocketMQ的路由中心志笼,主要提供管理沿盅、服務(wù)注冊(cè)及服務(wù)發(fā)現(xiàn)功能。
Broker是由RocketMQ的核心模塊纫溃,主要提供消息的接受腰涧、存儲(chǔ)和拉取等功能
如何保證高可用?
1.RocketMQ中的數(shù)據(jù)是分布式存儲(chǔ)在Broker中的紊浩,如果右節(jié)點(diǎn)宕機(jī)窖铡,那么RocketMQ是如何保證數(shù)據(jù)不丟失的呢?
- 采用多副本的方式郎楼,RocketMQ采用主從架構(gòu)及多副本策略万伤,來保證Broker數(shù)據(jù)的高可用
NameServer如何感知Broker的健康狀態(tài)。
- Broker在啟動(dòng)后會(huì)自動(dòng)向所有的NameServer急求你注冊(cè)呜袁,這樣所有的NameServer節(jié)點(diǎn)都知道了這個(gè)Broker敌买。業(yè)務(wù)系統(tǒng)可以通過Nameserver集群拉取Broker,從而進(jìn)行消息的發(fā)送/獲取阶界。
引入消息中間件會(huì)帶來什么問題虹钮?
利用消息中間件能解決系統(tǒng)的各種瓶頸問題,但也會(huì)提高系統(tǒng)的復(fù)雜度膘融,所以需要解決消息中間件自身的各種問題芙粱,這可能會(huì)導(dǎo)致降低系統(tǒng)的可用性及穩(wěn)定性。
RocketMQ的高可用方法
RocketMQ主要采用鏡像集群模式來保證高可用氧映,能夠百分之百保證數(shù)據(jù)不丟失春畔。與RabbitMQ的普通集群模式不同,在RabbitMQ的鏡像集群模式下岛都,所創(chuàng)建隊(duì)列queue中的消息及元數(shù)據(jù)都存在多個(gè)RabbitMQ實(shí)例上律姨。即在所有的RabbitMQ節(jié)點(diǎn)上都有這個(gè)queue的完整鏡像,在寫入消息時(shí)會(huì)將消息同步到多個(gè)mirror queue中臼疫。
優(yōu)點(diǎn): 在任何一臺(tái)機(jī)器宕機(jī)择份,其他機(jī)器還保留了queue的完整消息數(shù)據(jù),這樣Consumer就可以去其他好的節(jié)點(diǎn)上消費(fèi)信息烫堤。
缺點(diǎn): 性能開銷較大荣赶,因?yàn)橄⑿枰降剿泄?jié)點(diǎn),所有網(wǎng)絡(luò)傳輸消耗很大
kafka的高可用方案
kafka由多個(gè)Broker組成鸽斟,每個(gè)Broker就是一個(gè)節(jié)點(diǎn)拔创。一個(gè)Topic可用被劃分為多個(gè)Partition。Partition可用存在于不同的Broker節(jié)點(diǎn)上富蓄,每個(gè)Partition只存放一部分?jǐn)?shù)據(jù)伏蚊。
如何保證消息不被重復(fù)消費(fèi)?
要完全避免重復(fù)消費(fèi)消息是很難做到的格粪,因?yàn)榫W(wǎng)絡(luò)的抖動(dòng)躏吊、機(jī)器的宕機(jī)和處理的異常都是難以避免的氛改。
- 生產(chǎn)過程中 可用給每個(gè)生產(chǎn)者定義一個(gè)唯一的ID
- 給生產(chǎn)的每一條消息 定義一個(gè)唯一的ID
- 消息中間件服務(wù)端村消息時(shí),存儲(chǔ)生產(chǎn)者ID與最后一條消息ID映射比伏。如果在生產(chǎn)出一條新消息后胜卤,消息中間件服務(wù)端會(huì)先將消息ID與其存儲(chǔ)的最后一條消息ID進(jìn)行對(duì)比。如果相等 則是重復(fù)消息 赁项。如果不相等葛躏,則進(jìn)行存儲(chǔ)。
- 消費(fèi)過程中
- 給消息生成一個(gè)唯一的ID悠菜,在消息消費(fèi)后將數(shù)據(jù)ID存到數(shù)據(jù)庫中
- 在消費(fèi)下一條消息前舰攒,現(xiàn)在數(shù)據(jù)庫中查詢是否有這個(gè)消息ID,如果有則是重復(fù)消息悔醋,不處理摩窃。
如何保證消息的順序性?
在Topic中芬骄,一個(gè)Partition對(duì)應(yīng)一個(gè)Consumer猾愿,只能單線程消費(fèi)。對(duì)性能及并發(fā)要求稍微高的場(chǎng)景中就很不合適了账阻,因?yàn)閱尉€程吞吐量效率太低蒂秘。
- 在消費(fèi)端程序中寫多個(gè)內(nèi)存隊(duì)列
- 將相同key的消息數(shù)據(jù)放在同一個(gè)內(nèi)存隊(duì)列中
- 在多線程消費(fèi)時(shí),每個(gè)線程對(duì)一個(gè)內(nèi)存隊(duì)列進(jìn)行消費(fèi)
消息中間件中的消息延遲淘太?
- 監(jiān)控消息中間件中的消息延遲
- 開發(fā)消息監(jiān)控程序
- 減少消息中間中的消息延遲
- 優(yōu)化消費(fèi)代碼以提升性能
- 增加消費(fèi)者數(shù)量