rabbitmq 限流&延时队列

167 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

三、限流

为了展示消息本地容量(限流)确实有效果,那么可以将消费者里面休眠一会模拟业务逻辑

spring:
  rabbitmq:
    host: 192.168.200.132
    #开启确认模式
    publisher-confirms: true
    #开启退回模式
    publisher-returns: true
    listener:
      simple:
        acknowledge-mode: manual #手动确认 auto #自动确认 none #不需要确认
        prefetch: 1 #配置本地最大容量是1条

四、延时队列

1. 过期队列--TTL
2. 死信

什么样的消息会进入死信队列:

  • 过期的消息会自动到达死信队列
  • 被拒绝重回队列的消息会到达死信队列
3. 延时队列
 @Bean
    public Queue orderB(){
        Map<String, Object> map = new HashMap<>();
        //设置该队列中的消息过期时间是5s
        map.put("x-message-ttl", 5000);
        //设置死信交换机和死信路由键
        map.put("x-dead-letter-exchange", "orderDelEx");
        map.put("x-dead-letter-routing-key", "order");
        return new Queue("order.B",true,false,false, map);
    }
​
    @Bean
    public Binding bindOrderB(Queue orderB, DirectExchange orderEx){
        return BindingBuilder.bind(orderB).to(orderEx).with("orderB");
    }
​
    @Bean
    public Queue orderDel(){
        return new Queue("orderDel");
    }
    @Bean
    public DirectExchange orderDelEx(){
        return new DirectExchange("orderDelEx");
    }
    @Bean
    public Binding bindingOrderDel(Queue orderDel, DirectExchange orderDelEx){
        return BindingBuilder.bind(orderDel).to(orderDelEx).with("order");
    }
​
@RabbitListener(queues = {"order.A","orderDel"})
@Component
@Slf4j
public class OrderAListener {
    //省略...
}

流程:

  1. 先创建orderB队列并且给orderB设置过期时间和死信交换机以及死信路由键
  2. 创建交换机创建队列完成绑定(死信)
  3. 发送消息至orderB进行测试查看

过程:

  • 消息先到达orderB
  • 在orderB中的消息到达过期时间后会自动路由至指定的死信交换机并且根据指定的死信路由键将消息发送至死信队列
  • 如果死信队列有消费者那么消息会被消费

image-20200928114113923.png

五、消息幂等问题

mysql的乐观锁方式解决:

image-20200928115600847.png

六、集群搭建

注意事项:

  • 一定要做快照
  • 三台节点之间需要设置统一的erlang-cookie
  • 三台节点必须设置hostname
  • 节点之间需要通过--link来进行连接通信
  • 三台节点必须有一个是磁盘节点, 内存节点

三台节点信息:

erlang-cookie: itheima-31
hostname:myrabbitmq1/myrabbitmq2/myrabbitmq3
端口号: 5672/5673/5674  15672/15673/15674

集群搭建命令:

#1.停止原来的单节点mq
docker stop c_rabbitmq 
#2.启动三台mq
docker run -id --name=myrabbitmq1 --hostname rabbitmq1 -e RABBITMQ_ERLANG_COOKIE='itheima-31' -p 5672:5672 -p 15672:15672 rabbitmq:management
​
docker run -id --name=myrabbitmq2 --hostname rabbitmq2 -e RABBITMQ_ERLANG_COOKIE='itheima-31' -p 5673:5672 -p 15673:15672 --link myrabbitmq1:rabbitmq1 rabbitmq:management
​
docker run -id --name=myrabbitmq3 --hostname rabbitmq3 -e RABBITMQ_ERLANG_COOKIE='itheima-31' -p 5674:5672 -p 15674:15672 --link myrabbitmq1:rabbitmq1  --link myrabbitmq2:rabbitmq2 rabbitmq:management
#3.进入容器内部设置
#myrabbitmq1操作
#进入容器内部
docker exec -it myrabbitmq1 bash
#停止rabbitmq服务
rabbitmqctl stop_app
#清空rabbitmq交换机和队列---》恢复出厂设置
rabbitmqctl reset
#启动rabbitmq服务
rabbitmqctl start_app
#退出
exit#myrabbitmq2操作
#进入容器内部
docker exec -it myrabbitmq2 bash
#停止rabbitmq服务
rabbitmqctl stop_app
#清空rabbitmq交换机和队列---》恢复出厂设置
rabbitmqctl reset
#连接集群,将rabbitmq2设置为内存节点
rabbitmqctl join_cluster --ram rabbit@rabbitmq1
#启动rabbitmq服务
rabbitmqctl start_app
#退出
exit#myrabbitmq3操作
#进入容器内部
docker exec -it myrabbitmq3 bash
#停止rabbitmq服务
rabbitmqctl stop_app
#清空rabbitmq交换机和队列---》恢复出厂设置
rabbitmqctl reset
#连接集群,将rabbitmq3设置为磁盘
rabbitmqctl join_cluster  rabbit@rabbitmq1
#启动rabbitmq服务
rabbitmqctl start_app
#退出
exit

集群存在问题:

队列只存在于一个节点上,如果该节点down机,那么队列不可用,为了解决这个问题可以给队列设置为镜像队列(副本),在设置镜像队列时需要注意:

idea中的服务必须是停止运行,并且三台mq是正常运行,再在任意一台mq进行设置命令操作

idea中的服务必须是停止运行,并且三台mq是正常运行,再在任意一台mq进行设置命令操作

idea中的服务必须是停止运行,并且三台mq是正常运行,再在任意一台mq进行设置命令操作

#为了解决集群中单节点故障后队列依然可以正常使用,这里给所有的队列设置为镜像队列
rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
​
#在任意一个容器中可以查看集群状态
rabbitmqctl cluster_status
​
#注意事项
mq集群中至少需要一台磁盘节点,最好是有两台磁盘节点存在(防止挂掉一台)