【ActiveMQ】相關

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

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章