消息: 消息体, topic

 

routing key, binding key ,exchanger

 

多个消费者可以订阅同一个队列 ,消息会被分摊

交换器的模式有

direct

topic

fanout( 类似广播,不看routing key)

 

比较下相似的direct,topic,  topic可以用通配符*,比如 *.petrol.*

 

【不重复消费】

db操作的话可以用:唯一索引

另外,用一个第三方介质比如redis 存 ( 全局ID, messageId) , 进行判重

 

 

【rabbitmq可靠性】

 1.生产者端: confirm机制 

  还有个事务

  • 生产端发送消息到broker后,监听从rabbitmq返回的ack确认信息,以触发confirmCallback回调

  • 如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。

 

spring:
  rabbitmq:
    publisher-returns: true
    publisher-confirm-type: correlated

 

@Component 
public class ConfirmCallbackService implements RabbitTemplate.ConfirmCallback { 

  
   @Override 
   public void confirm(CorrelationData correlationData, boolean ack, String cause) { 
      if (ack) { 
        //接收成功 
        
      } else { 
        //接收失败 
      } 
    } 
}

 

rabbitTemplate.setConfirmCallback(confirmCallbackService); 
    //发送消息 
rabbitTemplate.convertAndSend("confirmTestExchange1", "", "hello,ConfirmCallback你好"); 

 

 2. 消费者端:消息确认 basicAck机制 ,死信队列

  

 basicAck:

手动签收消息,给broker回复

 @rabbitlistener 修饰的方法中,使用channel.basicAck( tag , true)  ,

@Component 
@RabbitListener(queues = "confirm_test_queue") 
public class ReceiverMessage { 

  @RabbitHandler 
  public void processHandler(String msg, Channel channel, Message message) throws IOException { 
  
    long deliveryTag = message.getMessageProperties().getDeliveryTag(); 
    try {
      System.out.println("消息内容===>" + new String(message.getBody())); 

      //TODO 具体业务逻辑 

//手动签收[参数1:消息投递序号,参数2:批量签收] channel.basicAck(deliveryTag, true); } catch (Exception e) { //拒绝签收[参数1:消息投递序号,参数2:批量拒绝,参数3:是否重新加入队列] channel.basicNack(deliveryTag, true, true); } } }

 

 

3. rabbitmq自身

【集群】

普通集群: 同一个queue,只有一个实例队列,其他节点只有这个queue的元数据(一些配置信息,可以找到实例)

镜像集群: 同一个queue,每个节点都有这个queue的所有数据 ,缺点是网络和磁盘开销大

持久化

 

 

消费端限流小结

  • rabbit:listener-container 中配置 prefetch属性设置消费端一次拉取多少消息
  • 消费端的确认模式一定为手动确认。acknowledge="manual"

 

 

 【消息积压】

1. 设置消息 TTL

  队列或者发消息时 设置,消息超时加入死信队列处理或者丢弃

2. 增加机器,多消费

 

3. 死信交换器

DLX 是一个普通的交换器,可以在任何队列上设置,

当死信消息出现时,RabbitMQ 自动将这个 消息重新发布到设置的 DLX 上,从而被路由到另一个队列,即 死信队列

消息成为死信的三种情况:

  1. 队列消息长度到达限制;

  2. 消费者拒接消费消息,basicNack/basicReject,并且不把消息重新放入原目标队列,requeue=false;

  3. 原队列存在消息过期设置,消息到达超时时间未被消费;

 

【消息有序性】

方案:

1 .同一组操作的消息发送到同一个queue, 且这个queue对应一个消费者,而queue中消息是有序的,这样就可以了

 

 

如果用多个队列进行消费,应该考虑引入一些机制

2. 延迟处理并利用数据库或缓存存储中间状态

  

  • 实现原理:为每个流程(比如订单)设置特定的状态记录在数据库中或 Redis 缓存中,收到每条消息后验证上一个状态是否已完成。未完成的消息延迟消费,以便前序状态先完成。

 

posted on 2024-10-08 01:44  towboat  阅读(3)  评论(0编辑  收藏  举报