學習筆記--Java訊息中介軟體

來源:互聯網
上載者:User

標籤:set   list   上下文   接收   try   處理   叢集配置   int   學習筆記   

#### 訊息中介軟體

訊息中介軟體:關注於資料的發送和接受,利用高效可靠的非同步訊息傳遞機制整合分布式系統
JMS:JavaMessage Service,Java平台中關於面向訊息中介軟體的API
AMQP:提供整合通訊服務的應用程式層標準協議
常見訊息中介軟體
ActiveMQ
RabbitMQ
Kafka
JMS規範
提供者:實現JMS規範的訊息中介軟體伺服器
用戶端:發送或接受訊息的應用程式
生產者/發行者:建立並發送訊息的用戶端
消費者/訂閱者:接收並處理訊息的用戶端
訊息:應用程式之間傳遞的資料內容
訊息模式:在用戶端之間傳遞訊息的方式,JMS中定義了主題和隊列兩種模式
JMS訊息模式
隊列模型:

  • 用戶端包括生產者和消費者
  • 訊息只能被一個消費者消費
  • 隨時消費

主題模型:

  • 用戶端包括髮布者和訂閱者
  • 訊息能被所有訂閱者消費
  • 消費者不能消費訂閱之前就發送到主題中的訊息

JMS編碼介面:

  • ConnectionFactory:用於建立串連到訊息中介軟體的串連工廠
  • Connection:代表了應用程式和Message Service器之間的通訊鏈路
  • Destination:訊息發布和接收的地點,包括隊列和主題
  • Session:表示一個單線程的上下文,用於發送和接收訊息
  • MessageConsumer:由會話建立,用於接收發送到目標的訊息
  • MessageProducer:由會話建立,用於發送訊息到目標
  • Message:在消費者和生產者之間傳送的對象,包括訊息頭,一組訊息屬性,一個訊息體

使用ActiveMQ
隊列模型
producer

        //1. 建立ConnectionFactory        ConnectionFactory factory = new ActiveMQConnectionFactory(url);        //2. 建立Connection        Connection connection = factory.createConnection();        //3. 啟動Connection        connection.start();        //4. 建立Session        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        //5. 建立Destination        Destination destination = session.createQueue(queueName);        //6. 建立MessageProducer        MessageProducer producer = session.createProducer(destination);        for (int i = 0; i < 100; i++) {            //7. 建立訊息            TextMessage message = session.createTextMessage("test" + i);            //8. 發布訊息            producer.send(message);            System.out.println("發送訊息: " + message.getText());        }        //9. 關閉串連        connection.close();

consumer

        //1. 建立ConnectionFactory        ConnectionFactory factory = new ActiveMQConnectionFactory(url);        //2. 建立Connection        Connection connection = factory.createConnection();        //3. 啟動Connection        connection.start();        //4. 建立Session        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        //5. 建立Destination        Destination destination = session.createQueue(queueName);        //6. 建立MessageConsumer        MessageConsumer consumer = session.createConsumer(destination);        //7. 建立訊息監聽器        consumer.setMessageListener(new MessageListener() {            @Override            public void onMessage(Message message) {                TextMessage textMessage = (TextMessage) message;                try {                    System.out.println("接收訊息: " + textMessage.getText());                } catch (JMSException e) {                    e.printStackTrace();                }            }        });        //9. 關閉串連(訊息監聽非同步執行,需程式全部運行結束才能關閉串連)//        connection.close();

主題模型
producer

        //1. 建立ConnectionFactory        ConnectionFactory factory = new ActiveMQConnectionFactory(url);        //2. 建立Connection        Connection connection = factory.createConnection();        //3. 啟動Connection        connection.start();        //4. 建立Session        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        //5. 建立Destination        Destination destination = session.createTopic(topicName);        //6. 建立MessageProducer        MessageProducer producer = session.createProducer(destination);        for (int i = 0; i < 100; i++) {            //7. 建立訊息            TextMessage message = session.createTextMessage("test" + i);            //8. 發布訊息            producer.send(message);            System.out.println("發送訊息: " + message.getText());        }                //9. 關閉串連        connection.close();

consumer

        //1. 建立ConnectionFactory        ConnectionFactory factory = new ActiveMQConnectionFactory(url);        //2. 建立Connection        Connection connection = factory.createConnection();        //3. 啟動Connection        connection.start();        //4. 建立Session        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);        //5. 建立Destination        Destination destination = session.createTopic(topicName);        //6. 建立MessageConsumer        MessageConsumer consumer = session.createConsumer(destination);        //7. 建立訊息監聽器        consumer.setMessageListener(new MessageListener() {            @Override            public void onMessage(Message message) {                TextMessage textMessage = (TextMessage) message;                try {                    System.out.println("接收訊息: " + textMessage.getText());                } catch (JMSException e) {                    e.printStackTrace();                }            }        });        //9. 關閉串連(訊息監聽非同步執行,需程式全部運行結束才能關閉串連)//        connection.close();

spring jms

  • ConnectionFactory 用於管理串連的串連工廠
  • 由spring提供
  • SingleConnectionFactory和CachingConnectionFactory
  • JmsTemplate 用於發送和接收訊息的模板類
  • 由spring提供,在容器中註冊就可以使用
  • 安全執行緒
  • MessageListener 訊息監聽器
  • 實現一個onMessage方法,只接收一個Message參數

spring使用jms樣本
common.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xmlns:context="http://www.springframework.org/schema/context"      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <context:annotation-config />    <!-- ActiveMQ為我們提供的ConnectionFactory -->    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">        <property name="brokerURL" value="tcp://127.0.0.1:61616" />    </bean>    <!-- spring jms為我們提供串連池 -->    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">        <property name="targetConnectionFactory" ref="targetConnectionFactory" />    </bean>    <!-- 一個隊列目的地,點對點的 -->    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">        <constructor-arg value="queue" />    </bean>    <!-- 一個主題目的地,發布訂閱訊息 -->    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">        <constructor-arg value="topic"/>    </bean></beans>

producer.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">    <import resource="common.xml" />    <!-- 配置JmsTemplate,用於發送訊息-->    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">        <property name="connectionFactory" ref="connectionFactory" />    </bean>    <bean class="com.qyluo.jms.spring.producer.ProducerServiceImpl" /></beans>

cosumer.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">    <!-- 匯入公用配置 -->    <import resource="common.xml" />    <!-- 配置訊息監聽器 -->    <bean id="consumerMessageListener" class="com.qyluo.jms.spring.consumer.ConsumerMessageListener" />    <!-- 配置訊息監聽容器 -->    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">        <property name="connectionFactory" ref="connectionFactory" />        <property name="destination" ref="topicDestination"/>        <property name="messageListener" ref="consumerMessageListener"/>    </bean></beans>

ProducerServiceImpl

public class ProducerServiceImpl implements ProducerService {    @Autowired    JmsTemplate jmsTemplate;    @Resource(name = "topicDestination")    Destination destination;    @Override    public void sendMessage(final String message) {        //使用JmsTemplate發送訊息        jmsTemplate.send(destination, new MessageCreator() {            //建立一個訊息            @Override            public Message createMessage(Session session) throws JMSException {                TextMessage textMessage = session.createTextMessage(message);                return textMessage;            }        });        System.out.println("發送訊息: " + message);    }}

AppProducer

public class AppProducer {    public static void main(String[] args) {        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("producer.xml");        ProducerService service = context.getBean(ProducerService.class);        for (int i = 0; i < 100; i++) {            service.sendMessage("text" + i);        }        context.close();    }}

ConsumerMessageListener
public class ConsumerMessageListener implements MessageListener { @Override public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; try { System.out.println("接收訊息: " + textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } }

AppConsumer

public class AppConsumer {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");    }}
ActiveMQ叢集

叢集方式

  • 用戶端叢集:多個消費者消費同一個隊列
  • Broker clusters:多個Broker之間同步訊息
  • Master Slave:實現高可用

ActiveMQ失效轉移(failover)
允許當其中一台Message Service器宕機時,用戶端在傳輸層上重新串連到其它Message Service器
文法:failover:(uri1,...,uriN)?transportOptions
transportOptions參數說明

  • randomize 預設為true,表示在URI列表中選擇URI串連時是否採用隨機策略
  • initialReconnectDelay 預設為10,單位毫秒,表示第一次嘗試重新串連之間等待的時間
  • maxReconnectDelay 預設為30000,單位毫秒,最長重連的時間間隔

Broker Cluster叢集配置
NetworkConnector(網路連接器):ActiveMQ伺服器之間的網路通訊方式
分為靜態連接器和動態連接器
靜態連接器:

<networkConnectors>    <networkConnector uri="static:(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)"/></networkConnectors>

動態連接器:

<networkConnectors>    <networkConnector uri="multicast://default"/></networkConnectors><transportConnectors>    <transportConnector uri="tcp://localhost:0" discoverUri="multicast://default"/></transportConnectors>

Master/Slave叢集配置
ActiveMQ Master Slave叢集方案

  • Share nothing storage master/slave (已淘汰,5.8+後移除)
  • Shared storage master/slave 共用儲存
  • Replicated LevelDB Store 基於複製的LevelDB Store

兩種叢集方式對比
方式 | 高可用 | 負載平衡 |
--|----------|--------------|
Master/Slave | 是 | 否 |
Broker Cluster | 否 | 是 |

三台伺服器的完美叢集方案
Node A和Node B做訊息同步,Node A和Node C做訊息同步,Node B和Node C做Master / Slave對資源進行持久化

伺服器 服務連接埠 管理連接埠 儲存 網路連接器 用途
Node-A 61616 8161 - Node-B、Node-C 消費者
Node-B 61617 8162 /share_file/kahadb Node-A 生產者,消費者
Node-C 61618 8163 /share_file/kahadb Node-A 生產者,消費者
企業系統中的最佳實務

實際業務情境特點

  • 子業務系統都有叢集的可能性
  • 同一個訊息會廣播給關注該類訊息的所有子業務系統
  • 同一類訊息在叢集中被負載消費
  • 業務的發生和訊息的發布最終一致性

使用ActiveMQ的虛擬主題解決方案

  • 發行者:將訊息發布到一個主題中,主題名以VirtualTopic開頭,如VirtualTopic.TEST
  • 消費者:從隊列中擷取訊息,在隊列名中表明自己身份,如Consumer.A.VirtualTopic.TEST

使用JMS中XA系列介面保證強一致性

  • 引入分散式交易
  • 要求業務操作必須支援XA協議

使用訊息表的本地事務解決方案

使用記憶體日誌的解決方案

基於訊息機制的事件匯流排
事件驅動架構

RabbitMQ

RabbitMQ:使用交換器綁定到隊列

  • 建立ConnectionFactory
  • 建立Connection
  • 建立Channel
  • 定義Exchange,類型I必須為fanout
  • 定義Queue並且綁定隊列
Kafka

Kafka使用group.id分組消費者

  • 配置訊息者參數group.id相同時對訊息進行負載處理
  • 設定管理員partitions參數,控制同一個group.id下的consumer數量小於partitions
  • kafka只保證同一個group.id下的訊息是有序的

學習筆記--Java訊息中介軟體

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.