activemq优化

来源:互联网 发布:壳氏唯切菜板知乎 编辑:程序博客网 时间:2024/06/05 16:20

ActiveMQ在Version 5.13.0+ 版本后,将OpenWire, STOMP, AMQP, MQTT这四种主要协议的端口监听进行了合并,并使用auto关键字进行表示

也就是说,ActiveMQ将监听这一个端口的消息状态,并自动匹配合适的协议格式。配置如下:

<transportConnectors>    <transportConnector name="auto" uri="auto://0.0.0.0:61617?maximumConnections=1000" /></transportConnectors>
如果您不特别指定ActiveMQ的网络监听端口,那么这些端口都将使用BIO网络IO模型。所以为了首先提高单节点的网络吞吐性能,我们需要明确指定Active的网络IO模型,如下所示:
<transportConnectors>      <transportConnector name="nio" uri="nio://0.0.0.0:61618?maximumConnections=1000"/>  </transportConnectors> 
请注意,URI格式头以”nio”开头,表示这个端口使用以TCP协议为基础的NIO网络IO模型,但是这样的设置方式,只能使这个端口支持Openwire协议。那么我们怎么既让这个端口支持NIO网络IO模型,又让它支持多个协议呢?ActiveMQ的服务端设置,允许开发人员使用“+”符号来为端口设置多种特性,如下:

<transportConnector name="stomp+nio" uri="stomp+nio://0.0.0.0:61613?transport.transformer=jms"/>// 表示这个端口使用NIO模型支持Stomp协议<transportConnector name="amqp+ssl" uri="amqp+ssl://localhost:5671"/>// 表示这个端口支持amqp和ssl密文传输
所以如果我们既需要某一个端口支持NIO网络IO模型,又需要它支持多个协议,那么可以进行如下的配置:

<transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61608?maximumConnections=1000" />
另外,如果是为了生产环境进行的配置,那么您至少应该还要配置这个端口支持的最大连接数量、设置每一条消息的最大传输值、设置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" />
==========================================================

ActiveMQ的内存区域来源

<systemUsage>    <systemUsage>        <memoryUsage>            <memoryUsage percentOfJvmHeap="70" />        </memoryUsage>        <storeUsage>            <storeUsage limit="100 gb"/>        </storeUsage>        <tempUsage>            <tempUsage limit="50 gb"/>        </tempUsage>    </systemUsage></systemUsage>

systemUsage:该标记用于设置整个ActiveMQ节点在进程级别的各种“容量”的设置情况。其中可设置的属性包括:sendFailIfNoSpaceAfterTimeout,当ActiveMQ收到一条消息时,如果ActiveMQ这时已经没有多余“容量”了,那么就会等待一段时间(这里设置的毫秒数),如果超过这个等待时间ActiveMQ仍然没有可用的容量,那么就拒绝接收这条消息并在消息的发送端抛出javax.jms.ResourceAllocationException异常;sendFailIfNoSpace,当ActiveMQ收到一条消息时,如果ActiveMQ这时已经没有多余“容量”了,就直接拒绝这条消息(不用等待一段时间),并在消息的发送端抛出javax.jms.ResourceAllocationException异常。

memoryUsage:该子标记设置整个ActiveMQ节点的“可用内存限制”。这个值不能超过上文中您设置的JVM maxmemory的值。其中的percentOfJvmHeap属性表示使用“百分数值”进行设置,除了这个属性以外,您还可以使用limit属性进行固定容量授权,例如:limit=”1000 mb”。这些内存容量将供所有队列使用。

storeUsage:该标记设置整个ActiveMQ节点,用于存储“持久化消息”的“可用磁盘空间”。该子标记的limit属性必须要进行设置。在使用后续介绍的KahaDB方案或者LevelDB方案进行PERSISTENT Message持久化存储时,这个storeUsage属性都会起作用;但是如果使用数据库存储方案,这个属性就不会起作用了。

tempUsage:在ActiveMQ 5.X+ 版本中,一旦ActiveMQ服务节点存储的消息达到了memoryUsage的限制,NON_PERSISTENT Message就会被转储到 temp store区域。虽然我们说过NON_PERSISTENT Message不进行持久化存储,但是ActiveMQ为了防止“数据洪峰”出现时NON_PERSISTENT Message大量堆积致使内存耗尽的情况出现,还是会将NON_PERSISTENT Message写入到磁盘的临时区域——temp store。这个子标记就是为了设置这个temp store区域的“可用磁盘空间限制”。最后提醒各位读者storeUsage和tempUsage并不是“最大可用空间”,而是一个阀值

====================================================

生产者策略:Send

消息生产者发送的消息主要分为两种类型:发送PERSISTENT Meaage和发送NON_PERSISTENT Message。默认情况下,ActiveMQ服务端认为生产者端发送的是PERSISTENT Message

所以如果要发送NON_PERSISTENT Message,那么生产者端就要明确指定

MessageProducer sender = session.createProducer(sendQueue);sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
发送NON_PERSISTENT Message时,消息发送方默认使用异步方式:即是说消息发送后发送方不会等待NON_PERSISTENT Message在服务端的任何回执

事务

以下代码示例了如何在生产者端使用事务发送消息:

......//进行连接connection = connectionFactory.createQueueConnection();connection.start();//建立会话(设置一个带有事务特性的会话)session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);//建立queue(当然如果有了就不会重复建立)Queue sendQueue = session.createQueue("/test");//建立消息发送者对象MessageProducer sender = session.createProducer(sendQueue);//发送(JMS是支持事务的)for(int index = 0 ; index < 10 ; index++) {    TextMessage outMessage = session.createTextMessage();    outMessage.setText("这是发送的消息内容-------------------" + index);    // 无论是NON_PERSISTENT message还是PERSISTENT message    // 都要在commit后才能真正的入队    if(index % 2 == 0) {        sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);    } else {        sender.setDeliveryMode(DeliveryMode.PERSISTENT);    }    // 没有commit的消息,也是要先发送给服务端的    sender.send(outMessage);}session.commit();......
在“connection.createSession”这个方法中一共有两个参数(这句代码在上文中已经出现过多次)。第一个布尔型参数很好理解,就是标示这个连接会话是否启动事务;第二个整型参数标示了消息消费者的“应答模型”

消费者策略:Dispatch Async

比起消息生产者来说消息消费者的性能更能影响ActiveMQ系统的整体性能,因为要成功完成一条消息的处理,它的工作要远远多于消息生产者。

默认情况下ActiveMQ服务端采用异步方式向客户端推送消息

消费者关键策略中,需要重点讨论的是消费者“预取数量”——prefetchSize。

ActiveMQ系统中,默认的策略是ActiveMQ服务端一旦有消息,就主动按照设置的规则推送给当前活动的消费者其中每次推送都有一定的数量限制,这个限制值就是prefetchSize。针对Queue工作模型的队列和Topic工作模型的队列,ActiveMQ有不同的默认“预取数量”;针对NON_PERSISTENT Message和PERSISTENT Message,ActiveMQ也有不同的默认“预取数量”:

  • PERSISTENT Message—Queue:prefetchSize=1000
  • NON_PERSISTENT Message—Queue:prefetchSize=1000
  • PERSISTENT Message—Topic:prefetchSize=100
  • NON_PERSISTENT Message—Topic:prefetchSize=32766
ActiveMQ中设置的各种默认预取数量一般情况下不需要进行改变。如果您使用默认的异步方式从服务器端推送消息到消费者端,且您对消费者端的性能有足够的信心,可以加大预取数量的限制。但是非必要情况下,请不要设置prefetchSize=1,因为这样就是一条一条的取数据;也不要设置为prefetchSize=0,因为这将导致关闭服务器端的推送机制,改为客户端主动请求

事务

JMS规范除了为消息生产者端提供事务支持以外,还为消费服务端准备了事务的支持。您可以通过在消费者端操作事务的commit和rollback方法,向服务器告知一组消息是否处理完成。采用事务的意义在于,一组消息要么被全部处理并确认成功,要么全部被回滚并重新处理

......//建立会话(采用commit方式确认一批消息处理完毕)session = connection.createSession(true, Session.SESSION_TRANSACTED);//建立Queue(当然如果有了就不会重复建立)sendQueue = session.createQueue("/test");//建立消息发送者对象MessageConsumer consumer = session.createConsumer(sendQueue);consumer.setMessageListener(new MyMessageListener(session));......class MyMessageListener implements MessageListener {    private int number = 0;    /**     * 会话     */    private Session session;    public MyMessageListener(Session session) {        this.session = session;    }    @Override    public void onMessage(Message message) {        // 打印这条消息        System.out.println("Message = " + message);        // 如果条件成立,就向服务器确认这批消息处理成功        // 服务器将从队列中删除这些消息        if(number++ % 3 == 0) {            try {                this.session.commit();            } catch (JMSException e) {                e.printStackTrace(System.out);            }        }    }}
以上代码演示的是消费者通过事务commit的方式,向服务器确认一批消息正常处理完成的方式。请注意代码示例中的“session = connection.createSession(true, Session.SESSION_TRANSACTED);”语句。第一个参数表示连接会话启用事务支持;第二个参数表示使用commit或者rollback的方式进行向服务器应答。

但是消息处理失败后,不断的重发消息肯定不是一个最好的处理办法:如果一条消息被不断的处理失败,那么最可能的情况就是这条消息承载的业务内容本身就有问题。那么无论重发多少次,这条消息还是会处理失败。为了解决这个问题,ActiveMQ中引入了“死信队列”(Dead Letter Queue)的概念。即一条消息再被重发了多次后(默认为重发6次redeliveryCounter==6),将会被ActiveMQ移入“死信队列”。默认情况下“死信队列”只接受PERSISTENT Message,如果NON_PERSISTENT Message超过了重发上限,将直接被删除.






0 0
原创粉丝点击