java 极客_Java极客思维
?
開篇介紹
大家好,公眾號(hào)【Java極客思維】近期會(huì)整理一些Java高頻面試題分享給小伙伴,也希望看到的小伙伴在找工作過程中能夠用得到!本章節(jié)主要針對(duì)Java一些消息中間件高頻面試題進(jìn)行分享。
通知:公眾號(hào)【Java極客思維】正在送書福利活動(dòng),關(guān)注公眾號(hào)并參加福利活動(dòng)吧!只有參與了本次活動(dòng)的小伙伴才能夠參與年底的大福利,不要錯(cuò)過呀~
Q1:
RabbitMQ 的介紹、用途、好處?
RabbitMQ是一款開源的,Erlang編寫的,基于AMQP協(xié)議的消息中間件。
作用:解耦?、?異步?、?削峰?。
優(yōu)點(diǎn):解耦、異步、削峰;
缺點(diǎn):降低了系統(tǒng)的穩(wěn)定性:系統(tǒng)中使用了消息隊(duì)列,如果消息隊(duì)列掛了,那么系統(tǒng)也會(huì)掛。降低了系統(tǒng)可用性。
加入消息隊(duì)列,要考慮很多方面的問題,比如:一致性問題 、如何保證消息不被重復(fù)消費(fèi) 、?如何保證消息可靠性傳輸 等。因此考慮的因素有很多方面,復(fù)雜性增加。
Q2:
RabbitMQ 包括哪些要素?生產(chǎn)者?:消息的創(chuàng)建者,發(fā)送到RabbitMQ
消費(fèi)者?:連接到RabbitMQ,訂閱到隊(duì)列上,消費(fèi)消息,持續(xù)訂閱(basicConsumer)和單條訂閱(basicGet)
消息 :包含有效載荷和標(biāo)簽,有效載荷指要傳輸?shù)臄?shù)據(jù),標(biāo)簽描述了有效載荷,并且RabbitMQ用它來決定誰獲得消息,消費(fèi)者只能拿到有效載荷,并不知道生產(chǎn)者是誰。
Q3:
RabbitMQ 什么是信道?
信道:是生產(chǎn)者、消費(fèi)者與RabbitMQ通信的渠道,生產(chǎn)者publish或是消費(fèi)者subscribe一個(gè)隊(duì)列都是通過信道來通信的。信道是建立在TCP連接上的虛擬連接。就是說RabbitMQ在一條TCP上建立成百上千個(gè)信道來達(dá)到多個(gè)線程處理,這個(gè)TCP被多個(gè)線程共享,每個(gè)線程對(duì)應(yīng)一個(gè)信道,信道在RabbitMQ都有一個(gè)唯一的ID,保證了信道私有性,對(duì)應(yīng)上唯一的線程使用。
疑問:為什么不建立多個(gè)TCP連接?
原因是RabbitMQ需要保證性能,系統(tǒng)為每個(gè)線程開辟一個(gè)TCP是非常消耗性能的,美妙成百上千的建立銷毀TCP會(huì)嚴(yán)重消耗系統(tǒng)性能;所以RabbitMQ選擇建立多個(gè)信道(建立在TCP的虛擬連接)連接到RabbitMQ上
Q4:
RabbitMQ概念里的channel、exchange 和 queue是邏輯概念,還是對(duì)應(yīng)著進(jìn)程實(shí)體?作用分別是什么?
queue?具有自己的?erlang?進(jìn)程;
exchange?內(nèi)部實(shí)現(xiàn)為保存?binding?關(guān)系的查找表;
channel?是實(shí)際進(jìn)行路由工作的實(shí)體,負(fù)責(zé)按照 routing_key 將 message投遞給queue。
由 AMQP 協(xié)議描述可知,channel?是真實(shí)TCP連接之上的?虛擬連接?, 所有AMQP 命令都是通過 channel 發(fā)送的,且每一個(gè) channel 有?唯一的ID?。一個(gè) channel 只能被單獨(dú)一個(gè)操作系統(tǒng)線程使用,所以投遞到特定的 channel 上的 message 是有順序的。單一個(gè)操作系統(tǒng)線程上允許使用多個(gè)channel。
Q5:
RabbitMQ消息是如何路由的?
消息路由必須有三部分:交換器、路由、綁定。
生產(chǎn)者把消息發(fā)布到交換器上,綁定決定了消息如何從路由器路由到特定的隊(duì)列;消息最終到達(dá)隊(duì)列,并被消費(fèi)者接收。
消息發(fā)布到交換器時(shí),消息將擁有一個(gè)?路由鍵(routing key)?, 在消息創(chuàng)建時(shí)設(shè)定。
通過隊(duì)列路由鍵,可以把隊(duì)列綁定到交換器上。
消息到達(dá)交換器后,RabbitMQ會(huì)將消息的路由鍵與隊(duì)列的路由鍵進(jìn)行匹配(針對(duì)不同的交換器有不同的路由規(guī)則)。如果能夠匹配到隊(duì)列,則消息會(huì)投遞到相應(yīng)隊(duì)列中;如果不能匹配到任何隊(duì)列,消息將進(jìn)入"黑洞"。
常用的交換器主要分為以下三種:direct?:如果路由鍵完全匹配,消息就會(huì)被投遞到相應(yīng)的隊(duì)列;每個(gè)AMQP的實(shí)現(xiàn)都必須有一個(gè)direct交換器,包含一個(gè)空白字符串名稱的默認(rèn)交換器。聲明一個(gè)隊(duì)列時(shí),會(huì)自動(dòng)綁定到默認(rèn)交換器,并且以隊(duì)列名稱作為路由鍵:channel -> basic_public($msg, '', 'queue-name')
fanout?:?如果交換器收到消息,將會(huì)廣播到所有綁定的隊(duì)列上;
topic?:可以使來自不同源頭的消息能夠到達(dá)同一個(gè)隊(duì)列。使用topic交換器時(shí),可以使用通配符,比如:"*"?匹配特定位置的任意文本,"."?把路由鍵分為了幾個(gè)標(biāo)識(shí)符,?"#"?匹配所有規(guī)則等。
特別注意:發(fā)往topic交換器的消息不能隨意的設(shè)置選擇鍵(routing_key),必須是有"."隔開的一系列的標(biāo)識(shí)符組成。
Q6:
RabbitMQ消息確認(rèn)過程?
消費(fèi)者收到的每一條消息都必須進(jìn)行確認(rèn)(自動(dòng)確認(rèn)和自行確認(rèn))
消費(fèi)者在聲明隊(duì)列時(shí),可以置頂autoAck參數(shù),當(dāng)autoAck = false時(shí),RabbitMQ會(huì)等待消費(fèi)者顯式發(fā)送回 ack 信號(hào)后才從內(nèi)存(和磁盤,如果是持久化消息的話)中刪除消息,否則RabbitMQ會(huì)在隊(duì)列中消息被消費(fèi)后立即刪除它。
采用消息確認(rèn)機(jī)制后,只要使 autoAck = false,消費(fèi)者就有足夠的時(shí)間處理消息(任務(wù)),不用擔(dān)心處理消息過程中消費(fèi)者進(jìn)程掛掉后消息丟失的問題,因?yàn)镽abbitMQ會(huì)一直持有消息直到消費(fèi)者顯式調(diào)用basicAck為止。
當(dāng)autoAck = false時(shí),對(duì)于RabbitMQ服務(wù)器端而言,隊(duì)列中的消息分成了兩部分:一部分是等待投遞給消費(fèi)者的消息;一部分是已經(jīng)投遞給消費(fèi)者,但是還沒有收到消費(fèi)者ack信號(hào)的消息。如果服務(wù)器端一直沒有收到消費(fèi)者的ack信號(hào),并且消費(fèi)此消息的消費(fèi)者已經(jīng)斷開連接,則服務(wù)器端會(huì)安排該消息 重新進(jìn)入隊(duì)列,等待投遞給下一個(gè)消費(fèi)者(也可能還是原來的那個(gè)消費(fèi)者)。
RabbitMQ不會(huì)為 ack消息設(shè)置超時(shí)時(shí)間,它判斷此消息是否需要重新投遞給消費(fèi)者的唯一依據(jù)是消費(fèi)該消息的消費(fèi)者連接是否已經(jīng)斷開。這么設(shè)計(jì)的原因是RabbitMQ允許消費(fèi)者消費(fèi)一條消息的時(shí)間可以很久很久。
Q7:
如何保證RabbitMQ不被重復(fù)消費(fèi)?
正常情況下,消費(fèi)者在消費(fèi)消息的時(shí)候,消費(fèi)完畢后,會(huì)發(fā)送一個(gè)確認(rèn)信息給消息隊(duì)列,消息隊(duì)列就知道該消息被消費(fèi)了,就會(huì)將該消息從消息隊(duì)列中刪除。
但是因?yàn)榫W(wǎng)絡(luò)傳輸?shù)裙收?#xff0c;確認(rèn)信息沒有傳送到消息隊(duì)列,導(dǎo)致消息隊(duì)列不知道自己已經(jīng)消費(fèi)過該消息了,再次將消息分發(fā)給其他的消費(fèi)者。
解決思路:
保證消息的唯一性,就算是多次傳輸,不要讓消息的多次消費(fèi)帶來影響;
保證消息冪等性;
比如:在寫入消息隊(duì)列的數(shù)據(jù)做唯一標(biāo)識(shí),消費(fèi)消息時(shí),根據(jù)唯一標(biāo)識(shí)判斷該消息是否被消費(fèi)過。
Q8:
如何保證RabbitMQ消息的可靠傳輸?
消息不可靠的情況可能是消息丟失,劫持等原因;
丟失可能又分為:生產(chǎn)者丟失消息
消息隊(duì)列丟失消息
消費(fèi)者丟失消息
生產(chǎn)者丟失消息:
從生產(chǎn)者弄丟數(shù)據(jù)來看,RabbitMQ提供了?transaction?機(jī)制 和?confirm 模式 來確保生產(chǎn)者不丟失消息;transaction機(jī)制:?發(fā)送消息前,開啟事務(wù)(channel.exSelect()),然后發(fā)送消息,如果發(fā)送過程中出現(xiàn)異常,事務(wù)就會(huì)回滾(channel.txRollback()),如果發(fā)送成功則提交事務(wù)(channel.txCommit())。
confirm模式:一般這種模式居多,一旦channel進(jìn)入confirm模式,所有在該信道上發(fā)布的消息都將會(huì)被指派一個(gè)唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊(duì)列后;RabbitMQ就會(huì)發(fā)送一個(gè)ACK給生產(chǎn)者(包含消息的唯一ID),這就使得生產(chǎn)者知道消息已經(jīng)正確到達(dá)目的隊(duì)列了。
如果RabbitMQ沒能處理該消息,則會(huì)發(fā)送一個(gè)Nack消息回來,這樣可以進(jìn)行重試操作。
消息隊(duì)列丟失消息:
針對(duì)消息隊(duì)列丟失數(shù)據(jù)的情況,一般是開啟持久化磁盤的配置:
將隊(duì)列的持久化標(biāo)識(shí)?durable?設(shè)置為?true?, 則代表是一個(gè)持久的隊(duì)列,發(fā)送消息的時(shí)候講?deliveryMode=2?這樣設(shè)置以后,即使RabbitMQ掛了,重啟后也能恢復(fù)數(shù)據(jù)。
消費(fèi)者丟失消息:
消費(fèi)者丟失消息一般是因?yàn)椴捎昧俗詣?dòng)確認(rèn)消息模式,改為手動(dòng)確認(rèn)消息即可。
消費(fèi)者在收到消息之后,處理消息之前,會(huì)自動(dòng)回復(fù)RabbitMQ已收到消息;如果這時(shí)候處理消息失敗,就會(huì)丟失該消息;
解決方案:處理消息成功后,手動(dòng)回復(fù)確認(rèn)消息。
點(diǎn)關(guān)注、不迷路
如果覺得文章不錯(cuò),歡迎關(guān)注、點(diǎn)贊、收藏,你們的支持是我創(chuàng)作的動(dòng)力,感謝大家。
如果文章寫的有問題,請(qǐng)不要吝嗇,歡迎留言指出,我會(huì)及時(shí)核查修改。
如果你還想更加深入的了解我,可以微信搜索「Java極客思維」進(jìn)行關(guān)注。每天8:00準(zhǔn)時(shí)推送技術(shù)文章,讓你的上班路不在孤獨(dú),而且每月還有送書活動(dòng),助你提升硬實(shí)力!查看原文
總結(jié)
以上是生活随笔為你收集整理的java 极客_Java极客思维的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 斜角柜门板用什么铰链图片?
- 下一篇: 柏厨全屋定制贵吗?求知道的朋友说一说