Docker-rabbitMQ Springboot--死信队列--笔记

先上两个rabbitmq图
在这里插入图片描述
在这里插入图片描述

安装

	docker run -it --hostname rabbitmq --name mq1 -p 5672:5672 -p 15672:15672 rabbitmq:3-management

其他参数:

  • –hostname 容器主机名
  • –name 容器名
  • –link 该容器联合其他容器使用 例如:–link rabbitmq:mq1
  • -e 附加参数 例如:-e RABBITMQ_ERLANG_COOKIE=‘rabbitcookie’
  • –net host 使用宿主机网络,此时设置映射端口无效,直接使用宿主机IP和端口

实操

  1. yaml配置

    rabbitmq:
    	host: 192.168.38.128
    	port: 5672
    	username: guest
    	password: guest
    	virtual-host: /
    #确认消息已发送到交换机(Exchange)
    	publisher-confirms: true
    #确认消息已发送到队列(Queue)
    	publisher-returns: true
    	listener:
        direct:
        #全局direct开启手动确认模式
            acknowledge-mode: manual  
    	template:
        	retry:
            	enabled: true
            	#重试3次
            	max-attempts: 3
            	# 间隔一秒
            	initial-interval: 2000
    
  2. pom配置

     <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    
  3. 生产者 配置类

package com.zq.lhkj.rabbitmq;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitMQConfig {
    /**正常交换机名称*/
    public static final String EXCHANGE_NAME = "boot_topic_exchange";
    /**
     * 正常队列
     */
    public static final String QUEUE_NAME = "boot_queue_zc";
    /**
     * 死信队列
     */
    public static final String DLX_Q = "dlx_q";
    /**
     * 死信key
     */
    public static String DXLKEY = "boot3.haha";

    /**
     * 死信的交换器
     */
    public static String PROCESS_EXCHANGE = "dlx.exchange";

    //1.交换机
    @Bean("bootExchange")
    public Exchange bootExchange() {
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }


    //2.Queue 队列
    @Bean("bootQueue")
    public Queue bootQueue() {
        Map<String, Object> args = new HashMap<>(2);
//       x-dead-letter-exchange    声明  死信队列Exchange
        args.put("x-dead-letter-exchange", PROCESS_EXCHANGE);
//       x-dead-letter-routing-key    声明 死信队列抛出异常重定向队列的routingKey(TKEY_R)
        args.put("x-dead-letter-routing-key", DXLKEY);
        args.put("x-message-ttl", 15000);

        Queue queue = QueueBuilder.durable(QUEUE_NAME)
                // DLX,dead letter发送到的exchange ,设置死信队列交换器到处理交换器
                .withArguments(args)
                .build();
        return queue;
    }

    /**
     * 配置处理交换器
     *
     * @return
     */
    @Bean("processExchange")
   public Exchange processExchange() {
        return ExchangeBuilder.topicExchange(PROCESS_EXCHANGE).durable(true).build();
    }

    @Bean("bootQueue2")
    public Queue bootQueue2() {
        Queue queue = QueueBuilder.durable(DLX_Q).build();
        return queue;
    }


    //3. 队列和交互机绑定关系 Binding
    /*
        1. 知道哪个队列
        2. 知道哪个交换机
        3. routing key
     */
    @Bean
    public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange) {

        return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
    }

    @Bean
    public Binding bindQueueExchange2(@Qualifier("bootQueue2") Queue queue, @Qualifier("processExchange") Exchange exchange) {

        return BindingBuilder.bind(queue).to(exchange).with("boot3.#").noargs();
    }
/**
     * 解决 同一template不能设置多个回调的问题
     * @param connectionFactory
     * @return
     */
    @Bean
    @Scope("prototype")
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        template.setMandatory(true);
        template.setMessageConverter(new SerializerMessageConverter());
        //2. 定义回调
        template.setConfirmCallback(new Callback());
        return template;
    }

}

  1. 开启某个队列 手动确认

@Configuration
public class MessageListenerConfig {

   @Autowired
   private CachingConnectionFactory connectionFactory;
   @Autowired
   private RabbimtMQListener myAckReceiver;//消息接收处理类

   @Bean
   public SimpleMessageListenerContainer simpleMessageListenerContainer() {
       SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
       container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息
       //设置一个队列
       container.setQueueNames(RabbitMQConfig.QUEUE_NAME);
      // 每次取多少个
       container.setPrefetchCount(1);
       //如果同时设置多个如下: 前提是队列都是必须已经创建存在的
       //  container.setQueueNames("TestDirectQueue","TestDirectQueue2","TestDirectQueue3");
       //另一种设置队列的方法,如果使用这种情况,那么要设置多个,就使用addQueues
       //container.setQueues(new Queue("TestDirectQueue",true));
       //container.addQueues(new Queue("TestDirectQueue2",true));
       //container.addQueues(new Queue("TestDirectQueue3",true));
       container.setMessageListener(myAckReceiver);

       return container;
   }
}



ack回调

public class Callback implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        System.out.println("ConfirmCallback:     " + "相关数据:" + correlationData);
        System.out.println("ConfirmCallback:     " + "确认情况:" + ack);
        System.out.println("ConfirmCallback:     " + "原因:" + cause);
        if (ack) {
            System.out.println("消息发送确认成功");
        } else {
            System.out.println("消息发送确认失败");
        }
    }
 /**
     * 只有失败的时候 才会回调
     * @param message
     * @param replyCode
     * @param replyText
     * @param exchange
     * @param routingKey
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        //失败的回调
        try {
            System.out.println("ReturnCallback:     " + "消息:" + new String(message.getBody(), "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println("ReturnCallback:     " + "回应码:" + replyCode);
        System.out.println("ReturnCallback:     " + "回应信息:" + replyText);
        System.out.println("ReturnCallback:     " + "交换机:" + exchange);
        System.out.println("ReturnCallback:     " + "路由键:" + routingKey);

    }
}

  • 消费者 消息监听

@Component
public class RabbimtMQListener implements ChannelAwareMessageListener {
   /*开启手动确认模式*/
//    @Bean
//    @ConditionalOnClass
//    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(CachingConnectionFactory connectionFactory) {
//        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
//        factory.setConnectionFactory(connectionFactory);
//        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
//        return factory;
//    }
//    @RabbitListener(queues = "test_q")
//    public void ListenerQueue(Message message){
//        //System.out.println(message);
//        System.out.println(new String(message.getBody()));
//
//    }

   @Override
   public void onMessage(Message message, Channel channel) throws Exception {
       System.out.println(new String(message.getBody())+";;;;");
       //不需要手动确认时 该参数为null 
       long deliveryTag = message.getMessageProperties().getDeliveryTag();
       //第三个参数false时,不再放入队列,true时 会再次进入对接执行。
       channel.basicNack(deliveryTag,false,false);
       
   }
}

生产者发布消息

@RestController
@RequestMapping("/rabbitmq")
public class rabbitmqController {
   @Autowired
   private RabbitTemplate rabbitTemplate;
   // 消息后处理对象,设置一些消息的参数信息
   MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
       @Override
       public Message postProcessMessage(Message message) throws AmqpException {
           //1.设置message的信息
           message.getMessageProperties().setExpiration("10000");//消息的过期时间
           //2.返回该消息
           return message;
       }
   };

   @GetMapping("/send")
   public void login(String exchange,String topic, String msg) {

           //3. 发送消息
           rabbitTemplate.convertAndSend(exchange,topic,msg,messagePostProcessor);
           //convertAndSend(String exchange, String routingKey, Object message, MessagePostProcessor messagePostProcessor, @Nullable CorrelationData correlationData)
          //CorrelationData  里面可以放一个id  可以标识消息的唯一性,业务场景可能使用到
   }

}


坑点与注意点:

  • 当一个队列创建完后,无法再次修改参数,比如修改ttl等,此时可以使用policy策略实现。

  • 进入死信队列的情况包括:
    1.队列长度达到长度限制 x-max-length
    2.手动确认时,消费者拒接消息时。basicNack或者basicReject并且不把消息重新放入对接时,第三个参数为false。
    3.当消息设置过期时间,到期未消费者。

  • 日志与监控
    在这里插入图片描述

  • 消息追踪–测试开发使用,因开启大大影响性能,只限调试使用
    firehose
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200730145930872.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F4YmJlc3Q=,size_16,color_FFFFFF,t_70

    rabbitmq_tracing插件(推荐)

    1. rabbitmq-plugins list
    2. rabbitmq-plugins enable rabbitmq_tracing启用插件
  • 官方也有个延迟队列的插件 rabbitmq_delayed_message_exchange
    安装文档:https://www.cnblogs.com/cyleon/p/10450040.html

  • 路由key: *.hh.## *的含义是前面有1个单词, #是0或者多个单词

  • 消息补偿
    在这里插入图片描述

  • 幂等(乐观锁)
    在这里插入图片描述

集群(docker)

  • 创建多个RabbitMQ容器

第一个mq

docker run -d --hostname rabbit1 --name myrabbit1 -p 15672:15672 -p 5672:5672 -e RABBITMQ_ERLANG_COOKIE=‘rabbitcookie’ rabbitmq:3.7.8-management

第二个

docker run -d --hostname rabbit2 --name myrabbit2 -p 5673:5672 -p 15673:15672 --link myrabbit1:rabbit1 -e RABBITMQ_ERLANG_COOKIE=‘rabbitcookie’ rabbitmq:3.7.8-management

注意点:–link 连接多个容器,使其可以互相访问 ,如果三台,要连接前面2个容器
RABBITMQ_ERLANG_COOKIE参数,多个mq容器 访问秘钥一定要一样

  • 主节点
docker exec -it myrabbit1 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
exit

从节点:

docker exec -it myrabbit2 bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster --ram rabbit@rabbit1
rabbitmqctl start_app
exit

注意点:-ram 表示设置为内存节点,忽略该参数则默认为磁盘节点。
使用http://ip:15672 进行访问了,账号密码默认为guest&guest,可见2个节点了。

  • 开启镜像同步
    在这里插入图片描述
    完成镜像集群搭建。

HA

  • 安装 Ha
    docker pull haproxy
  • 配置文件
global
      maxconn 10000                   #默认最大连接数
      log 127.0.0.1 local0            #[err warning info debug]
      chroot /usr/local/sbin            #chroot运行的路径
      daemon                          #以后台形式运行haproxy
      pidfile /var/run/haproxy.pid    #haproxy的pid存放路径,启动进程的用户必须有权限访问此文件
defaults
      log 127.0.0.1 local3
      mode http                       #所处理的类别 (#7层 http;4层tcp  )
      maxconn 10000                   #最大连接数
      option dontlognull              #不记录健康检查的日志信息
      option redispatch               #serverId对应的服务器挂掉后,强制定向到其他健康的服务器
      #stats refresh 30                #统计页面刷新间隔
      retries 3                       #3次连接失败就认为服务不可用,也可以通过后面设置
      balance roundrobin              #默认的负载均衡的方式,轮询方式
     #balance source                  #默认的负载均衡的方式,类似nginx的ip_hash
     #balance leastconn               #默认的负载均衡的方式,最小连接
      timeout connect 5000                 #连接超时
      timeout client 50000                #客户端超时
      timeout server 50000                #服务器超时
      timeout check 2000              #心跳检测超时
####################################################################
listen http_front
       bind 0.0.0.0:5669           #监听端口
       stats refresh 30s           #统计页面自动刷新时间
       stats uri /haproxy?stats            #统计页面url
       stats realm Haproxy Manager #统计页面密码框上提示文本
       stats auth admin:admin      #统计页面用户名和密码设置
       #stats hide-version         #隐藏统计页面上HAProxy的版本信息
#####################我把RabbitMQ的管理界面也放在HAProxy后面了###############################
listen rabbitmq_admin 
   bind 0.0.0.0:5671
listen rabbitmq_cluster 
   bind 0.0.0.0:5670
   option tcplog
   mode tcp
   option tcplog
   mode tcp
   timeout client  3h
   timeout server  3h
   option          clitcpka
   balance roundrobin      #负载均衡算法(#banlance roundrobin 轮询,balance source 保存session值,支持static-rr,leastconn,first,uri等参数)
   #balance url_param userid
   #balance url_param session_id check_post 64
   #balance hdr(User-Agent)
   #balance hdr(host)
   #balance hdr(Host) use_domain_only
   #balance rdp-cookie
   #balance leastconn
   #balance source //ip
   server   rabbitmq2 192.168.38.128:5672 check inter 5s rise 2 fall 3   #check inter 2000 是检测心跳频率,rise 22次正确认为服务器可用,fall 33次失败认为服务器不可用
   server   rabbitmq1 192.168.38.128:5673 check inter 5s rise 2 fall 3
  • HA状态管理
    http://192.168.38.128:5669/haproxy?stats
    在这里插入图片描述
  • mq后台管理页面
    http://192.168.38.128:5671/#/queues
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑着巨人找巨人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值