ActiveMQ--高级特性和大厂常考重点

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

    1. zookeeper +replicated-leveldbstore-store 
  2. 异步投递Async Sends

    1. 异步投递
      • http://activemq.apache.org/ async-sends

      • 说明

      • 对于一个slowConsumer,使用同步发送消息可能出现Producer堵塞等情况,慢消费者适合使用异步发送。

    2. 是什么
      •  不使用事务且消息是持久化的发送的消息使持久化的,本身没有使用事务会造成消息不能完全都成功还是都失败,并且持久化的消息(持久化到MQ内存中),此时的消息是同步的

         

            
    3. 官网配置
      1. 第一中开启异步投递的方式
      2. 第二种开启异步投递的方式 

      3. 第三种开启异步投递的方式
        1.  

             

              
    4. 面试题追问 
      1. 异步发送如何确认发送成功:
      2.  异步投递需要接收回调,才会确定是否成功

      3. 同步消息等send不阻塞了就代表发送成功了

      4. 异步发送的代码实现;
        1.   
          package com.model.YiBuTouDi;
          
          import org.apache.activemq.ActiveMQConnectionFactory;
          import org.apache.activemq.ActiveMQMessageProducer;
          import org.apache.activemq.AsyncCallback;
          
          import javax.jms.*;
          import java.util.UUID;
          
          /**
           * Hello world!
           *
           */
          public class JmsProducer {
              // 第一种开启异步投递的方法:
              public static final String ACTIVEMQ_URL="tcp://192.168.56.130:61616";
          
              public static final String QUEUE_NAME="queue01";
              public static void main(String[] args) throws JMSException {
          
          //        1.创建连接工厂,按照给定的url地址,采用默认的用户名和密码
                  ActiveMQConnectionFactory activeMQConnectionFactory=new ActiveMQConnectionFactory(ACTIVEMQ_URL);
          
                  //  第二种开启异步投递的方式
                  activeMQConnectionFactory.setUseAsyncSend(true);
          
          //        2.创建连接工厂,获得连接connection并启动访问
                  Connection connection = activeMQConnectionFactory.createConnection();
                  connection.start();
          //        3.创建会话
          //        两个参数,第一交事务/第二个叫签收
                  Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
          //        4.创建目的地(具体是队列还是主题topic)
                  Queue queue = session.createQueue(QUEUE_NAME);
          //        5.创建消息的生产者
                  ActiveMQMessageProducer activeMQMessageProducer = (ActiveMQMessageProducer) session.createProducer(queue);
          //        6.通过使用messageProducer生产3条消息发送给MQ的队列里面
                  TextMessage textMessage=null;
                  for (int i = 0; i < 3; i++) {
          //        7.创建消息,好比时学生按照要求给来老师写的问题
                      textMessage = session.createTextMessage("message----" + i);
          //            为消息设置id号标识
                      textMessage.setJMSMessageID(UUID.randomUUID().toString()+"======");
                      String msgID=textMessage.getJMSMessageID();
          //        8.通过messageProducer发送给mq
                      activeMQMessageProducer.send(textMessage, new AsyncCallback() {
                          @Override
                          public void onSuccess() {
                              System.out.println(msgID+"发送成功了");
                          }
          
                          @Override
                          public void onException(JMSException exception) {
                              System.out.println(msgID+"发送失败了");
                          }
                      });
                  }
          //        9.关闭资源
                  activeMQMessageProducer.close();
                  session.close();
                  connection.close();
                  System.out.println("*生产者发送消息over******");
              }
          }

           

        2.  

           

           

                 
  3. 延迟投递和定时投递

    1. http://activemq.apache.org/delay-and-schedule-message- delivery.html

       

    2. 官网说明

      1. 四大属性

      2.  

      3.   
    3. 案例演示

      1. 要在activemq.xml中配置schedulerSupport属性为true

         

        1. schedulerSupport="true"
        2.  
           
      2. Java代码里面封装的辅助消息类型:ScheduledMessage

      3. 代码:

        • JmsProduce_ DelayAndSchedule

          • package com.model.YanChiHeDingShiTouDi;
            
            import org.apache.activemq.ActiveMQConnectionFactory;
            import org.apache.activemq.ScheduledMessage;
            import org.springframework.scheduling.annotation.Scheduled;
            
            import javax.jms.*;
            
            /**
             * Hello world!
             *
             */
            public class JmsProducer_DelayAndSchedule {
                public static final String ACTIVEMQ_URL="tcp://192.168.56.130:61616";
                public static final String QUEUE_NAME="queue-delay";
                public static void main(String[] args) throws JMSException {
            
                    ActiveMQConnectionFactory activeMQConnectionFactory=new ActiveMQConnectionFactory(ACTIVEMQ_URL);
                    Connection connection = activeMQConnectionFactory.createConnection();
                    connection.start();
                    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                    Queue queue = session.createQueue(QUEUE_NAME);
                    MessageProducer messageProducer = 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("delay--message----" + i);
                        textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,delay);
                        textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD,period);
                        textMessage.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT,repeat);
                        messageProducer.send(textMessage);
                    }
                    messageProducer.close();
                    session.close();
                    connection.close();
                    System.out.println("生产者发送消息over******");
                }
            }

             

              

        • JmsConsumer_ DelayAndSchedule 

          • package com.model.YanChiHeDingShiTouDi;
            
            import org.apache.activemq.ActiveMQConnectionFactory;
            
            import javax.jms.*;
            
            public class JmsConsumer_DelayAndSchedule {
                    public static final String ACTIVEMQ_URL="tcp://192.168.56.130:61616";
                    public static final String QUEUE_NAME="queue-delay";
                    public static void main(String[] args) throws JMSException {
            
            //        1.创建连接工厂,按照给定的url地址,采用默认的用户名和密码
                        ActiveMQConnectionFactory activeMQConnectionFactory=new ActiveMQConnectionFactory(ACTIVEMQ_URL);
            //        2.创建连接工厂,获得连接connection并启动访问
                        Connection connection = activeMQConnectionFactory.createConnection();
                        connection.start();
            //        3.创建会话
            //        两个参数,第一交事务/第二个叫签收
                        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //        4.创建目的地(具体是队列还是主题topic)
                        Queue queue = session.createQueue(QUEUE_NAME);
            //        5.创建消息的消费者
                        MessageConsumer consumer = session.createConsumer(queue);
            //        6.消费者消费信息
                        while(true){
                            TextMessage message = (TextMessage) consumer.receive();
                            if (message!=null){
                                System.out.println("message==="+message.getText());
                            }else {
                                break;
                            }
                        }
            //        7.关闭资源
                        consumer.close();
                        session.close();
                        connection.close();
                    }
            }

             

              
        •   

           

  4. 分发策略

  5. ActiveMQ消费重试机制

    1. 生产案例的面试题
      • 具体哪些情况会引起消息重发:

        1. Client用了transactions且在session中调用了rollback() 

        2. Client用 了transactions且在调用commit()之前关闭或者没有commit 

        3.  Client在CLIENT_ _ACKNOWLEDGE(签收机制)的传递模式下,在session中 调用了recover() (重试)

      • 请说说消息重发时间间隔和重发次数吗?

        1. 间隔: 1 
        2. 次数: 6 
      • 有毒消息PoisonACK谈谈你的理解:

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

      • 记得给学生讲解2次,上述回答

          
    2. 官网 : https://activemq.apache.org/redelivery-policy.html  
      1.  

    3. 属性说明
      1.   
    4. 案例验证与讲解 
      1. JmsProduce_ Redelivery

        1. 和前面一样,正常生产三条消息  

      2. JmsConsumer_ Redelivery

        1. 消费者开启事务,但是不提交,进行消费一次

        2. 消费一次,但是后台控制端 的中的三条消息不变,没有出队,造成重复消费
        3. 消费者在连续消费六次,重复消费。

        4. 当消费者在次消费,超过了默认的最大重发次数。将三条信息加入到DLQ(死信队列)中,消费者将无法在消费到这三条信息  

      3. 故意出bug,默认调用6次后看情况,了 解死信队列

        1.  

           

      4. JmsConsumer_ Redelivery修改 

        1. 修改最大重发次数,重发三次后就会将消息加入到,DLQ失信队列中

    5. 整合spring后如何使用,假如在工作中需要

      1.   

           
  6. 死信队列

    1. http:/activemq.apache.org/message-redelivery-and-dlq-handling.html

    2. 是什么
    3. 死信队列的使用:处理失败的消息

      • *一般生产环境中在使用MQ的时候设计两个队列:一个是核心业务队列,- .个是死信队列。

         

      • *核心业务队列,就是比如上图专门用来让订单系统发送订单消息的,然后另外-一个死信队列就是用来处理异常情况的。

      • *假如第三方物流系统故障了此时无法请求,那么仓储系统每次消费到--条订单消息,尝试通知发货和配送都会遇到对方的接口报错。此时仓储系
        统就可以把这条消息拒绝访问或者标志位处理失败。--旦标志这条消息处理失败了之后,MQ就会把这条消息转入提前设置好的-一个死信队列中。
        然后你会看到的就是,在第三方物流系统故障期间,所有订单消息全部处理失败,全部会转入死信队列。然后你的仓储系统得专门有一一个后台线
        程,监控第三方物流系统是否正常,能否请求的,不停的监视。- -旦发现对方恢复正常,这个后台线程就从死信队列消费出来处理失败的订单, .重新执行发货和配送的通知逻辑

          
    4. activemq死信队列的配置介绍

      1. SharedDeadLetterStrategy

      2. IndividualDeadLetterStrategy

        •  
            
      3. 配置案例

        • 自动删除过期消息

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

        •    

  7. 如何保证消息不被重复消费呢?幂等性问题你谈谈(防止消息重复消费的问题)

    1. 网络延迟传输中,会造成进行MQ重试中,在重试过程中,可能会造成重复消费。

       

    2. 如果消息是做数据库的插入操作,给这个消息做一个唯一-主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。

    3. 如果上面两种情况还不行,准备- -个第 三服务方来做消费记录。以redis为例, 给消息分配-一个 全局id,只要消费过该消息,将<id,message>以
      K-V形式写入redis.那消费者开始消费前,先去redis中查询有没消费记录即可。

       
posted @ 2021-06-02 19:34  张紫韩  阅读(102)  评论(0编辑  收藏  举报