以前都是看看消息队列的文章,程序里简单的调用一下接口,一直没有详细的搭建,并不了解其中的细节。导致最近项目上使用ActiveMQ,踩到了性能的坑,在网上找各种资料,这里简单记录一下。
由于我使用的是P2P的队列方式,TOPIC类型的没有使用,所以这里只是关于点对点的记述
这个网上的教程很多,找一篇,照着弄就可以了。我这里的环境是简单的一个单点的服务,并没有集群。
由于activeMQ默认是开启消息持久化的,在消息入队以后会把消息持久化到本地数据库里,这个会很大程度的影响入队性能。不过,对消息持久化有要求的功能,还是不能关闭这个配置。
producer发送消息有同步和异步两种模式,可以通过配置文件和代码配置:
apache-activemq-5.9.0\conf\activemq.xml中有如下配置:
这里配置了各种协议,可以增加或修改协议为nio模式。
这样消息入队的性能就有所提升。
这个更坑了,我采用默认模式,居然一秒就能处理百八十个消息,上网翻阅资料,才知道这里,客户端消费消息,有2种模式。
“可优化的ACK”,这是ActiveMQ对于consumer在消息消费时,对消息ACK的优化选项,也是consumer端最重要的优化参数之一,你可以通过如下方式开启:
String brokerUrl = "tcp://localhost:61616?" +
"jms.optimizeAcknowledge=true" +
"&jms.optimizeAcknowledgeTimeOut=30000" +
"&jms.redeliveryPolicy.maximumRedeliveries=6";
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerUrl);
我们需要在brokerUrl指定optimizeACK选项,其中brokerUrl参数选项是全局的,即当前factory下所有的connection/session/consumer都会默认使用这些值
String queueName = "test-queue?customer.prefetchSize";
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination queue = session.createQueue(queueName);
在destinationUri中指定prefetchSize(预获取)选项,也可以加在代码里
ActiveMQPrefetchPolicy prefetchPolicy = connectionFactory.getPrefetchPolicy();
prefetchPolicy.setQueuePrefetch(30);
optimizeAck表示是否开启“优化ACK”,只有在为true的情况下,prefetchSize(下文中将会简写成prefetch)以及optimizeAcknowledgeTimeout参数才会有意义。此处需要注意"optimizeAcknowledgeTimeout"选项只能在brokerUrl中配置。
如果prefetchACK为true,那么prefetch必须大于0;当prefetchACK为false时,你可以指定prefetch为0以及任意大小的正数。不过,当prefetch=0是,表示consumer将使用PULL(拉取)的方式从broker端获取消息,broker端将不会主动push消息给client端,直到client端发送PullCommand时;当prefetch>0时,就开启了broker push模式,此后只要当client端消费且ACK了一定的消息之后,会立即push给client端多条消息。
这就是所谓的拉取与推送模式。
当consumer端使用receive()方法同步获取消息时,prefetch可以为0和任意正值;当prefetch=0时,那么receive()方法将会首先发送一个PULL指令并阻塞,直到broker端返回消息为止,这也意味着消息只能逐个获取(类似于Request<->Response),这也是Activemq中PULL消息模式;当prefetch > 0时,broker端将会批量push给client 一定数量的消息(<= prefetch),client端会把这些消息(unconsumedMessage)放入到本地的队列中,只要此队列有消息,那么receive方法将会立即返回,当一定量的消息ACK之后,broker端会继续批量push消息给client端。
当consumer端使用MessageListener异步获取消息时,这就需要开发设定的prefetch值必须 >=1,即至少为1;在异步消费消息模式中,设定prefetch=0,是相悖的,也将获得一个Exception。
optimizeACK和prefetch配合,将会达成一个高效的消息消费模型:批量获取消息,并“延迟”确认(ACK)。prefetch表达了“批量获取”消息的语义,broker端主动的批量push多条消息给client端,总比client多次发送PULL指令然后broker返回一条消息的方式要优秀很多,它不仅减少了client端在获取消息时阻塞的次数和阻塞的时间,还能够大大的减少网络开支。optimizeACK表达了“延迟确认”的语义(ACK时机),client端在消费消息后暂且不发送ACK,而是把它缓存下来(pendingACK),等到这些消息的条数达到一定阀值时,只需要通过一个ACK指令把它们全部确认;这比对每条消息都逐个确认,在性能上要提高很多。由此可见,prefetch优化了消息传送的性能,optimizeACK优化了消息确认的性能。
如果消息很重要,特别是需要接收到”redelivery“的消息,那么我们需要将optimizeACK=false,prefetchSize=1
至此,只是简单的记述了使用的一些心得,还有很多具体的配置待了解。。。。。。