扫盲消息队列 | 消息中间件 | Kafka
先吐槽
我真的寫技術(shù)文章寫到懷疑人生,我翻看歷史發(fā)文記錄,只要我一本正經(jīng)的寫的技術(shù)文章,都沒人看,但是!一發(fā)閑扯淡的內(nèi)容,閱讀量肯定是技術(shù)文的好幾倍(讀者爸爸們別這么搞嘛)
這說明啥?說明學(xué)習(xí)還是太枯燥無趣了,但是你想想,每天就網(wǎng)上看閑扯淡的文章,這咋能進大廠嘛!對吧。
再接受幾次這樣的打擊我都不想寫技術(shù)文章了。哎!不過我也就嘴上說說,我還是會堅持寫下去的。
反正你們有沒有認真看我不知道,我寫完一遍這個文章,每個知識點細節(jié)我都滾瓜亂熟了,因為都是我一個字一個字敲出來的。
開始正文吧!21世紀(jì)的流水線工人,消息隊列是一定要會的。
我真的不能再貼心了!!!!
背景
image-20200420194331765分布式微服務(wù)系統(tǒng)下,凡是可以“排隊”去做的事情,都可以使用消息隊列。網(wǎng)上買東西同樣也需要“排隊付款”,但是有人說,我點確認付款后馬上就顯示成功了,沒感覺到排隊呀?其實在后臺系統(tǒng)中是排了,只不過排隊的時間對于人來說有點短,可能1-2秒就結(jié)束了,但是對于計算機來說,這1-2秒的時間很長了。
大型分布式系統(tǒng)建設(shè)中,消息隊列主要解決應(yīng)用耦合、異步消息、流量削鋒等問題。實現(xiàn)高性能、高可用、可伸縮和最終一致性架構(gòu)。是大型分布式系統(tǒng)不可缺少的中間件。消息發(fā)布者只管把消息發(fā)布到 MQ 中而不用管誰來取,消息使用者只管從 MQ 中取消息而不管是誰發(fā)布的。這樣發(fā)布者和使用者都不用知道對方的存在。
Web應(yīng)用程序毫無疑問有大量的代碼執(zhí)行HTTP請求/響應(yīng)周期的一部分。這適用于更快的任務(wù)耗費數(shù)百毫秒內(nèi)或更少。然而,有些處理,還需要耗時更多甚至最終會是一兩秒鐘緩慢的同步執(zhí)行,在如此長時間的調(diào)用流轉(zhuǎn)中,肯定有一些調(diào)用是可以不同步的,如下單送積分,用戶下單是最主要的,送積分的操作可以異步去做,訂單支付成功給用戶的短信通知,返回支付訂單進入下一環(huán)節(jié)更更好,短信通知可以異步去發(fā)送,為了應(yīng)對諸如此類的異步操作,消息隊列這門技術(shù)應(yīng)運而生。
message-queue-example在計算機科學(xué)中,消息隊列(Message queue)是一種進程間通信或同一進程的不同線程間的通信方式。實際上,消息隊列常常保存在鏈表結(jié)構(gòu)中。[2]擁有權(quán)限的進程可以向消息隊列中寫入或讀取消息。
目前,有很多消息隊列有很多開源的實現(xiàn),包括JBoss Messaging、JORAM、Apache ActiveMQ、Sun Open Message Queue、RabbitMQ[3]、IBM MQ[4]、Apache Qpid[5]、Apache RocketMQ[6]和HTTPSQS。[7]
說了這么多沒用的,消息隊列到底在企業(yè)里怎么用的?
我就直接上兩段代碼吧
發(fā)送一條消息demo
public?class?MqProducer?{private?final?Logger?LOG?=?LoggerFactory.getLogger(MqProducer.class);@Resourceprivate?Producer?payProducer;public?void?sendPayMsg(String?msg)?{try?{LOG.debug("send?msg:{}",?msg);payProducer.send(msg);//發(fā)送出去一條消息。}?catch?(MQException?e)?{LOG.error("mq消息異常?message:{}",?msg,?e);}} }接收一個消息demo
public?class?DemoConsumer?{/***?注意:服務(wù)端對單ip創(chuàng)建相同主題相同隊列的消費者實例數(shù)有限制,超過100個拒絕創(chuàng)建.*?*/private?static?IConsumerProcessor?consumer;public?static?void?main(String[]?args)?throws?Exception?{Properties?properties?=?new?Properties();properties.setProperty(ConsumerConstants.SubscribeGroup,?"dache.risk.log.queue.v2");//?創(chuàng)建topic對應(yīng)的consumer對象(注意每次build調(diào)用會產(chǎn)生一個新的實例)consumer?=?KafkaClient.buildConsumerFactory(properties,?"topic.xxx.xxx");//?調(diào)用recvMessageWithParallel設(shè)置listenerconsumer.recvMessageWithParallel(String.class,?new?IMessageListener()?{@Overridepublic?ConsumeStatus?recvMessage(Message?message,?MessagetContext?context)?{//TODO:業(yè)務(wù)側(cè)的消費邏輯代碼try?{System.out.println("message=["?+?message.getBody()?+?"]??partition="?+?message.getParttion());}?catch?(Exception?e)?{e.printStackTrace();}return?ConsumeStatus.CONSUME_SUCCESS;}});} }消息長什么樣子?
{"businessType":1,"cityId":10,"ctime":1567426767077,"dataKey":20190902,"logType":1,"phone":"13212341234","uid":12345678,"userType":1,"uuid":"32EA02C86D78863"}代碼呢,就是普通的java代碼,只不過引入了一個kafka的jar,消息就是json串,使用消息隊列真的就這么點代碼,剩下的內(nèi)容都是業(yè)務(wù)代碼了。
新手關(guān)注消息隊列,主要關(guān)注兩個最重要的概念就行了,一個是生產(chǎn)者,一個是消費者,兩者的關(guān)系和我們?nèi)粘0l(fā)短信一樣,短信是通過手機號發(fā)送接收,系統(tǒng)間消息是通過topic,可以理解成手機號。
Producer消息的生產(chǎn)方,如支付系統(tǒng)確認用戶已經(jīng)支付,支付系統(tǒng)要通知訂單系統(tǒng)和物流系統(tǒng),支付系統(tǒng)就是生產(chǎn)者。
Consumer消費的接收方,Producer 的案例中,物流系統(tǒng)就是消費方,前兩個都比較簡單,我就不多說了。
Topic每條發(fā)布到MQ集群的消息都有一個類別,這個類別被稱為topic,可以理解成一類消息的名字。所有的消息都以topic作為單位進行歸類。
日常開發(fā)中需要關(guān)心哪些指標(biāo)
1.生產(chǎn)消息數(shù)目
每分鐘幾百幾千個都正常水平吧,業(yè)務(wù)繁忙的每分鐘幾萬幾十萬也是有的
image-202004201933503712.消息延遲情況
延遲越低越好啦,幾百毫秒正常水平。
image-202004201935407663.消息積壓數(shù)
這個當(dāng)然是要0了,如果遇到消費端服務(wù)器上線,可能會有段時間積壓正常,這個指標(biāo),日常應(yīng)該都是0才對。
image-20200420194052328為什么使用消息隊列
開頭不是說了,排隊能解決一個問題,就是削峰,意思就是流量洪峰來了,收銀員結(jié)賬速度依舊是一樣的,不會被累死,還有兩個重要的概念就是解耦、異步
使用消息隊列有什么缺點呢?
這個新手也一定要知道啦,因為面試官會問。
消息丟失問題: 任何系統(tǒng)不能保證萬無一失,比如 Producer 發(fā)出了10000條消息,Consumer 只收到了 9999 個消息,有1個丟了,Consumer 能否接受丟一條?如果是訂單成功短信可以接受丟一條,就是有一個顧客沒有通知到已經(jīng)發(fā)貨,但貨還是發(fā)出去了,如果是支付系統(tǒng),用戶已經(jīng)付款卻因為消息丟失沒有通知到訂單或物流系統(tǒng),那恐怕顧客要找你麻煩了。
消息重復(fù)問題:如 Producer 發(fā)出了10000條消息,Consumer 只收到了 10001 條消息,有一條是重復(fù)的,業(yè)務(wù)能否接受一條重復(fù)的消息,這個是作為系統(tǒng)設(shè)計者要考慮的問題。
消息的順序問題:如 Producer 發(fā)送順序是123,Consumer 收到的消息是132,要考慮消費端是否對順序敏感。
一致性問題: 如消息丟失問題真的發(fā)生且無法找回,會造成兩個系統(tǒng)的數(shù)據(jù)最終不一致,如果消息延遲,會造成短暫不一致。
ActiveMQ vs Kafka vs RabbitMQ
RabbitMQ、Kafka和ActiveMQ都是用于提供異步通信和解耦進程(分離消息的發(fā)送方和接收方)的消息傳遞技術(shù)。
它們被稱為消息隊列、消息代理或消息傳遞工具。RabbitMQ、Kafka和ActiveMQ都有相同的基本用途,但它們的工作方式不同。Kafka是一個高吞吐量的分布式消息傳遞系統(tǒng)。
RabbitMQ是一個基于AMQP的可靠消息代理。ActiveMQ和Kafka都是Apache的產(chǎn)品,都是用Java編寫的,RabbitMQ是用Erlang編寫的。
進BAT你就研究這其中一個就可以了,數(shù)量不在多,重點是深度。
ActiveMQ,Kafka和RabbitMQ有哪些替代方案?
這些在國內(nèi)都不是很常用,新手了解一下就可以了,反正,知識廣度&眼界是有了。
Apollo:在現(xiàn)有REST API的基礎(chǔ)上構(gòu)建一個通用的GraphQL API,可以快速發(fā)布新的應(yīng)用程序特性,而無需等待后端更改。
IBM MQ:它是一個消息傳遞中間件,可以簡化和加速跨多個平臺的不同應(yīng)用程序和業(yè)務(wù)數(shù)據(jù)的集成。它提供了經(jīng)過驗證的企業(yè)級消息傳遞功能,能夠熟練而安全地移動信息。
ZeroMQ:擴展性好,開發(fā)比較靈活,采用C語言實現(xiàn),實際上他只是一個socket庫的重新封裝,如果我們做為消息隊列使用,需要開發(fā)大量的代碼
Amazon SQS
關(guān)于消息隊列的常見面試題
為什么使用消息隊列?
消息隊列有什么優(yōu)點和缺點?
那為什么Kafka的吞吐量遠高于其他同類中間件?
比較重要的關(guān)鍵字嗎?比如Producer,Consumer,Partition,Broker,你都是怎么理解的?
參考資料
Thorough Introduction to Apache Kafka
推薦一本書《深入理解Kafka:核心設(shè)計與實踐原理》,微信讀書就可以免費閱讀。
總結(jié)
以上是生活随笔為你收集整理的扫盲消息队列 | 消息中间件 | Kafka的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员过关斩将-- 工作好多年可能还未真
- 下一篇: 7种方法帮助企业改进软件维护效率