AMQ基础

一、消息中间件模式分部

queue一对一实现了负载均衡,将producer生产的消息发送到消息队列中,由多个消费者消费。但一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有一个可用的消费者。

topic一对多实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到一个消息的拷贝。

详见 自己连接

二、 代码

  1. 添加activemq的依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
  1. 配置 yml
spring.activemq.broker-url=tcp://172.16.154.27:61616
spring.activemq.user=admin
spring.activemq.password=123456
spring.activemq.in-memory=true
spring.activemq.pooled=false
  1. 工厂配置文件,整合amq
@Configuration
public class ActiveMQConfig {
   
    @Bean
    public JmsListenerContainerFactory<?> queueListenerFactory(@Qualifier("activeMQConnectionFactory") ActiveMQConnectionFactory connectionFactory) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        SimpleMessageListenerContainer container=new SimpleMessageListenerContainer();
        container.setConcurrentConsumers(3);
        container.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(false);
        factory.setConnectionFactory(connectionFactory);
        factory.setConcurrency("3-15");  //连接数
        factory.setRecoveryInterval(1000L); //重连间隔时间
        factory.setSessionAcknowledgeMode(4);
        return factory;
    }

    @Bean
    public ActiveMQConnectionFactory activeMQConnectionFactory(){
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
        connectionFactory.setTrustAllPackages(true);
        connectionFactory.setRedeliveryPolicy(redeliveryPolicy());
        return connectionFactory;
    }

    @Bean
    public RedeliveryPolicy redeliveryPolicy(){
        RedeliveryPolicy redeliveryPolicy=new RedeliveryPolicy();
        //是否在每次尝试重新发送失败后,增长这个等待时间
        redeliveryPolicy.setUseExponentialBackOff(true);
        //重发次数,默认为6次
        redeliveryPolicy.setMaximumRedeliveries(5);
        //重发时间间隔,默认为1秒
        redeliveryPolicy.setInitialRedeliveryDelay(1);
        //第一次失败后重新发送之前等待500毫秒,第二次失败再等待500 * 2毫秒,这里的2就是value
        redeliveryPolicy.setBackOffMultiplier(2);
        //是否避免消息碰撞
        redeliveryPolicy.setUseCollisionAvoidance(false);
        //设置重发最大拖延时间-1 表示没有拖延只有UseExponentialBackOff(true)为true时生效
        redeliveryPolicy.setMaximumRedeliveryDelay(-1);
        return redeliveryPolicy;
    }

    @Bean
    public JmsTemplate jmsTemplate(ActiveMQConnectionFactory activeMQConnectionFactory){
        JmsTemplate jmsTemplate=new JmsTemplate();
        jmsTemplate.setDeliveryMode(1);//进行持久化配置 1表示非持久化,2表示持久化
        jmsTemplate.setConnectionFactory(activeMQConnectionFactory);
        jmsTemplate.setSessionAcknowledgeMode(4);//客户端签收模式
        return jmsTemplate;
    }

}
  1. 定义 queue。(也可以topic)
@Configuration
public class QueueConfig {


    @Bean(name="telQueue")
    public Queue telQueue() {
        return new ActiveMQQueue(MESSAGE_TEL);
    }

    @Bean(name = "emailQueue")
    public Queue emailQueue() {
        return new ActiveMQQueue(MESSAGE_EMAIL);
    }

}
  1. 定义生产者----使用jmsTemplate
@Slf4j
@Component
public class QueueSender {
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Resource(name = "telQueue")
    private Queue telQueue;

    @Resource(name = "emailQueue")
    private Queue emailQueue;

    public void sendTel(final MessageTel message){
        log.info("发送短信message={}",message);
        this.jmsMessagingTemplate.convertAndSend(telQueue,message);
    }

    public void sendEmail(final MessageEMail message){
        log.info("发送email message={}",message);
        this.jmsMessagingTemplate.convertAndSend(emailQueue,message);
    }

}
  1. 定义消费者—使用@JmsListener。@JmsListener可指定多个destination 监听多个队列
@Slf4j
@Component
public class QueueReceiver {
   
    @Autowired
    private MailUtil mailUtil;
    @Autowired
    private SendSMSUtil sendSMSUtil;


    /**
     * 发送短信
     *
     * @param messageTel
     */
    @JmsListener(destination = QueueConfig.MESSAGE_TEL, containerFactory = "queueListenerFactory")
    public void receiveTel1(MessageTel messageTel) {
         log.info("-----receive tel message-----"); 
         
    }

    /**
     * 发送邮件
     *
     * @param messageEMail
     */
    @JmsListener(destination = QueueConfig.MESSAGE_EMAIL, containerFactory = "queueListenerFactory")
    // 可监听多个队列
    // @JmsListeners(value = {@JmsListener(destination = "T1"), @JmsListener(destination = "T2")})
    public void receiveEmail(MessageEMail messageEMail) {
        log.info("-----receive email message-----");
          
    }
}

消费消息有2种方法,
  一种是调用consumer.receive()方法,该方法将阻塞直到获得并返回一条消息。这种情况下,消息返回给方法调用者之后就自动被确认了。
  另一种方法是采用listener回调函数,在有消息到达时,会调用listener接口的onMessage方法。在这种情况下,在onMessage方法执行完毕后,消息才会被确认,此时只要在方法中抛出异常,该消息就不会被确认。

三、JMSTemplate

生产者:JmsTemplate      
消费者:@JmsListener(destination = "ActiveMQQueue")

官方API链接在此,恶灵退散~
常用对比。注意send和convertAndSend
在这里插入图片描述

四、优先级

可以使用消息优先级来指示JMS Provider首先提交紧急的消息。优先级分10个级别,从0(最低)到9(最高)。
如果不指定优先级,默认级别是4。需要注意的是,JMS Provider并不一定保证按照优先级的顺序提交消息。

五、配置信息

amq也可以在application.properires配置消息队列,并在启动类添加@EnableJms开启消息队列。

# failover:(tcp://localhost:61616,tcp://localhost:61617)
# tcp://localhost:61616
spring.activemq.broker-url=tcp://localhost:61616
#true 表示使用内置的MQfalse则连接服务器
spring.activemq.in-memory=false
#true表示使用连接池;false时,每发送一条数据创建一个连接
spring.activemq.pool.enabled=true
#连接池最大连接数
spring.activemq.pool.max-connections=10
#空闲的连接过期时间,默认为30秒
spring.activemq.pool.idle-timeout=30000
#强制的连接过期时间,与idleTimeout的区别在于:idleTimeout是在连接空闲一段时间失效,而expiryTimeout不管当前连接的情况,只要达到指定时间就失效。默认为0,never
spring.activemq.pool.expiry-timeout=0

六、监听器功能

@SendTo将消息处理完继续发送继续处理

@Component
public class MessageListener {

    @JmsListener(destination = "order.queue.message")
    @SendTo("other.queue")	
    private String receive(String message){
        System.out.println("自动接收到order.queue.message消息:"+ message);
//        注意是将此方法的返回值返回到 新的队列中
        return message;
    }

    @JmsListener(destination = "other.queue")
    private void  receiveOther(String message){
        System.out.println("接收到other.queue继续发送的消息:" + message);
    }
}

参考链接~~~

七、持久化

7.1 速度

持久化消息非常慢

默认的情况下,非持久化的消息是异步发送的,持久化的消息是同步发送的,遇到慢一点的硬盘,发送消息的速度是无法忍受的。但是在开启事务的情况下,消息都是异步发送的,效率会有2个数量级的提升。所以在发送持久化消息时,请务必开启事务模式。其实发送非持久化消息时也建议开启事务,因为根本不会影响性能。

7.2 持久化消息

ActiveMQ会将内存中的非持久化消息写入临时文件中,以腾出内存。虽然都保存到了文件里,但它和持久化消息的区别是,重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除。
那如果文件增大到达了配置中的最大限制的时候会发生什么?我做了以下实验:

设置2G左右的持久化文件限制,大量生产持久化消息直到文件达到最大限制,此时生产者阻塞,但消费者可正常连接并消费消息,等消息消费掉一部分,文件删除又腾出空间之后,生产者又可继续发送消息,服务自动恢复正常。

设置2G左右的临时文件限制,大量生产非持久化消息并写入临时文件,在达到最大限制时,生产者阻塞,消费者可正常连接但不能消费消息,或者原本慢速消费的消费者,消费突然停止。整个系统可连接,但是无法提供服务,就这样挂了。

具体原因不详,解决方案:尽量不要用非持久化消息,非要用的话,将临时文件限制尽可能的调大。

八、mq阻塞(amq、rmq)

解决方案:
1、增加消费者数量,提高消费速度
2、提高消费者处理消息的速度,优化代码、减少处理时间
3、调整mq配置参数。如最大连接数量、最大消息数量
4、增加mq容量

九、mq消息中间件工作流程


在这里插入图片描述

【1】发送端 MQ-Product (消息生产者)将消息发送给 MQ-server;
【2】MQ-server 将消息落地,持久化到数据库等;
【3】MQ-server 回 ACK 给 MQ-Producer;
【4】MQ-server 将消息发送给消息接收端 MQ-Consumer (消息消费者);
【5】MQ-Consumer 消费接收到消息后发送 ACK 给 MQ-server;
【6】MQ-server 将落地消息删除;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值