Como o RabbitMQ garante que as mensagens não sejam perdidas?

Habitue-se a escrever! Este é o terceiro dia da minha participação no "Nuggets Daily New Plan · April Update Challenge", clique para ver os detalhes do evento .

1. Fundo

No processo de entrevista, esta pergunta é uma resposta obrigatória. O blogueiro organizou-o de várias maneiras e resumiu o seguinte. Se houver um requisito de entrevista, você pode recitá-lo adequadamente.

2. O processo de entrega de mensagens

Vamos primeiro explicar um conceito, o que é entrega confiável? No RabbitMQ, uma mensagem enviada do produtor para o servidor RabbitMQ precisa seguir as seguintes etapas:insira a descrição da imagem aqui

  1. O produtor está pronto para entregar a mensagem.
  2. O produtor estabelece uma conexão com o servidor RabbitMQ.
  3. O produtor envia a mensagem.
  4. O servidor RabbitMQ recebe a mensagem e a roteia para a fila especificada.
  5. O servidor RabbitMQ inicia um retorno de chamada para informar ao produtor que a mensagem foi enviada com sucesso.

A chamada entrega confiável é garantir que 100% da mensagem possa ser enviada do produtor para o servidor.

3. Soluções

Os seguintes problemas existem na fila: problema de perda de mensagem, problema de consumo repetido, o seguinte é o ponto de solução

1. Disco rígido permanente em fila

O processo perdido só é perdido quando a memória é enviada para o disco. Se for salvo no disco, a mensagem do serviço de reinicialização não será perdida, mas afetará a eficiência.

new Queue("demo_queue", true, false, false, args); 第二个参数为true
复制代码

2. Confirmação manual

Informe ao produtor que a mensagem foi bem-sucedida/falhou, caso contrário, se falhar, a fila permanecerá suspensa e sua mensagem aguardará. Assim, após a conclusão do consumo, o produtor é notificado se o consumo foi bem-sucedido/falhou, o que é implementado usando ack/nack. Principalmente através do arquivo de configuração para conseguir.

  rabbitmq:
    host: 192.168.xx.xx
    port: 5672
    username: root
    password: root
    virtual-host: /
    listener:
      simple:
        acknowledge-mode: manual  #手动应答
        prefetch: 1 # 每次只处理一个信息
    publisher-confirms: true #开启消息确认机制
    publisher-returns: true #支持消息发送失败返回队列
复制代码
    @RabbitListener(queues = "demo_queue")
    protected void consumerDead(Message message, Channel channel) throws Exception {
        RabbitEnum ackSign = RabbitEnum.ACCEPT;
        try {
            int i = 10 / 0;
        } catch (Exception e) {
            ackSign = RabbitEnum.RETRY;
            throw e;
        } finally {
            // 通过finally块来保证Ack/Nack会且只会执行一次
            if (ackSign == RabbitEnum.ACCEPT) {
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            } else if (ackSign == RabbitEnum.RETRY) {
                channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
            }
        }
    }
复制代码

3. Confirme se o envio foi bem-sucedido

Determine se a mensagem é enviada ao switch.

 @Bean
    public RabbitTemplate rabbitTemplate() {
        Logger logger = LoggerFactory.getLogger(RabbitTemplate.class);
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        // 消息发送失败返回到队列中, yml需要配置 publisher-returns: true
        rabbitTemplate.setMandatory(true);
        // 发送消息确认, yml需要配置 publisher-confirms: true 消息是否发送的核心配置
        rabbitTemplate.setConfirmCallback(msgSendConfirmCallBack());
        // 消息返回, yml需要配置 publisher-returns: true 消息返回的配置
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            String correlationId = message.getMessageProperties().getCorrelationId().toString();
            logger.debug("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {}  路由键: {}", correlationId, replyCode, replyText, exchange,
                routingKey);
        });
        return rabbitTemplate;
    }

    /**
     * 确认发送消息是否成功
     *
     * @return
     */
    @Bean
    public MsgSendConfirmCallBack msgSendConfirmCallBack() {
        return new MsgSendConfirmCallBack();
    }
复制代码
public class MsgSendConfirmCallBack implements RabbitTemplate.ConfirmCallback {

    /**
     * 回调方法
     * @param correlationData
     * @param ack
     * @param cause
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        System.out.println("MsgSendConfirmCallBack  , 回调id:" + correlationData);
        if (ack) {
            System.out.println("消息发送成功");
        } else {
            //可以将消息写入本地,使用定时任务重新发送
            System.out.println("消息发送失败:" + cause + "\n重新发送");
        }
    }

}
复制代码

4. Processamento de cluster

Escusado será dizer que o cluster do ambiente de produção é padrão.

5. Recuperação de desastres em diferentes lugares

6. Resistência

O envio de mensagens persiste para db para reenvio de mensagens. A mensagem do consumidor é fixada no banco de dados e o id da mensagem é usado para determinar se é um consumo repetido.

Acho que você gosta

Origin juejin.im/post/7082381667993649160
Recomendado
Clasificación