掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
兩個(gè)系統(tǒng)或兩個(gè)客戶端之間進(jìn)行消息傳送,利用高效可靠的消息傳遞機(jī)制進(jìn)行平臺(tái)無關(guān)的數(shù)據(jù)交流,并基于數(shù)據(jù)通信來進(jìn)行分布式系統(tǒng)的集成。通過提供消息傳遞和消息排隊(duì)模型,它可以在分布式環(huán)境下擴(kuò)展進(jìn)程間的通信。

創(chuàng)新互聯(lián)公司2013年開創(chuàng)至今,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元紅古做網(wǎng)站,已為上家服務(wù),為紅古各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18982081108
消息中間件,總結(jié)起來作用有三個(gè):異步化提升性能、降低耦合度、流量削峰。
系統(tǒng)A發(fā)送消息給中間件后,自己的工作已經(jīng)完成了,不用再去管系統(tǒng)B什么時(shí)候完成操作。而系統(tǒng)B拉去消息后,執(zhí)行自己的操作也不用告訴系統(tǒng)A執(zhí)行結(jié)果,所以整個(gè)的通信過程是異步調(diào)用的。
有些業(yè)務(wù)不想也不需要立即處理消息。消息隊(duì)列提供了異步處理機(jī)制,允許用戶把一個(gè)消息放入隊(duì)列,但并不立即處理它。想向隊(duì)列中放入多少消息就放多少,然后在需要的時(shí)候再去處理它們。
在任何重要的系統(tǒng)中,都會(huì)有需要不同的處理時(shí)間的元素。消息隊(duì)列通過一個(gè)緩沖層來幫助任務(wù)最高效率的執(zhí)行,該緩沖有助于控制和優(yōu)化數(shù)據(jù)流經(jīng)過系統(tǒng)的速度。以調(diào)節(jié)系統(tǒng)響應(yīng)時(shí)間。
降低工程間的強(qiáng)依賴程度,針對(duì)異構(gòu)系統(tǒng)進(jìn)行適配。在項(xiàng)目啟動(dòng)之初來預(yù)測(cè)將來項(xiàng)目會(huì)碰到什么需求,是極其困難的。通過消息系統(tǒng)在處理過程中間插入了一個(gè)隱含的、基于數(shù)據(jù)的接口層,兩邊的處理過程都要實(shí)現(xiàn)這一接口,當(dāng)應(yīng)用發(fā)生變化時(shí),可以獨(dú)立的擴(kuò)展或修改兩邊的處理過程,只要確保它們遵守同樣的接口約束。
有些情況下,處理數(shù)據(jù)的過程會(huì)失敗。除非數(shù)據(jù)被持久化,否則將造成丟失。消息隊(duì)列把數(shù)據(jù)進(jìn)行持久化直到它們已經(jīng)被完全處理,通過這一方式規(guī)避了數(shù)據(jù)丟失風(fēng)險(xiǎn)。許多消息隊(duì)列所采用的”插入-獲取-刪除”范式中,在把一個(gè)消息從隊(duì)列中刪除之前,需要你的處理系統(tǒng)明確的指出該消息已經(jīng)被處理完畢,從而確保你的數(shù)據(jù)被安全的保存直到你使用完畢。
因?yàn)橄㈥?duì)列解耦了你的處理過程,所以增大消息入隊(duì)和處理的頻率是很容易的,只要另外增加處理過程即可。不需要改變代碼、不需要調(diào)節(jié)參數(shù)。便于分布式擴(kuò)容。
系統(tǒng)的一部分組件失效時(shí),不會(huì)影響到整個(gè)系統(tǒng)。消息隊(duì)列降低了進(jìn)程間的耦合度,所以即使一個(gè)處理消息的進(jìn)程掛掉,加入隊(duì)列中的消息仍然可以在系統(tǒng)恢復(fù)后被處理。
在大多使用場(chǎng)景下,數(shù)據(jù)處理的順序都很重要。大部分消息隊(duì)列本來就是排序的,并且能保證數(shù)據(jù)會(huì)按照特定的順序來處理。
在訪問量劇增的情況下,應(yīng)用仍然需要繼續(xù)發(fā)揮作用,但是這樣的突發(fā)流量無法提取預(yù)知;如果以為了能處理這類瞬間峰值訪問為標(biāo)準(zhǔn)來投入資源隨時(shí)待命無疑是巨大的浪費(fèi)。使用消息隊(duì)列能夠使關(guān)鍵組件頂住突發(fā)的訪問壓力,而不會(huì)因?yàn)橥话l(fā)的超負(fù)荷的請(qǐng)求而完全崩潰。
分布式系統(tǒng)產(chǎn)生的海量數(shù)據(jù)流,如:業(yè)務(wù)日志、監(jiān)控?cái)?shù)據(jù)、用戶行為等,針對(duì)這些數(shù)據(jù)流進(jìn)行實(shí)時(shí)或批量采集匯總,然后進(jìn)行大數(shù)據(jù)分析是當(dāng)前互聯(lián)網(wǎng)的必備技術(shù),通過消息隊(duì)列完成此類數(shù)據(jù)收集是最好的選擇。
點(diǎn)對(duì)點(diǎn)消息傳遞域的特點(diǎn)如下:
每個(gè)消息只能有一個(gè)消費(fèi)者。
消息的生產(chǎn)者和消費(fèi)者之間沒有時(shí)間上的相關(guān)性。無論消費(fèi)者在生產(chǎn)者發(fā)送消息的時(shí)候是否處于運(yùn)行狀態(tài),它都可以提取消息。發(fā)布/訂閱消息傳遞域的特點(diǎn)如下:
每個(gè)消息可以有多個(gè)消費(fèi)者。
生產(chǎn)者和消費(fèi)者之間有時(shí)間上的相關(guān)性。
訂閱一個(gè)主題的消費(fèi)者只能消費(fèi)自它訂閱之后發(fā)布的消息。JMS規(guī)范允許客戶創(chuàng)建持久訂閱,這在一定程度上放松了時(shí)間上的相關(guān)性要求 。持久訂閱允許消費(fèi)者消費(fèi)它在未處于激活狀態(tài)時(shí)發(fā)送的消息。在點(diǎn)對(duì)點(diǎn)消息傳遞域中,目的地被成為隊(duì)列(queue);在發(fā)布/訂閱消息傳遞域中,目的地被成為主題(topic)。
JMS消息由以下三部分組成的:
消息頭:
每個(gè)消息頭字段都有相應(yīng)的getter和setter方法。
消息屬性:
如果需要除消息頭字段以外的值,那么可以使用消息屬性。
消息體:
JMS定義的消息類型有TextMessage、MapMessage、BytesMessage、StreamMessage和ObjectMessage。
消息類型:
只有在被確認(rèn)之后,才認(rèn)為已經(jīng)被成功地消費(fèi)了,消息的成功消費(fèi)通常包含三個(gè)階段 :客戶接收消息、客戶處理消息和消息被確認(rèn)。在事務(wù)性會(huì)話中,當(dāng)一個(gè)事務(wù)被提交的時(shí)候,確認(rèn)自動(dòng)發(fā)生。在非事務(wù)性會(huì)話中,消息何時(shí)被確認(rèn)取決于創(chuàng)建會(huì)話時(shí)的應(yīng)答模式(acknowledgement mode)。該參數(shù)有以下三個(gè)可選值:
可以使用消息優(yōu)先級(jí)來指示JMS Provider首先提交緊急的消息。優(yōu)先級(jí)分10個(gè)級(jí)別,從0(最低)到9(最高)。如果不指定優(yōu)先級(jí),默認(rèn)級(jí)別是4。需要注意的是,JMS Provider并不一定保證按照優(yōu)先級(jí)的順序提交消息。
可以設(shè)置消息在一定時(shí)間后過期,默認(rèn)是永不過期。
可以通過會(huì)話上的createTemporaryQueue方法和createTemporaryTopic方法來創(chuàng)建臨時(shí)目的地。它們的存在時(shí)間只限于創(chuàng)建它們的連接所保持的時(shí)間。只有創(chuàng)建該臨時(shí)目的地的連接上的消息消費(fèi)者才能夠從臨時(shí)目的地中提取消息。
ActiveMQ是一種開源的基于JMS(Java Message Servie)規(guī)范的一種消息中間件的實(shí)現(xiàn),ActiveMQ的設(shè)計(jì)目標(biāo)是提供標(biāo)準(zhǔn)的,面向消息的,能夠跨越多語言和多系統(tǒng)的應(yīng)用集成消息通信中間件。
官網(wǎng)地址:http://activemq.apache.org/
1. KahaDB存儲(chǔ): KahaDB是默認(rèn)的持久化策略,所有消息順序添加到一個(gè)日志文件中,同時(shí)另外有一個(gè)索引文件記錄指向這些日志的存儲(chǔ)地址,還有一個(gè)事務(wù)日志用于消息回復(fù)操作。是一個(gè)專門針對(duì)消息持久化的解決方案,它對(duì)典型的消息使用模式進(jìn)行了優(yōu)化
特性:
2. AMQ 方式: 只適用于 5.3 版本之前。AMQ 也是一個(gè)文件型數(shù)據(jù)庫(kù),消息信息最終是存儲(chǔ)在文件中。內(nèi)存中也會(huì)有緩存數(shù)據(jù)。
3. JDBC存儲(chǔ) : 使用JDBC持久化方式,數(shù)據(jù)庫(kù)默認(rèn)會(huì)創(chuàng)建3個(gè)表,每個(gè)表的作用如下:
activemqmsgs:queue和topic的消息都存在這個(gè)表中activemqacks:存儲(chǔ)持久訂閱的信息和最后一個(gè)持久訂閱接收的消息IDactivemq_lock:跟kahadb的lock文件類似,確保數(shù)據(jù)庫(kù)在某一時(shí)刻只有一個(gè)broker在訪問
4. LevelDB存儲(chǔ) : LevelDB持久化性能高于KahaDB,但是在ActiveMQ官網(wǎng)對(duì)LevelDB的表述:LevelDB官方建議使用以及不再支持,推薦使用的是KahaDB
5.Memory 消息存儲(chǔ): 顧名思義,基于內(nèi)存的消息存儲(chǔ),就是消息存儲(chǔ)在內(nèi)存中。persistent=”false”,表示不設(shè)置持 久化存儲(chǔ),直接存儲(chǔ)到內(nèi)存中,在broker標(biāo)簽處設(shè)置。
協(xié)議官網(wǎng)API:http://activemq.apache.org/configuring-version-5-transports.html
1.NIO協(xié)議和TCP協(xié)議類似,但NIO更側(cè)重于底層的訪問操作。它允許開發(fā)人員對(duì)同一資源可有更多的client調(diào)用和服務(wù)端有更多的負(fù)載。
2.適合使用NIO協(xié)議的場(chǎng)景:
(1)可能有大量的Client去鏈接到Broker上一般情況下,大量的Client去鏈接Broker是被操作系統(tǒng)的線程數(shù)所限制的。因此,NIO的實(shí)現(xiàn)比TCP需要更少的線程去運(yùn)行,所以建議使用NIO協(xié)議(2)可能對(duì)于Broker有一個(gè)很遲鈍的網(wǎng)絡(luò)傳輸NIO比TCP提供更好的性能
3.NIO連接的URI形式:nio://hostname:port?key=value
4.Transport Connector配置示例:
- name="tcp"
- uri="tcp://localhost:61616?trace=true" />
- name="nio"
- uri="nio://localhost:61618?trace=true" />
1.UDP和TCP的區(qū)別
(1)TCP是一個(gè)原始流的傳遞協(xié)議,意味著數(shù)據(jù)包是有保證的,換句話說,數(shù)據(jù)包是不會(huì)被復(fù)制和丟失的。UDP,另一方面,它是不會(huì)保證數(shù)據(jù)包的傳遞的
( 2)TCP也是一個(gè)穩(wěn)定可靠的數(shù)據(jù)包傳遞協(xié)議,意味著數(shù)據(jù)在傳遞的過程中不會(huì)被丟 失。這樣確保了在發(fā)送和接收之間能夠可靠的傳遞。相反,UDP僅僅是一個(gè)鏈接協(xié)議,所以它沒有可靠性之說
2.從上面可以得出:TCP是被用在穩(wěn)定可靠的場(chǎng)景中使用的;UDP通常用在快速數(shù)據(jù)傳遞和不怕數(shù)據(jù)丟失的場(chǎng)景中,還有ActiveMQ通過防火墻時(shí),只能用UDP
3.UDP連接的URI形式:udp://hostname:port?key=value
4.Transport Connector配置示例:
- name="udp"
- uri="udp://localhost:61618?trace=true" />
1.連接的URI形式:ssl://hostname:port?key=value
2.Transport Connector配置示例:
"ssl" uri="ssl://localhost:61617?trace=true"/>
這里以windows為案例演示
下載地址:http://activemq.apache.org/components/classic/download/
解壓后直接執(zhí)行 bin/win64/activemq.bat
http://localhost:8161/賬號(hào)密碼:admin/admin
修改 ActiveMQ 配置文件 activemq/conf/jetty.xml
jettyport節(jié)點(diǎn): 配置文件修改完畢,保存并重新啟動(dòng) ActiveMQ 服務(wù)
"jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start"> "host" value="127.0.0.1"/> "port" value="8161"/>
1. jar引入:
org.springframework.boot spring-boot-starter-activemq
2. Sender :
- import org.apache.activemq.ActiveMQConnectionFactory;
- import javax.jms.*;
- /**
- * @program: activemq_01
- * @ClassName Sender
- * @description: 消息發(fā)送
- * @author: muxiaonong
- * @create: 2020-10-02 13:01
- * @Version 1.0
- **/
- public class Sender {
- public static void main(String[] args) throws Exception{
- // 1. 獲取連接工廠
- ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(
- ActiveMQConnectionFactory.DEFAULT_USER,
- ActiveMQConnectionFactory.DEFAULT_PASSWORD,
- "tcp://localhost:61616"
- );
- // 2. 獲取一個(gè)向activeMq的連接
- Connection connection = factory.createConnection();
- // 3. 獲取session
- Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- // 4.找目的地,獲取destination,消費(fèi)端,也會(huì)從這個(gè)目的地取消息
- Queue queue = session.createQueue("user");
- // 5.1 消息創(chuàng)建者
- MessageProducer producer = session.createProducer(queue);
- // consumer --> 消費(fèi)者
- // producer --> 創(chuàng)建者
- // 5.2. 創(chuàng)建消息
- for (int i = 0; i < 100; i++) {
- TextMessage textMessage = session.createTextMessage("hi:"+i);
- // 5.3 向目的地寫入消息
- producer.send(textMessage);
- Thread.sleep(1000);
- }
- // 6.關(guān)閉連接
- connection.close();
- System.out.println("結(jié)束。");
- }
- }
3. Receiver :
- import org.apache.activemq.ActiveMQConnectionFactory;
- import javax.jms.*;
- /**
- * @program: activemq_01
- * @ClassName Receiver
- * @description: 消息接收
- * @author: muxiaonong
- * @create: 2020-10-02 13:01
- * @Version 1.0
- **/
- public class Receiver {
- public static void main(String[] args) throws Exception{
- // 1. 獲取連接工廠
- ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(
- ActiveMQConnectionFactory.DEFAULT_USER,
- ActiveMQConnectionFactory.DEFAULT_PASSWORD,
- "tcp://localhost:61616"
- );
- // 2. 獲取一個(gè)向activeMq的連接
- Connection connection = factory.createConnection();
- connection.start();
- // 3. 獲取session
- Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- // 4.找目的地,獲取destination,消費(fèi)端,也會(huì)從這個(gè)目的地取消息
- Destination queue = session.createQueue("user");
- // 5 獲取消息
- MessageConsumer consumer = session.createConsumer(queue);
- while(true){
- TextMessage message = (TextMessage)consumer.receive();
- System.out.println("message:"+message.getText());
- }
- }
- }
測(cè)試結(jié)果:
- message:hi:38
- message:hi:39
- message:hi:40
- message:hi:41
- message:hi:42
- message:hi:43
- message:hi:44
- message:hi:45
web后臺(tái)顯示有一個(gè)消費(fèi)者處于連接狀態(tài),且已消費(fèi)了68個(gè)message,而該條隊(duì)列已沒有message待消費(fèi)了。
今天的MQ入門教程系列就這里了,感興趣的小伙伴可以試試,MQ作為一個(gè)消息中間件,不管是面試還是工作中都會(huì)經(jīng)常用到,所以是很有必要去了解和學(xué)習(xí)的一個(gè)技術(shù)點(diǎn),今天的分享就到這里了,謝謝各位小伙伴的觀看,我們下篇文章見,大家加油!
本文轉(zhuǎn)載自微信公眾號(hào)「牧小農(nóng)」

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流