rabbitmq常见的使用场景及问题解决方案

前言

RabbitMq是基于AMQP协议的开源消息代理软件,与spring的整合在上一篇中已经介绍了。如果想细致了解AMQP可以去spring官网上查看(https://spring.io/projects/spring-amqp#overview)。

如何保证消息投递成功

1.开启应答模式

spring.rabbitmq.publisher-confirms=true

Confirm模式只管有无投递到exchange,而不管有无发送到队列当中。

2.手动应答

spring.rabbitmq.listener.simple.acknowledge-mode=manual

消费者端需要手动应答,可以当作限流使用。

3.返回模式

spring.rabbitmq.publisher-returns=true

用于 消息未投递到queue上的反馈。

4.设置重试次数
如果消费端消费失败不做任何处理的话,会不停的将消息重新塞入队列中,最终耗尽磁盘资源。

spring.rabbitmq.listener.simple.retry.enabled = true
spring.rabbitmq.listener.simple.retry.initial-interval = 1000
spring.rabbitmq.listener.simple.retry.max-attempts = 3

或者在业务代码里做处理,try catch住会有问题的代码,并做出相应的处理。

生产者代码

@Service
public class SendMqService implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
    private static Logger LOGGER = LoggerFactory.getLogger(SendMqService.class);

    private final RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);
    }

    @Autowired
    public SendMqService(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }
    
    public <T> void send(String exchange, String routingKey, T msg) {
        String sign = UUID.randomUUID().toString();
        CorrelationData data = new CorrelationData(sign);
        LOGGER.info("sign:{};exchange:{},routingKey:{}发送mq消息:{}", sign, exchange, routingKey, JSON.toJSONString(msg));
        rabbitTemplate.setMandatory(true);
        this.rabbitTemplate.convertAndSend(exchange, routingKey, msg,data);
        LOGGER.info("sign:{};发送mq消息成功", sign);
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String s) {
        //默认自动应答,检测是否投递到exchange。
        if (ack) {
            System.out.println("确认消息发送成功:" + correlationData);
        } else {
            //消息投递失败,消息满了?各种场景对应不同的处理
            System.out.println("消息发送失败:" + s);
        }
    }

    @Override
    public void returnedMessage(Message message, int i, String s, String s1, String s2) {
        //返回模式  消息为投递到queue时的反馈
        System.out.println(message.getMessageProperties().getCorrelationId() + " 发送失败");

    }
}

生产者代码

@RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "omg.test.queue.fan", durable = "true"),
            exchange = @Exchange(value = "omg.test.exchange.fan", durable = "true", type = ExchangeTypes.FANOUT)))
    public void c1(Message message,Channel channel) throws IOException, InterruptedException {
        System.out.println("收到消息"+new String(message.getBody()));
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        System.out.println("ACK消息");
    }

大量的消息堆积怎么办(ack未应答会导致队列堆积消息)

1.重启
2.消费速率问题,如果不是重要消息,可以直接从控制台上清除。
3.设置队列接受的数量,最大内存大小等。x-max-length x-max-length-bytes
4.消费端限流,push的方式会一直推送消息。可以设置basicQos,即最多同时处理的消息数。

防止消息重复消费

String sign = UUID.randomUUID().toString();
CorrelationData data = new CorrelationData(sign);
rabbitTemplate.convertAndSend(exchange, routingKey, msg,data);

消费端需要将sign做幂等处理,可以入库。

如何保证生产者和消费者的数据一致性问题

1.消费者回调,在消费消息后,调用提前约定好的api,通知生产者。这样做的缺点就是没有避免解耦。
2.补偿机制。生产者发送消息后将信息入库,定义标记位,消费者消费消息后,将状态修改。启定时任务去轮询记录表,捞出未处理的记录,并重新发送。注意设置重试次数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值