异步投递:
Activemq 支持同步,异步两种发送的模式将消息发送到 broker ,模式的选择对发送延时有巨大的影响。producer 能达到怎样的产出率主要受发送延时的影响,使用异步发送可以显著的提高发送的性能。
Activemq 默认使用异步的发送模式:除非明确指定使用同步发送的方式或者未使用事务的前提下发送持久化的消息,这两种情况都是同步发送的。
异步发送:
它可以最大化 producer 端的发送频率。我们通常在发送消息量比较密集的情况下使用异步发送,它可以很大的提高Producer性能,不过这些也带来了额外的问题,就是需要消耗较多client端内存,同时也会导致broker端性能消耗增加;此外他不能有效的保证消息的成功发送。在useAsyncSend=true的情况下,客户端需要容忍消息丢失的可能。
开启异步发送的三种方式:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616?jms.useAsyncSend=true");
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
connectionFactory.setUseAsyncSend(true);
Connection connection = connectionFactory.createConnection();
((ActiveMQConnection)connection).setUseAsyncSend(true);
异步发送如何确定消息发送成功:
异步发送的场景:生产者设置 useAsyncSend = true,使用producer.send 持续发送消息。由于消息不阻塞,生产者会认为所有发送的消息都会成功发送至mq。如果此时mq宕机,此时生产者内存中未发送的消息都会丢失。
所以,异步的消息,发送成功后,需要一个回调。
具体实现:
ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(jymQueue);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
// 6.通过使用消息生产者生产三条消息发送到mq 队列中去
for (int i = 0; i <= 3; i++){
// 7.创建消息,一个字符串
TextMessage textMessage = session.createTextMessage("jdbc ---" + i);
// 8.通过 producer 发送给mq;
producer.send(textMessage, new AsyncCallback() {
public void onSuccess() {
}
public void onException(JMSException e) {
}
});
}
说明:将MessageProducer 转换成更加细粒度的 ActiveMQMessageProducer ,利用API进行业务上的处理。
同步与异步消息的区别:
同步:send不阻塞就一定发送成功。
异步:需要回收一个回调来判断是否接受成功
延迟投递:
四大属性:
Property name | type | description |
AMQ_SCHEDULED_DELAY | long | 延迟投递的时间 |
AMQ_SCHEDULED_PERIOD | long | 重复投递的时间间隔 |
AMQ_SCHEDULED_REPEAT | int | 重复投递的次数 |
AMQ_SCHEDULED_CRON | String | Cron 表达式 |
具体设置:
xml 开启延时投递
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">
具体实现:
MessageProducer producer = session.createProducer(queue);
long delay = 3*1000; // 延迟三秒
long period = 4*1000; // 每四秒一次
int repeat = 5; // 循环五次
for (int i = 0; i < 3; i++) {
TextMessage textMessage = session.createTextMessage("hello,jym:" + i);
textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,delay);
textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD,period);
textMessage.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT,repeat);
producer.send(textMessage);
}
说明:设置延时的时间参数,mq服务端就会延时发送给消费端。
消息重试机制
具体哪些机制会引起消息重发:
- client 开启事务,但是回滚了。
- client 使用事务,在commit 之前关闭 或者没有 commit
- client 在手动签收的传递模式下,在session 中调用了 recover()
默认每秒重发6次
设置重发次数:
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
redeliveryPolicy.setMaximumRedeliveries(3);
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);
Connection connection = activeMQConnectionFactory.createConnection();
有毒消息:
一个消息被重发超过最大重发次数(默认为6次)时,消费端会给MQ 发送一个 “poison ack” 表示该消息有毒,告诉borker 不要再发了。这个时候borker 会把这个消息放到 DLQ(死信队列).
当消息设置为持久化时,会进入死信队列,也可以指定该消息不进入。
当消息为未持久化时,该消息失败了不会进入死信队列,也可以指定该消息进入。
消息不被重复消费,幂等性调用
消息因为网络的延迟,发送了好多次,出现重复调用。
解决幂等性调用:
将数据存放进redis里,设置消息头,通过消息头为key,每次消费之前 查询一次,如果有消费记录 不让消费了。
学习年限不足,知识过浅,说的不对请见谅。
世界上有10种人,一种是懂二进制的,一种是不懂二进制的。