消息中間件的應(yīng)用場(chǎng)景
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
作者 | wusier
來源 | urlify.cn/M3MRJn
提高系統(tǒng)性能首先考慮的是數(shù)據(jù)庫的優(yōu)化,但是數(shù)據(jù)庫因?yàn)闅v史原因,橫向擴(kuò)展是一件非常復(fù)雜的工程,所有我們一般會(huì)盡量把流量都擋在數(shù)據(jù)庫之前。
不管是無限的橫向擴(kuò)展服務(wù)器,還是縱向阻隔到達(dá)數(shù)據(jù)庫的流量,都是這個(gè)思路。阻隔直達(dá)數(shù)據(jù)庫的流量,緩存組件和消息組件是兩大殺器。這里就重點(diǎn)說說MQ的應(yīng)用場(chǎng)景。
MQ簡(jiǎn)介
MQ:Message queue,消息隊(duì)列,就是指保存消息的一個(gè)容器。具體的定義這里就不類似于數(shù)據(jù)庫、緩存等,用來保存數(shù)據(jù)的。當(dāng)然,與數(shù)據(jù)庫、緩存等產(chǎn)品比較,也有自己一些特點(diǎn),具體的特點(diǎn)后文會(huì)做詳細(xì)的介紹。
現(xiàn)在常用的MQ組件有activeMQ、rabbitMQ、rocketMQ、zeroMQ,當(dāng)然近年來火熱的kafka,從某些場(chǎng)景來說,也是MQ,當(dāng)然kafka的功能更加強(qiáng)大,雖然不同的MQ都有自己的特點(diǎn)和優(yōu)勢(shì),但是,不管是哪種MQ,都有MQ本身自帶的一些特點(diǎn),下面,咱們就先聊聊MQ的特點(diǎn)。
MQ特點(diǎn)
(1)先進(jìn)先出
不能先進(jìn)先出,都不能說是隊(duì)列了。消息隊(duì)列的順序在入隊(duì)的時(shí)候就基本已經(jīng)確定了,一般是不需人工干預(yù)的。而且,最重要的是,數(shù)據(jù)是只有一條數(shù)據(jù)在使用中。 這也是MQ在諸多場(chǎng)景被使用的原因。
(2)發(fā)布訂閱
發(fā)布訂閱是一種很高效的處理方式,如果不發(fā)生阻塞,基本可以當(dāng)做是同步操作。這種處理方式能非常有效的提升服務(wù)器利用率,這樣的應(yīng)用場(chǎng)景非常廣泛。
(3)持久化
持久化確保MQ的使用不只是一個(gè)部分場(chǎng)景的輔助工具,而是讓MQ能像數(shù)據(jù)庫一樣存儲(chǔ)核心的數(shù)據(jù)。
(4)分布式
在現(xiàn)在大流量、大數(shù)據(jù)的使用場(chǎng)景下,只支持單體應(yīng)用的服務(wù)器軟件基本是無法使用的,支持分布式的部署,才能被廣泛使用。而且,MQ的定位就是一個(gè)高性能的中間件。
應(yīng)用場(chǎng)景
消息隊(duì)列中間件是分布式系統(tǒng)中重要的組件,主要解決應(yīng)用解耦,異步消息,流量削鋒等問題,實(shí)現(xiàn)高性能,高可用,可伸縮和最終一致性架構(gòu)。目前使用較多的消息隊(duì)列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ
消息中間件監(jiān)控
Activemq 監(jiān)控
Rabbitmq 監(jiān)控
Kafka 監(jiān)控
異步處理
場(chǎng)景說明:用戶注冊(cè)后,需要發(fā)注冊(cè)郵件和注冊(cè)短信。傳統(tǒng)的做法有兩種 1.串行的方式;2.并行方式
a、串行方式:將注冊(cè)信息寫入數(shù)據(jù)庫成功后,發(fā)送注冊(cè)郵件,再發(fā)送注冊(cè)短信。以上三個(gè)任務(wù)全部完成后,返回給客戶端。

b、并行方式:將注冊(cè)信息寫入數(shù)據(jù)庫成功后,發(fā)送注冊(cè)郵件的同時(shí),發(fā)送注冊(cè)短信。以上三個(gè)任務(wù)完成后,返回給客戶端。與串行的差別是,并行的方式可以提高處理的時(shí)間

假設(shè)三個(gè)業(yè)務(wù)節(jié)點(diǎn)每個(gè)使用50毫秒鐘,不考慮網(wǎng)絡(luò)等其他開銷,則串行方式的時(shí)間是150毫秒,并行的時(shí)間可能是100毫秒。
因?yàn)镃PU在單位時(shí)間內(nèi)處理的請(qǐng)求數(shù)是一定的,假設(shè)CPU1秒內(nèi)吞吐量是100次。則串行方式1秒內(nèi)CPU可處理的請(qǐng)求量是7次(1000/150)。并行方式處理的請(qǐng)求量是10次(1000/100)
小結(jié):如以上案例描述,傳統(tǒng)的方式系統(tǒng)的性能(并發(fā)量,吞吐量,響應(yīng)時(shí)間)會(huì)有瓶頸。如何解決這個(gè)問題呢?
引入消息隊(duì)列,將不是必須的業(yè)務(wù)邏輯,異步處理。改造后的架構(gòu)如下:

按照以上約定,用戶的響應(yīng)時(shí)間相當(dāng)于是注冊(cè)信息寫入數(shù)據(jù)庫的時(shí)間,也就是50毫秒。注冊(cè)郵件,發(fā)送短信寫入消息隊(duì)列后,直接返回,因此寫入消息隊(duì)列的速度很快,基本可以忽略,因此用戶的響應(yīng)時(shí)間可能是50毫秒。因此架構(gòu)改變后,系統(tǒng)的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了兩倍。
應(yīng)用解耦
場(chǎng)景說明:用戶下單后,訂單系統(tǒng)需要通知庫存系統(tǒng)。傳統(tǒng)的做法是,訂單系統(tǒng)調(diào)用庫存系統(tǒng)的接口。如下圖:

傳統(tǒng)模式的缺點(diǎn):假如庫存系統(tǒng)無法訪問,則訂單減庫存將失敗,從而導(dǎo)致訂單失敗,訂單系統(tǒng)與庫存系統(tǒng)耦合
如何解決以上問題呢?引入應(yīng)用消息隊(duì)列后的方案,如下圖:
訂單系統(tǒng):用戶下單后,訂單系統(tǒng)完成持久化處理,將消息寫入消息隊(duì)列,返回用戶訂單下單成功
庫存系統(tǒng):訂閱下單的消息,采用拉/推的方式,獲取下單信息,庫存系統(tǒng)根據(jù)下單信息,進(jìn)行庫存操作
假如:在下單時(shí)庫存系統(tǒng)不能正常使用。也不影響正常下單,因?yàn)橄聠魏螅唵蜗到y(tǒng)寫入消息隊(duì)列就不再關(guān)心其他的后續(xù)操作了。實(shí)現(xiàn)訂單系統(tǒng)與庫存系統(tǒng)的應(yīng)用解耦
流量削峰
流量削鋒也是消息隊(duì)列中的常用場(chǎng)景,一般在秒殺或團(tuán)搶活動(dòng)中使用廣泛。
應(yīng)用場(chǎng)景:秒殺活動(dòng),一般會(huì)因?yàn)榱髁窟^大,導(dǎo)致流量暴增,應(yīng)用掛掉。為解決這個(gè)問題,一般需要在應(yīng)用前端加入消息隊(duì)列。
a、可以控制活動(dòng)的人數(shù)
b、可以緩解短時(shí)間內(nèi)高流量壓垮應(yīng)用

用戶的請(qǐng)求,服務(wù)器接收后,首先寫入消息隊(duì)列。假如消息隊(duì)列長(zhǎng)度超過最大數(shù)量,則直接拋棄用戶請(qǐng)求或跳轉(zhuǎn)到錯(cuò)誤頁面。
秒殺業(yè)務(wù)根據(jù)消息隊(duì)列中的請(qǐng)求信息,再做后續(xù)處理。
消息通訊
消息通訊是指,消息隊(duì)列一般都內(nèi)置了高效的通信機(jī)制,因此也可以用在純的消息通訊。比如實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)消息隊(duì)列,或者聊天室等。
點(diǎn)對(duì)點(diǎn)通訊:

客戶端A和客戶端B使用同一隊(duì)列,進(jìn)行消息通訊。
聊天室通訊:

客戶端A,客戶端B,客戶端N訂閱同一主題,進(jìn)行消息發(fā)布和接收。實(shí)現(xiàn)類似聊天室效果。
以上實(shí)際是消息隊(duì)列的兩種消息模式,點(diǎn)對(duì)點(diǎn)或發(fā)布訂閱模式。模型為示意圖,供參考。
具體例子可以參考官網(wǎng):https://www.rabbitmq.com/web-stomp.html
海量數(shù)據(jù)同步(日志)
日志處理是指將消息隊(duì)列用在日志處理中,比如Kafka的應(yīng)用,解決大量日志傳輸?shù)膯栴}。架構(gòu)簡(jiǎn)化如下

日志采集客戶端,負(fù)責(zé)日志數(shù)據(jù)采集,定時(shí)寫受寫入Kafka隊(duì)列
Kafka消息隊(duì)列,負(fù)責(zé)日志數(shù)據(jù)的接收,存儲(chǔ)和轉(zhuǎn)發(fā)
日志處理應(yīng)用:訂閱并消費(fèi)kafka隊(duì)列中的日志數(shù)據(jù)
eg:日志收集系統(tǒng)

分為Zookeeper注冊(cè)中心,日志收集客戶端,Kafka集群和Storm集群(OtherApp)四部分組成。
Zookeeper注冊(cè)中心,提出負(fù)載均衡和地址查找服務(wù)
日志收集客戶端,用于采集應(yīng)用系統(tǒng)的日志,并將數(shù)據(jù)推送到kafka隊(duì)列
Kafka集群:接收,路由,存儲(chǔ),轉(zhuǎn)發(fā)等消息處理
Storm集群:與OtherApp處于同一級(jí)別,采用拉的方式消費(fèi)隊(duì)列中的數(shù)據(jù)
網(wǎng)易使用案例:
網(wǎng)易NDC-DTS系統(tǒng)在使用,應(yīng)該是最典型的應(yīng)用場(chǎng)景,主要就是binlog的同步,數(shù)據(jù)表的主從復(fù)制。簡(jiǎn)單一點(diǎn)就是:MySQL進(jìn)程寫binlog文件 -> 同步應(yīng)用去實(shí)時(shí)監(jiān)控binlog文件讀取發(fā)送到Kafka -> 目標(biāo)端處理binlog 。原理上與阿里開源的canal, 點(diǎn)評(píng)的puma大同小異。
任務(wù)調(diào)度
參考延時(shí)隊(duì)列
分布式事物
分布式事務(wù)有強(qiáng)一致,弱一致,和最終一致性這三種:
強(qiáng)一致:
當(dāng)更新操作完成之后,任何多個(gè)后續(xù)進(jìn)程或者線程的訪問都會(huì)返回最新的更新過的值。這種是對(duì)用戶最友好的,就是用戶上一次寫什么,下一次就保證能讀到什么。根據(jù) CAP 理論,這種實(shí)現(xiàn)需要犧牲可用性。
弱一致:
系統(tǒng)并不保證續(xù)進(jìn)程或者線程的訪問都會(huì)返回最新的更新過的值。系統(tǒng)在數(shù)據(jù)寫入成功之后,不承諾立即可以讀到最新寫入的值,也不會(huì)具體的承諾多久之后可以讀到。
最終一致:
弱一致性的特定形式。系統(tǒng)保證在沒有后續(xù)更新的前提下,系統(tǒng)最終返回上一次更新操作的值。在沒有故障發(fā)生的前提下,不一致窗口的時(shí)間主要受通信延遲,系統(tǒng)負(fù)載和復(fù)制副本的個(gè)數(shù)影響。DNS 是一個(gè)典型的最終一致性系統(tǒng)。
在分布式系統(tǒng)中,同時(shí)滿足“CAP定律”中的“一致性”、“可用性”和“分區(qū)容錯(cuò)性”三者是幾乎不可能的。在互聯(lián)網(wǎng)領(lǐng)域的絕大多數(shù)的場(chǎng)景,都需要犧牲強(qiáng)一致性來換取系統(tǒng)的高可用性,系統(tǒng)往往只需要保證“最終一致性”,只要這個(gè)最終時(shí)間是在用戶可以接受的范圍內(nèi)即可,這時(shí)候我們只需要用短暫的數(shù)據(jù)不一致就可以達(dá)到我們想要效果。
實(shí)例描述
比如有訂單,庫存兩個(gè)數(shù)據(jù),一個(gè)下單過程簡(jiǎn)化為,加一個(gè)訂單,減一個(gè)庫存。而訂單和庫存是獨(dú)立的服務(wù),那怎么保證數(shù)據(jù)一致性。
這時(shí)候我們需要思考一下,怎么保證兩個(gè)遠(yuǎn)程調(diào)用“同時(shí)成功”,數(shù)據(jù)一致?
請(qǐng)大家先注意一點(diǎn)遠(yuǎn)程調(diào)用最郁悶的地方就是,結(jié)果有3種,成功、失敗和超時(shí)。超時(shí)的話,成功失敗都有可能。
一般的解決方案,大多數(shù)的做法是借助mq來做最終一致。
如何實(shí)現(xiàn)最終一致
我們是怎么利用Mq來達(dá)到最終一致的呢?
首先,拿我們上面提到的訂單業(yè)務(wù)舉例:
在我們進(jìn)行加訂單的過程中同時(shí)插入logA(這個(gè)過程是可以做本地事務(wù)的)
然后可以異步讀取logA,發(fā)mqA
B端接收mqA,同時(shí)減少庫存,B這里需要做冪等(避免因?yàn)橹貜?fù)消息造成的業(yè)務(wù)錯(cuò)亂)
那么我們通過上面的分析可能聯(lián)想到這樣的問題?
本地先執(zhí)行事務(wù),執(zhí)行成功了就發(fā)個(gè)消息過去,消費(fèi)端拿到消息執(zhí)行自己的事務(wù)
比如a,b,c,a異步調(diào)用b,c如果b失敗了,或者b成功,或者b超時(shí),那么怎么用mq讓他們最終一致呢?b失敗就失敗了,b成功之后給c發(fā)一個(gè)消息,b和c對(duì)a來講都是異步的,且他們都是同時(shí)進(jìn)行的話,而且需要a,b,c同時(shí)成功的情況,那么這種情況用mq怎么做?
其實(shí)做法還是參照于本地事務(wù)的概念的。
第一種情況:假設(shè)a,b,c三者都正常執(zhí)行,那整個(gè)業(yè)務(wù)正常結(jié)束
第二種情況:假設(shè)b超時(shí),那么需要a給b重發(fā)消息(記得b服務(wù)要做冪等),如果出現(xiàn)重發(fā)失敗的話,需要看情況,是終端服務(wù),還是繼續(xù)重發(fā),甚至人為干預(yù)(所有的規(guī)則制定都需要根據(jù)業(yè)務(wù)規(guī)則來定)
第三種情況:假設(shè)a,b,c三者之中的一個(gè)失敗了,失敗的服務(wù)利用MQ給其他的服務(wù)發(fā)送消息,其他的服務(wù)接收消息,查詢本地事務(wù)記錄日志,如果本地也失敗,刪除收到的消息(表示消息消費(fèi)成功),如果本地成功的話,則需要調(diào)用補(bǔ)償接口進(jìn)行補(bǔ)償(需要每個(gè)服務(wù)都提供業(yè)務(wù)補(bǔ)償接口)。
注意事項(xiàng):
mq這里有個(gè)坑,通常只適用于只允許第一個(gè)操作失敗的場(chǎng)景,也就是第一個(gè)成功之后必須保證后面的操作在業(yè)務(wù)上沒障礙,不然后面失敗了前面不好回滾,只允許系統(tǒng)異常的失敗,不允許業(yè)務(wù)上的失敗,通常業(yè)務(wù)上失敗一次后面基本上也不太可能成功了,要是因?yàn)榫W(wǎng)絡(luò)或宕機(jī)引起的失敗可以通過重試解決,如果業(yè)務(wù)異常,那就只能發(fā)消息給a和c讓他們做補(bǔ)償了吧?通常是通過第三方進(jìn)行補(bǔ)償,ABC提供補(bǔ)償接口,設(shè)計(jì)范式里通常不允許消費(fèi)下游業(yè)務(wù)失敗。
怎么理解呢,舉個(gè)例子:
比如A給B轉(zhuǎn)賬,A先自己扣錢,然后發(fā)了個(gè)消息,B這邊如果在這之前銷戶了,那重試多少次也沒用,只能人工干預(yù)。
網(wǎng)易在分布式事務(wù)采用的解決方式
網(wǎng)易部分業(yè)務(wù)是用MQ實(shí)現(xiàn)了最終一致性,目前教育產(chǎn)品,例如:網(wǎng)易云課堂。
也有一部分業(yè)務(wù)用了TCC事務(wù),但是TCC事務(wù)用的比較少,因?yàn)闀?huì)侵染業(yè)務(wù),開發(fā)成本比較高,如果體量不大的話直接用JPA或MQ支持事務(wù)就好。
網(wǎng)易的產(chǎn)品中使用分布式事務(wù)基于技術(shù)
TCC,F(xiàn)MT(Framework-managed transactions),事務(wù)消息都有。
開源產(chǎn)品myth:https://gitee.com/shuaiqiyu/myth
常用消息隊(duì)列(ActiveMQ、RabbitMQ、RocketMQ、Kafka)比較
特性MQ | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
生產(chǎn)者消費(fèi)者模式 | 支持 | 支持 | 支持 | 支持 |
發(fā)布訂閱模式 | 支持 | 支持 | 支持 | 支持 |
請(qǐng)求回應(yīng)模式 | 支持 | 支持 | 不支持 | 不支持 |
Api完備性 | 高 | 高 | 高 | 高 |
多語言支持 | 支持 | 支持 | java | 支持 |
單機(jī)吞吐量 | 萬級(jí) | 萬級(jí) | 萬級(jí) | 十萬級(jí) |
消息延遲 | 無 | 微秒級(jí) | 毫秒級(jí) | 毫秒級(jí) |
可用性 | 高(主從) | 高(主從) | 非常高(分布式) | 非常高(分布式) |
消息丟失 | 低 | 低 | 理論上不會(huì)丟失 | 理論上不會(huì)丟失 |
文檔的完備性 | 高 | 高 | 教高 | 高 |
提供快速入門 | 有 | 有 | 有 | 有 |
社區(qū)活躍度 | 高 | 高 | 中 | 高 |
商業(yè)支持 | 無 | 無 | 商業(yè)云 | 商業(yè)云 |
ActiveMQ 歷史悠久的開源項(xiàng)目,已經(jīng)在很多產(chǎn)品中得到應(yīng)用,實(shí)現(xiàn)了JMS1.1規(guī)范,可以和spring-jms輕松融合,實(shí)現(xiàn)了多種協(xié)議,不夠輕巧(源代碼比RocketMQ多),支持持久化到數(shù)據(jù)庫,對(duì)隊(duì)列數(shù)較多的情況支持不好。總體來說:
RabbitMQ 它比Kafka成熟,支持AMQP事務(wù)處理,在可靠性上,RabbitMQ超過Kafka,在性能方面超過ActiveMQ。
RocketMQ RocketMQ是阿里開源的消息中間件,目前在Apache孵化,使用純Java開發(fā),具有高吞吐量、高可用性、適合大規(guī)模分布式系統(tǒng)應(yīng)用的特點(diǎn)。RocketMQ思路起源于Kafka,但并不是簡(jiǎn)單的復(fù)制,它對(duì)消息的可靠傳輸及事務(wù)性做了優(yōu)化,目前在阿里集團(tuán)被廣泛應(yīng)用于交易、充值、流計(jì)算、消息推送、日志流式處理、binglog分發(fā)等場(chǎng)景,支撐了阿里多次雙十一活動(dòng)。因?yàn)槭前⒗飪?nèi)部從實(shí)踐到產(chǎn)品的產(chǎn)物,因此里面很多接口、API并不是很普遍適用。其可靠性毋庸置疑,而且與Kafka一脈相承(甚至更優(yōu)),性能強(qiáng)勁,支持海量堆積。
Kafka設(shè)計(jì)的初衷就是處理日志的,不支持AMQP事務(wù)處理,可以看做是一個(gè)日志系統(tǒng),針對(duì)性很強(qiáng),所以它并沒有具備一個(gè)成熟MQ應(yīng)該具備的特性。Kafka的性能(吞吐量、tps)比RabbitMQ要強(qiáng),如果用來做大數(shù)據(jù)量的快速處理是比RabbitMQ有優(yōu)勢(shì)的。
添加到短語集
沒有此單詞集:英語 → 中文(簡(jiǎn)體)...
創(chuàng)建新的單詞集...
拷貝
鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布
??????
??長(zhǎng)按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 
