• ActiveMQ——NIO传输协议及其性能优化(采用Auto+NIO传输模式)


    注意:在更改传输协议之前,必须保证ActiveMQ没有运行!

    简介
    NIO Transport与常规TCP传输非常相似。不同之处在于它是使用NIO API实现的,它可以帮助提高性能和可扩展性。NIO仅是服务器端传输选项。尝试在客户端使用它将实例化常规TCP传输。

    要从TCP切换到NIO,只需更改URI的方案部分。这是在代理的XML配置文件中定义的示例:

    <broker>
    ...
    <transportConnectors>
    <transportConnector name="nio" uri="nio://0.0.0.0:61616"/>
    </<transportConnectors>
    ...
    </broker>
    注意:如果不特别指定ActiveMQ的网络监听端口,那么这些端口都将使用BIO网络IO模型(OpenWire、STOMP、AMQPS……)。所以为了首先提高单节点的网络吞吐性能,需要明确指定Active的网络IO模型。如下所示,URL格式头以“你开头”,表示这个端口使用以TCP协议为基础的NIO网络IO模型:

     

    适合使用NIO协议的场景:

    可能有大量的Client去连接到Broker上,一般情况下,大量的Client去连接Broker是被操作系统的线程所限制的。因此,NIO的实现比TCP需要更少的线程去运行,所以建议使用NIO协议
    可能对于Broker有一个很迟钝的网络传输,NIO比TCP提供更好的性能。
    配置语法

    nio://hostname:port?key=value
    配置选项与TCP传输相同。

    注意:原始NIO传输是使用OpenWire协议的tcp传输的替代品。其他网络协议,如AMQP,MQTT,Stomp等也有自己的NIO传输实现。它通常通过在协议前缀中添加“+ nio”后缀来配置,例如

    mqtt+nio://localhost:1883
    所有协议特定配置也应适用于NIO版本的传输。

    实例(采用发布/订阅模式,Topic主题)
    1、更改 activemq.xml配置文件,在<transportConnectors>标签中添加,同时注释掉tcpURL:

    <transportConnector name="nio" uri="nio://localhost:61618?trace=true"/>


    2、配置Spring文件,将连接URL更改为NIO,注意端口号改为61618

     

    <?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"
    xmlns:jms="http://www.springframework.org/schema/jms"
    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
    http://www.springframework.org/schema/jms
    http://www.springframework.org/schema/jms/spring-jms.xsd
    ">

    <!--配置包自动扫描-->
    <context:component-scan base-package="com.hern.avtivemq"/>

    <!--配置自动注解-->
    <context:annotation-config></context:annotation-config>

    <!--配置生产者-->
    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
    <!-- ActiveMq连接工厂 -->
    <property name="connectionFactory">
    <!--真正可以生产Connection的ConnectionFactory,由对应的JMS服务厂商提供-->
    <bean class="org.apache.activemq.ActiveMQConnectionFactory">
    <!--配置ActiveMQ的Broker连接URL-->
    <property name="brokerURL" value="nio://127.0.0.1:61618"/>
    </bean>
    </property>
    <!--最大连接数-->
    <property name="maxConnections" value="100"/>
    </bean>

    <!--配置队列Queue-->
    <bean id="activeMQQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg index="0" value="spring-active-queue"/>
    </bean>

    <!--配置主题Topic-->
    <bean id="activeMQTopic" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg index="0" value="spring-active-topic"/>
    </bean>

    <!--Spring提供的JMS工具类,它可以进行消息发送、接收等-->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="defaultDestination" ref="activeMQTopic"/>
    <!--<property name="defaultDestination" ref="activeMQQueue"/>-->
    <property name="messageConverter">
    <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
    </property>
    </bean>

    <!--配置监听-->
    <bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="destination" ref="activeMQTopic"/>
    <!--引用自己的监听器-->
    <property name="messageListener" ref="myMessageListener"/>
    <!--单条消息确认-->
    <property name="sessionAcknowledgeMode" value="4"/>
    </bean>
    </beans>
    3、生成者

    package com.hern.avtivemq;

    import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.core.MessageCreator;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;

    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.Session;
    import javax.jms.TextMessage;

    /*
    * 消息生产者
    * */
    @Service
    public class SpringMQ_Produce {

    @Autowired
    private JmsTemplate jmsTemplate;

    public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");

    SpringMQ_Produce springMQ_produce = (SpringMQ_Produce) applicationContext.getBean("springMQ_Produce");

    //发送消息
    springMQ_produce.jmsTemplate.send(session -> {
    TextMessage textMessage = session.createTextMessage("---Spring整合ActiveMQ---");
    System.out.println("发送的消息内容是:" + textMessage.getText());
    return textMessage;
    });

    System.out.println("发送结束");
    }
    }
    4、消费者

    package com.hern.avtivemq;

    import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.stereotype.Service;

    /*
    * 消息消费者
    * */
    @Service
    public class SpringMQ_Consume {

    @Autowired
    private JmsTemplate jmsTemplate;

    public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");

    SpringMQ_Consume springMQ_consume = (SpringMQ_Consume) applicationContext.getBean("springMQ_Consume");

    //接收消息
    String result = (String) springMQ_consume.jmsTemplate.receiveAndConvert();

    System.out.println("接收的消息是:" + result);
    }
    }
    5、监听器

    package com.hern.avtivemq;

    import org.springframework.stereotype.Component;

    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.TextMessage;

    @Component("myMessageListener")
    public class MyMessageListener implements MessageListener {
    @Override
    public void onMessage(Message message) {
    if (message != null && message instanceof TextMessage){
    TextMessage textMessage = (TextMessage) message;
    try {
    System.out.println("监听器接受内容是:" + textMessage.getText());
    } catch (JMSException e) {
    e.printStackTrace();
    }
    }
    }
    }
    性能优化(采用Auto+NIO传输模式)
    从5.13.0版本开始,ActiveMQ支持wire format协议检测,可以自动检测OpenWire,STOMP,AMQP和MQTT,允许为这4种类型的客户端共享一个传输。要通过NIO TCP连接配置ActiveMQ自动wire format检测,使用 auto+nio传输前缀。

    AUTO传输选项可以设置的一些配置选项:

    参数名称 默认值 描述
    protocolDetectionTimeOut 30000 连接超时前的时间(以毫秒为单位)。这类似于maxInactivityDuration。如果客户端建立连接但没有为要检测的协议发送数据或足够的数据,则线程将等待更多数据通过套接字进入。如果代理在一段时间后未完成协议初始化,则会让代理终止连接。默认值为30秒。将默认值设置为<= 0以禁用此功能。
    maxConnectionThreadPoolSize MAX_INT 此选项允许配置处理连接尝试的线程池的最大大小。如果有许多不同的客户端同时尝试连接,则降低此数字可以帮助防止代理程序耗尽线程。默认情况下,它通过设置为MAX_INT来关闭
    Wire Formats配置

    OpenWire是ActiveMQ使用的默认Wire Formats。它为高速消息传递提供了高效的二进制格式。可以在JMS客户端的连接URI字符串或Brokers传输绑定URI上配置OpenWire选项。

    参数前缀 描述
    wireFormat. 将选项应用于所有wireFormat.
    wireFormat.default. 将选项应用于OpenWire的默认格式
    wireFormat.stomp. 将选项应用于STOMP有线格式
    wireFormat.amqp. 将选项应用于AMQP有线格式
    wireFormat.mqtt. 将选项应用于MQTT有线格式
    配置启用的Wire协议

    默认情况下,所有wire协议都可用。这可以配置为仅通过设置属性auto来启用某些格式.protocols.

    值 描述
    default 启用OpenWire
    amqp 启用AMQP格式
    stomp 启用S​​TOMP格式
    mqtt 启用MQTT格式
    仅显示启用OpenWire和STOMP的示例:

    <transportConnector name="auto" uri="auto://localhost:5671?auto.protocols=default,stomp"/>
    1、更改 activemq.xml配置文件,在<transportConnectors>标签中添加,这里额外设置NIO使用的线程池核心工作线程数和最大工作线程数(若以前配置了NIO传输,需要将其注释掉):

    <transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61608?maximumConnections=1000&amp;
    wireFormat.maxFrameSize=104857600&amp;
    org.apache.activemq.transport.nio.SelectorManager.corePoolSize=20&amp;
    org.apache.activemq.transport.nio.SelectorManager.maximumPoolSize=50" />


    2、配置Spring文件,将连接URL更改为NIO,注意端口号改为61608:

    <?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"
    xmlns:jms="http://www.springframework.org/schema/jms"
    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
    http://www.springframework.org/schema/jms
    http://www.springframework.org/schema/jms/spring-jms.xsd
    ">

    <!--配置包自动扫描-->
    <context:component-scan base-package="com.hern.avtivemq"/>

    <!--配置自动注解-->
    <context:annotation-config></context:annotation-config>

    <!--配置生产者-->
    <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
    <!-- ActiveMq连接工厂 -->
    <property name="connectionFactory">
    <!--真正可以生产Connection的ConnectionFactory,由对应的JMS服务厂商提供-->
    <bean class="org.apache.activemq.ActiveMQConnectionFactory">
    <!--配置ActiveMQ的Broker连接URL-->
    <property name="brokerURL" value="nio://127.0.0.1:61608"/>
    </bean>
    </property>
    <!--最大连接数-->
    <property name="maxConnections" value="100"/>
    </bean>

    <!--配置队列Queue-->
    <bean id="activeMQQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg index="0" value="spring-active-queue"/>
    </bean>

    <!--配置主题Topic-->
    <bean id="activeMQTopic" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg index="0" value="spring-active-topic"/>
    </bean>

    <!--Spring提供的JMS工具类,它可以进行消息发送、接收等-->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="defaultDestination" ref="activeMQTopic"/>
    <!--<property name="defaultDestination" ref="activeMQQueue"/>-->
    <property name="messageConverter">
    <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
    </property>
    </bean>

    <!--配置监听-->
    <bean id="defaultMessageListenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="pooledConnectionFactory"/>
    <property name="destination" ref="activeMQTopic"/>
    <!--引用自己的监听器-->
    <property name="messageListener" ref="myMessageListener"/>
    <!--单条消息确认-->
    <property name="sessionAcknowledgeMode" value="4"/>
    </bean>
    </beans>
    3、生成者

    package com.hern.avtivemq;

    import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.core.MessageCreator;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;

    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.Session;
    import javax.jms.TextMessage;

    /*
    * 消息生产者
    * */
    @Service
    public class SpringMQ_Produce {

    @Autowired
    private JmsTemplate jmsTemplate;

    public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");

    SpringMQ_Produce springMQ_produce = (SpringMQ_Produce) applicationContext.getBean("springMQ_Produce");

    //发送消息
    springMQ_produce.jmsTemplate.send(session -> {
    TextMessage textMessage = session.createTextMessage("---Spring整合ActiveMQ---");
    System.out.println("发送的消息内容是:" + textMessage.getText());
    return textMessage;
    });

    System.out.println("发送结束");
    }
    }
    4、消费者

    package com.hern.avtivemq;

    import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.jms.core.JmsTemplate;
    import org.springframework.stereotype.Service;

    /*
    * 消息消费者
    * */
    @Service
    public class SpringMQ_Consume {

    @Autowired
    private JmsTemplate jmsTemplate;

    public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("application-configure.xml");

    SpringMQ_Consume springMQ_consume = (SpringMQ_Consume) applicationContext.getBean("springMQ_Consume");

    //接收消息
    String result = (String) springMQ_consume.jmsTemplate.receiveAndConvert();

    System.out.println("接收的消息是:" + result);
    }
    }
    5、监听器

    package com.hern.avtivemq;

    import org.springframework.stereotype.Component;

    import javax.jms.JMSException;
    import javax.jms.Message;
    import javax.jms.MessageListener;
    import javax.jms.TextMessage;

    @Component("myMessageListener")
    public class MyMessageListener implements MessageListener {
    @Override
    public void onMessage(Message message) {
    if (message != null && message instanceof TextMessage){
    TextMessage textMessage = (TextMessage) message;
    try {
    System.out.println("监听器接受内容是:" + textMessage.getText());
    } catch (JMSException e) {
    e.printStackTrace();
    }
    }
    }
    }
    ————————————————
    版权声明:本文为CSDN博主「Hern(宋兆恒)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_36761831/article/details/99093475

  • 相关阅读:
    el自定义函数库
    DOM4J
    【转载】SqlServer日期时间函数
    【原创】C#认识/理解/运用 StreamReader,StreamWriter,StringReader,StreamWriter
    【原创】C#认识/理解/运用 FileStream
    【原创】C#操作XML(带命名空间)
    【原创】ASP.NET MVC3使用html编辑器(kindeditor)
    【原创】ASP.NET MVC3 从零开始一步步构建Web
    【转载】MVC使用jqGrid
    【原创】C#使用HttpWebRequest,HttpWebResponse
  • 原文地址:https://www.cnblogs.com/telwanggs/p/15002269.html
Copyright © 2020-2023  润新知