ActiveMQ的介紹
MQ是消息中間件,是一種在分佈式系統中應用程序藉以傳遞消息的媒介,Apache ActiveMQ是Apache軟件基金會所研發的開放源代碼消息中間件,是使用Java語言實現的中間件。ActiveMQ是Apache下的開源項目,完全支持JMS1.1和J2EE1.4規範的JMS Provider實現。
特點:
支持的語言(支持很多種語言編寫客戶端):Java、C、C++、C#、Ruby、Perl、python、PHP
應用協議:OpenWire、Stomp、WS、Notifaction、XMPP、AMQP
完全支持JMS1.1和J2EE1.4規範(持久化、XA消息,事務);
支持多種傳送協議:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA,支持通過JDBC和journal提供高速的消息持久化。
從設計上保證了高性能的集羣,客戶端-服務器,點對點。
支持Ajax,支持與Ajax的整合,Webservices
可以很容易的調用內嵌JMS provider,進行測試
對Spring的支持,ActiveMQ可以很容易內嵌到使用spring的系統裏去。
除了常見的J2EE服務器(如Geronimo,JBoss4,GlassFish,WebLogic)的測試,其中通過JCA1.5 resource adaptors的配置可以讓ActiveMQ可以自動化的部署到任何兼容J2EE1.4商業服務器上。
相關概念:
1,Desination
目的地,JMS Provider(消息中間件)負責維護,用於對Message進行管理的對象。MessageProducer需要指定Destination才能發送消息,MessageConsumer需要指定Destination才能接收消息。
2,Producer
消息生成者(客戶端,生成消息),負責發送Message到目的地,應用接口爲MessageProducer。在JMS規範中,所有的標準定義都在javax.jms包中。
3,Consumer(Receiver)
消息消費者(處理消息),負責從目的地中消費(處理、監聽、訂閱)Message,應用接口爲MessageConsumer。
4,Message
消息(Message),消息封裝一次通信的內容,常見的類型有:StreamMessage、BytesMessage、TextMessage、ObjectMessage、MapMessage。
5,ConnectionFactory
鏈接工廠,用於創建鏈接的工廠類型看,注意,不能和JDBC中的ConnectionFactory混淆。
6,Connection
鏈接,用於建立訪問ActiveMQ連接的類型,由鏈接工廠創建,不能喝JDBC中的Connection混淆。
7,Session
會話,一次持久有效狀態的訪問,由鏈接創建,是具體操作消息的基礎支撐。
8,Queue & Topic
Queue是隊列目的地,Topic是主題目的地。都是Destination的子接口。
Queue特點:隊列中的消息,默認只能由唯一的一個消費者處理,一旦處理消息刪除。
Topic特點:主題中的消息,會發送給所有消費者同時處理,只有在消息可以重複處理的業務場景中可以使用。
9,PTP
Point to Point,點對點消息模型,就是基於Queue實現的消息處理方式。
10,PUB & SUB
publish & Sububscribe,消息的發佈訂閱模型,是基於Topic實現的消息處理方式。
ActiveMQ有兩種信息傳遞方式:queue 和 topic。
queue 是隊列,Point to Point(P2P),一對一通信。生產者將消息發送到 broker ,消費者從 broker獲取信息,生產者和消費者通過指定的 queueName 名稱標識往哪個隊列插入消息 / 從哪個隊列獲取信息。
topic 是主題,(Pub/Sub),發佈和訂閱。一對多通信。生產者將消息發送到 broker,broker 將消息推送給 監聽該topic 的消費者。
注意:queue 是 生產者 插入,消費者獲取,都是客戶端主動。topic 是生產者發佈,broker 推送,並不是消費者主動獲取。
①如果 topic 的生產者發佈了消息到 broker,此時沒有 consumer 監聽該topic,broker 不知道將消息推送到哪裏,此時broker也不會保存消息,而是將消息丟棄。topic類型的消息沒有持久化(有異議,明天查證),當沒有消費者在監聽,消息便丟失了。
②queue類型的消息,支持持久化。當生產者 發送消息到broker的隊列中,broker首先接收消息,並持久化消息,然後回送確認ACK到生產者,表示接收成功。此時即使沒有消費者,也沒有關係,等消費者上線之後,依然可以獲取到之前的消息。
ActiveMQ的持久化有三種方式,KaHaDB、jdbc數據庫、LevelDB。
KaHaDB:ActiveMQ默認的持久化方式,通過在本地的文件系統保存數據內容來保證數據不丟失。
jdbc數據庫:通過將數據內容保存到數據庫,來保證數據的不丟失。
LevelDB: Google推出的一種文件系統,但已不被ActiveMQ推薦。主要原因爲沒有精力適配。
相關說明:https://blog.csdn.net/qq447995687/article/details/93924145
所以在做持久化的時候,建議使用 KaHaDB或者使用數據庫。個人感覺如果數據格式比較簡單,可以使用文件系統,省心。
測試代碼:
Queue 生產者:
public void testMQProducerQueue() throws Exception{
//1、創建工廠連接對象,需要制定ip和端口號
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
//2、使用連接工廠創建一個連接對象
Connection connection = connectionFactory.createConnection();
//3、開啓連接
connection.start();
//4、使用連接對象創建會話(session)對象
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5、使用會話對象創建目標對象,包含queue和topic(一對一和一對多)
Queue queue = session.createQueue("test-queue");
//6、使用會話對象創建生產者對象
MessageProducer producer = session.createProducer(queue);
//7、使用會話對象創建一個消息對象
TextMessage textMessage = session.createTextMessage("hello!test-queue");
//8、發送消息
producer.send(textMessage);
//9、關閉資源
producer.close();
session.close();
connection.close();
}
Queue 消費者:
public void TestMQConsumerQueue() throws Exception{
//1、創建工廠連接對象,需要制定ip和端口號
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
//2、使用連接工廠創建一個連接對象
Connection connection = connectionFactory.createConnection();
//3、開啓連接
connection.start();
//4、使用連接對象創建會話(session)對象
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5、使用會話對象創建目標對象,包含queue和topic(一對一和一對多)
Queue queue = session.createQueue("test-queue");
//6、使用會話對象創建生產者對象
MessageConsumer consumer = session.createConsumer(queue);
//7、向consumer對象中設置一個messageListener對象,用來接收消息
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
if(message instanceof TextMessage){
TextMessage textMessage = (TextMessage)message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
//8、程序等待接收用戶消息
System.in.read();
//9、關閉資源
consumer.close();
session.close();
connection.close();
}
Topic 生產者:
public void TestTopicProducer() throws Exception{
//1、創建工廠連接對象,需要制定ip和端口號
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
//2、使用連接工廠創建一個連接對象
Connection connection = connectionFactory.createConnection();
//3、開啓連接
connection.start();
//4、使用連接對象創建會話(session)對象
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5、使用會話對象創建目標對象,包含queue和topic(一對一和一對多)
Topic topic = session.createTopic("test-topic");
//6、使用會話對象創建生產者對象
MessageProducer producer = session.createProducer(topic);
//7、使用會話對象創建一個消息對象
TextMessage textMessage = session.createTextMessage("hello!test-topic");
//8、發送消息
producer.send(textMessage);
//9、關閉資源
producer.close();
session.close();
connection.close();
}
Topic消費者:
public void TestTopicConsumer() throws Exception{
//1、創建工廠連接對象,需要制定ip和端口號
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.156.44:61616");
//2、使用連接工廠創建一個連接對象
Connection connection = connectionFactory.createConnection();
//3、開啓連接
connection.start();
//4、使用連接對象創建會話(session)對象
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//5、使用會話對象創建目標對象,包含queue和topic(一對一和一對多)
Topic topic = session.createTopic("test-topic");
//6、使用會話對象創建生產者對象
MessageConsumer consumer = session.createConsumer(topic);
//7、向consumer對象中設置一個messageListener對象,用來接收消息
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
if(message instanceof TextMessage){
TextMessage textMessage = (TextMessage)message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
//8、程序等待接收用戶消息
System.in.read();
//9、關閉資源
consumer.close();
session.close();
connection.close();
}
思考:
生產者發送消息時候,可以指定 該消息的一些屬性:是否持久化、是否是事務提交、同步發送還是異步發送
是否持久化:持久化的信息在mq宕機之後,仍然可以被消費者消費。沒有持久化的信息,MQ宕機,消息就沒有了。
是否是事務提交:事務提交支持多條消息一起發送,但是我測試發現多發一條,性能降低很多,網上也沒有事務的例子。
同步or異步:同步發送,生產者等待broker回送確認消息,會阻塞。異步發送,程序繼續執行,broker接收成功,會回調函數同時生產者接收成。壓測數據表示:同步非常慢,異步非常快,所以建議使用異步,但是要注意重新實現回調函數,如果發送失敗了,需要重新發送或者暫時持久化到本地。異步方式在 url 的末尾添加 ?useAsyncSend=true 即可
問:
0. broker收到消息之後,將消息存在哪裏?有沒有持久化有沒有區別?
1. broker 收到消息之後,如何將消息持久化到 KaHaDB 如何持久化到 數據庫?
2. ActiveMQ啓動的時候,如何讀取配置信息,如何保持與 KaHaDB 和 數據庫的連接?
3. KaHaDB 每個文件內存多大,或者每次多大的時候存一次?
4. MQ宕機之後,queue持久化 和 topic持久化的信息都能被消費者獲取嘛?
關於ActiveMQ壓測
網上的一份代碼:https://blog.csdn.net/truong/article/details/73717713
拿到他的代碼在本地跑了一下,壓測到本地的ActiveMQ。有了個數據結果:
(測試的時候最好,數據量大一點,這樣能穩定點,要是隻有20000條,可能一個瞬發就直接20000條,結束了)
同步 Topic : 400000條,消耗24.37 s ,TPS : 16413
異步Topic : 400000條, 10.515 s , TPS : 38040
同步 Queue: 每秒 20+ ,不知道爲什麼(看了眼控制檯,發現太慢了,就沒測,之前也測到過 200+,很崩潰)
異步 Queue: 400000條, 55.403 s , TPS : 7219
在生產者產生的時候,開啓一個消費者,又測了一下:
所以,異步就是合適的,網上的新手入門一般都是直接寫個同步,執行一遍演示,就完了。可是真正使用的時候,誰會用同步啊,這個速度差距太大了,受網絡影響。
參考文章:
https://blog.csdn.net/liuyuanq123/article/details/79109218
未看:(Topic 的持久化依靠broker保存信息,當 broker宕機之後,數據就沒有了,所以這不能成爲持久化)
https://www.cnblogs.com/xinhuaxuan/p/6105985.html
https://blog.csdn.net/qq_34934864/article/details/78727221