ActiveMQ高级特性

引入消息队列之后该如何保证其高可用性

zookeeper+replicated-levelDB-Store的主从集群

异步投递 Async Sends

对于一个Slow Consumer,使用同步发送消息可能会出现Producer堵塞等情况,慢消费者适合使用异步发送--------activeMQConnectionFactory.setUseAsyncSend(true)

ActiveMQ默认使用异步发送的模式:除非明确指定使用同步发送的方式或者在未使用事务的前提下发送持久化的消息,这两种情况都是同步发送的。
如果没有使用事务且发送的是持久化的消息,每一次发送都是同步发送的且会阻塞producer知道borker返回一个确认,表示消息已经被安全的持久化到磁盘。确认机制提供消费安全的保证,但同时会阻塞客户端带来很大的延时,很多高性能的应用,允许在失败的情况下有少量数据的丢失。如果满足这个特点,可以使用异步发送来提高生产率,即使发送的是持久化的消息。

异步发送
它可以最大化producer端的发送效率。我们通常在发送消息量比较密集的情况下使用异步发送,它可以很大的提升Producer性能;不过也带来了额外的问题,就是需要消耗较多的Client端内存同时也会导致broker端性能消耗增加;此外它不能有效的确保消息发送成功,在useAsyncSend=true的情况下客户端需要容忍消息丢失的可能。
如何确认发送成功?
生产者设置UseAsyncSend=true,使用producer.send(msg)持续发送消息。
由于消息不阻塞,生产者会认为所有send的消息均被成功发送至MQ。
如果MQ突然宕机,此时生产者端内存中尚未被发送至MQ的消息都会丢失。
所以,正确的异步发送方法是需要接受回调的。
同步发送和异步发送的区别就在于此,
同步发送等send不阻塞了就表示一定发送成功了,
异步发送需要接受回执并由客户端在判断一次是否发送成功。

public class jmsProduce_AsyncSend {
    public static  final String ACTIVEMQ_URL="nio://192.168.10.100:61608";
    public static  final String QUEUE_NAME="jdbc01";
    public static void main(String[] args) throws JMSException {
        //1.创建连接工厂,采用默认的用户名密码,连接给定的url
        ActiveMQConnectionFactory connectionFactory=new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        connectionFactory.setSendAcksAsync(true);
        //2.通过连接工厂,获得Connection并启动
        Connection connection = connectionFactory.createConnection();
        connection.start();
        //3创建session
        //两个参数,第一个:事务,第二个:签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4创建目的地(队列还是主题)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5创建消息的生产者
        ActiveMQMessageProducer producer =(ActiveMQMessageProducer) session.createProducer(queue);
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        //6.通过使用MessageProducers生产3条消息发送到mq的队列里
        for (int i = 1; i <=3; i++) {
            TextMessage textMessage= session.createTextMessage("jdbc  msg---" + i);//理解为一个字符串
            //发送
            textMessage.setJMSMessageID(UUID.randomUUID().toString()+"------order");
            String msgID=textMessage.getJMSMessageID();
            producer.send(textMessage, new AsyncCallback() {
                @Override
                public void onSuccess() {
                    System.out.println(msgID+"send ok");
                }

                @Override
                public void onException(JMSException e) {
                    System.out.println(msgID+"send false");
                }
            });
        }
        //关闭资源
        producer.close();
        session.close();
        connection.close();
        System.out.println("******消息发布完成");
    }
}

延时投递和定时投递

四大属性
在这里插入图片描述
修改activemq.xml配置文件
在这里插入图片描述
生产者

public class jmsProduce_DelayAndSchedule {
    public static  final String ACTIVEMQ_URL="nio://192.168.10.100:61608";
    public static  final String QUEUE_NAME="jdbc01-Delay";
    public static void main(String[] args) throws JMSException {
        ActiveMQConnectionFactory connectionFactory=new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        Connection connection = connectionFactory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageProducer producer = session.createProducer(queue);
        long delay=3*1000;  //延迟三秒
        long period=4*1000;  //每四秒一次
        int repeat=5;  //一共五次
        for (int i = 1; i <=3; i++) {
            TextMessage textMessage= session.createTextMessage("delay  msg---" + 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);
        }
        //关闭资源
        producer.close();
        session.close();
        connection.close();
        System.out.println("******消息发布完成");
    }
}

ActiveMQ消费重试机制

具体哪些情况会引起消息重发

1.Client用了transactions且在session中调用了rollback()
2.Client用了transactions且在调用commit()之前关闭或者没有commit
3.Client在CLIENT_ACKNOWLEDGE的传递模式下,在session中调用了recover()

消息重发时间间隔和重发次数

间隔:1s
次数:6

有毒消息Poison ACK的理解

一个消息被redelivedred超过默认的最大重发次数时,消费端会给MQ发送一个“poison ack”表示这个消息有毒,告诉broker不要再发了,这个时候broker会把这个消息放到DLQ(死信队列)。

修改重发次数

		RedeliveryPolicy redeliveryPolicy=new RedeliveryPolicy();
        redeliveryPolicy.setMaximumRedeliveries(3);//修改重发次数
        connectionFactory.setRedeliveryPolicy(redeliveryPolicy);

死信队列

一条消息被重发了多次后(默认6次),将会被ActiveMQ移入“死信队列”,可以在这个队列中查看出错的消息,进行人工干预。

SharedDeadLetterStrategy

将所有的DeadLetter保存在一个功效的队列中,这是ActiveMQ broker端的默认策略。“ActiveMQ_DLQ”,可以通过“deadLetterQueue”属性来设置

 <deadLetterStrategy>
 	<sharedDeadLetterStrategy deadLetterQueue="DLQ-QUEUE">
 </deadLetterStrategy>	

IndividualDeadLetterStrategy

把DeadLetter放入各自的死信通道中,
对于Queue而言,死信通道的前缀默认为“Activemq.DLQ.Queue”
对于Topic而言,死信通道的前缀默认为“Activemq.DLQ.Topic”
比如队列Order,那么对应的死信通道为“Activemq.DLQ.Queue.Order”

<policyEntry queue="order">
	<deadLetterStrategy>
	  <individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="false"/>
	</deadLetterStrategy>
</policyEntry>

自动删除过期消息

有时需要直接删除过期消息而不需要发送到死队列中,“processExpired” 默认为true

<policyEntry queue=">">
	<deadLetterStrategy>
	  <sharedDeadLetterStrategy processExpired="false" />
	</deadLetterStrategy>
</policyEntry>

存放非持久消息到死队列中

默认情况下,ActiveMQ不会把非持久的死消息发送到死信队列中,“processNonPersistent”表示是否将“非持久化”消息放入死信队列,默认为false

<policyEntry queue=">">
	<deadLetterStrategy>
	  <sharedDeadLetterStrategy processNonPersistent="true" />
	</deadLetterStrategy>
</policyEntry>

防止重复调用

网络延迟传输中,会造成进行MQ重试中,在重试过程中,可能会造成重复消费。
如果消息是做数据库的插入操作,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据
或者准备一个第三方服务来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该信息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询中有没消费记录即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值