提高可靠性通过以下四个方面:

  生产者的可靠性(发送消息时丢失)

    生产者发送消息时连接MQ失败

    生产者发送消息到达MQ后未找到exchange

    生产者发生消息到达MQ的exchange后,未找到合适的queue

    消息到达MQ后,处理消息的进程发生异常

  MQ的可靠性(MQ导致消息丢失)

    消息保存到queue后,未消费就突然宕机

  消费者的可靠性(消费者处理消息丢失)

    消息接收后未处理就发生异常

    消息接收后处理过程中抛出异常

  延迟消息

注意:!生产者重连与生产者确认都相当影响系统性能,一般情况下不建议开启 | rabbitMQ在3.12后无需配置,在3.6后只需将队列改为懒惰队列

生产者:

生产者重连:网络波动可能导致发送者连接MQ失败,我们可以通过配置实现连接失败后重连的机制

spring:
rabbitmq:
connection-timeout: 1s # 设置MQ的连接超时时间
template:
retry:
enabled: true # 开启超时重试机制
initial-interval: 1000ms # 失败后的初始等待时间
multiplier: 1 # 失败后下次的等待时长倍数,下次等待时长 = initial-interval * multiplier
max-attempts: 3 # 最大重试次数

注意:重连是阻塞式的重试,多次等待的过程中,当前线程是阻塞的,会影响性能

生产者确认:开启确认机制后,MQ收到消息会返回确认结果给生产者。SpringAMQP提供了publisherConfirm和publisherReturn两种确认机制

返回结果一般有以下几种:

  消息投递给MQ,路由失败,此时通过publisherRetrun返回路由异常的原因,返回ACK,告知投递成功

  临时消息投递给MQ,入队成功,返回ACK,告知投递成功

  持久化消息投递给MQ,入队成功并持久化,返回ACK,告知投递成功

  其他情况都是NACK,告知投递失败

使用步骤:

spring:
rabbitmq:
publisher-confirm-type: correlated # 开启publisher confirm机制,并设置confirm类型 1.none关闭确认机制,2.simple同步阻塞等待MQ消息,3.correlated异步回调等待MQ消息

   publisher-returns: true # 开启publisher return机制

publisher-return(这个比下面那个常见,一般replyText内会写明为什么失败)为rabbitMQ模板添加return callback(每个template只能添加一个,因此我们统一配置)

@Slf4j
@Configuration
public class MqConfig {
@Autowired
private RabbitTemplate rabbitTemplate; @PostConstruct
public void init() {
rabbitTemplate.setReturnsCallback(returnedMessage -> {
log.error("监听到了return callback");
log.debug("exchange:{}", returnedMessage.getExchange());
log.debug("routingKey:{}", returnedMessage.getRoutingKey());
log.debug("msg:{}", returnedMessage.getMessage());
log.debug("replaytext:{}", returnedMessage.getReplyText());
log.debug("replaycode:{}", returnedMessage.getReplyCode());
});
}
}

publish-confirm(这个一般是编码失败,很少见,而且直接接收到nack。在演示过程中,exchange写错会导致这个问题。所以说这个问题就相当于客户端和rabbitMQ交互时消息压根都没发给正确的交换机

 @Test
public void testCallback(){
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
correlationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
@Override
public void onFailure(Throwable ex) {
log.error("AMQP的异常,不怪我!:",ex);
}
@Override
public void onSuccess(CorrelationData.Confirm result) {
if(result.isAck()){
log.info("收到MQ的ack");
}else {
log.debug("收到MQ的nack:{}",result.getReason());
// TODO 重发消息
}
}
});
rabbitTemplate.convertAndSend("exchangeName","routeKey","message",correlationData);
}

简单来说,生产者确认机制就是一句话:confirm是保证我们发送信息到exchange了,而returns则是保证我们发送到queue了。

MQ:(这一栏基本都是不用配置的)

MQ正常情况下储存机制和redis类似,都是存内存的,因此他会因为宕机丢失,因为内存而阻塞,同样具有持久化策略。

1.数据持久化(AMQP这些都是默认的,不用处理)

  交换机持久化(生成的时候默认就是durable)

  队列持久化(生成的时候默认就是durable)

  消息持久化(这仨用springAMQP发的时候默认都是持久化的)

2.LazyQueue:3.6.0加入,3.12后所有queue都是lazy模式,而且不能改

  特征:收到的消息直接写入磁盘,消费者消费的时候才在磁盘中加载,再投递给消费者,并且可以提前缓存部分消息在内存。

用bean的时候只需要在链式中加上一个.lazy(),用注解的时候需要加上arguments=@Argument(name="x-queue-mode",value="lazy")

消费者:

消费者确认机制:功能类似发送者确认机制。处理完消息后发送下面三种结果

  返回ack:处理成功了,告诉queue销毁msg

  返回nack:处理失败,让queue再发送msg

  返回reject:处理失败了,而且让queue销毁msg

SpringAMQP提供三种配置方式:none,manual(手动档,存在业务入侵,但是更灵活),auto(运用AOP进行环绕增强)

spring:
rabbitmq:
listener:
simple:
acknowledge-mode: auto# 自动挡 爽!

消费者失败重连机制:

spring:
rabbitmq:
listener:
simple:
retry:
enabled: true # 开启消费者失败重试
initial-interval: 1000ms # 初识的失败等待时长为1秒
multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-interval
max-attempts: 3 # 最大重试次数
stateless: true # true无状态;false有状态。如果业务中包含事务,这里改为false

失败后有三种策略:

1.重试次数耗尽后,直接reject,丢弃消息

2.重试次数耗尽后,返回nack,消息重新入队

3.重试次数耗尽后,将失败消息投递给指定的交换机

这里我们选择第三种,在失败后统一将消息传给一个指定投放error消息的队列

先是注册exchange,queue,binding

@Bean
public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){
return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");
}

这样会在消息发送失败之后将消息内容,错误栈统一发送到队列中。

业务幂等性:

幂等是一个数学概念,即f(x)=f(f(x)),在程序开发中,指的是同一个业务,执行一次或者多次对业务的状态是一样的

方案一:唯一消息ID

  1. 每一条消息都生成一个唯一的id,与消息一起投递给消费者。
  2. 消费者接收到消息后处理自己的业务,业务处理成功后将消息ID保存到数据库
  3. 如果又收到相同消息,判断ID是否存在,存在则为重复消息放弃处理

SpringAMQP中的MessageConverter自带了MessageID功能,开启即可

    @Bean
public MessageConverter messageConverter(){
Jackson2JsonMessageConverter jjmc = new Jackson2JsonMessageConverter();
jjmc.setCreateMessageIds(true);
return jjmc;
}

缺点:业务侵入,而且会影响原本的性能

方案二:业务判断实现幂等性

实例

public void paySuccess(Long orderId){
//1.查询订单状态为未支付
Order byId = service.getById(orderId);
//2.判断是否需要进行修改
if(byId==null||byId.getStatus() != 1){
return;
}
//3.修改订单
service.markOrderPaySuccess(orderId);
}

最终兜底方案:延迟消息

1.死信交换机

什么是死信(dead letter)交换机:满足下面条件之一的

  消费者使用basic.reject或者basic.nack声明消费失败,并且消息的requeue参数为false;(处理失败而拒绝的消息)

  消息是一个过期消息,超时无人消费(过期的消息)

  投递的消息队列满了,最早的消息可能成为死信消息(队列满了而被拒绝的消息)

如何实现:队列通过dead-letter-exchange属性指定一个交换机,并且他不会有消费者。那么该队列中的死信就会投递到这个交换机中,这个交换机就是死信交换机。我们可以通过设置消息的ttl来实现消息的延迟发送

2.延迟消息插件(常用,并且较简便)

将普通交换机改造为支持延迟消息功能的交换机,消息投递到队列后可以暂存一段时间,之后再投递到队列

首先是在rabbitMQ中挂载插件并启动 rabbitmq/rabbitmq-delayed-message-exchange: Delayed Messaging for RabbitMQ

在发送时在properties中加入delay,在接受消息的时候,exchange的delay属性设置为true

提高MQ可靠性的更多相关文章

  1. 四种途径提高RabbitMQ传输数据的可靠性(二)

    前言 上一篇四种途径提高RabbitMQ传输消息数据的可靠性(一)已经介绍了两种方式提高数据可靠性传输的方法,本篇针对上一篇中提出的问题(1)与问题(2)提出解决常用的方法. 本文其实也就是结合以上四 ...

  2. (转)IBM MQ 创建以及常见问题集锦

    背景:这篇文章还是很全面的,但是很杂乱 后面慢慢整理吧! 1 MQ 消息队列+发送队列+消息通道 接收通道名称与发送端的发送通道名称要一致,修改通道信息后要执行 start channle(chlna ...

  3. MQ队列管理器搭建(三)

    MQ集群及网关队列管理器的搭建 描述:     如上图所示,为MQ的集群搭建部署图.CLUSTERA.CLUSTERB分别是两个集群,其中Qm1-Qm3.GateWayA为CLUSTERA集群中的队列 ...

  4. IBM MQ 创建以及常见问题集锦

    消息队列+发送队列+消息通道 接收通道名称与发送端的发送通道名称要一致,修改通道信息后要执行 start channle(chlname) 重启通道.常用的MQ命令 66.0.42.240 用户 mq ...

  5. WebSphere MQ性能调优浅谈

    导读:目前随着我们在中国的WebSphere MQ(MQSeries)用户数量越来越多,越来越多的用户开始对MQ使用时的性能优化问题提出要求,我根据日常积累的经验谈一谈在MQ性能优化方面应该考虑的因素 ...

  6. 2.RabbitMQ 的可靠性消息的发送

      本篇包含 1. RabbitMQ 的可靠性消息的发送 2. RabbitMQ 集群的原理与高可用架构的搭建 3. RabbitMQ 的实践经验   上篇包含 1.MQ 的本质,MQ 的作用 2.R ...

  7. ActiveMQ之JMS及保证消息的可靠性<持久化、事务、签收>(三)

    1.JAVAEE 是一套使用Java 进行企业级开发的13 个核心规范工业标准 , 包括: JDBC  数据库连接 JNDI  Java的命名和目录接口 EJB   Enterprise java b ...

  8. 如何保证mq不丢消息

    1.消息的发送流程 一条消息从生产到被消费,将会经历3个阶段 生产阶段,Producer 新建消息,然后通过网络将消息投递给MQ Broker 存储阶段,消息将会存储在Broker端磁盘中 消费阶段, ...

  9. kafka系列四、kafka架构原理、高可靠性存储分析及配置优化

    一.概述 Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cl ...

  10. Kafka数据可靠性深度解读

    原文链接:http://www.infoq.com/cn/articles/depth-interpretation-of-kafka-data-reliability Kafka起初是由Linked ...

随机推荐

  1. .NET 将多个程序集合并成单一程序集的 4+3 种方法

    将 .NET 程序集与依赖合并到一起的方法有下面四种: 使用 .NET Core 3.0 自带的 PublishSingleFile 属性合并依赖使用 Fody使用 SourceYard 源代码包使用 ...

  2. SQL KEEP 窗口函数等价改写案例

    一哥们出条sql题给我玩,将下面sql改成不使用keep分析函数的写法. select deptno, ename, sal, hiredate, min(sal) keep(dense_rank f ...

  3. GCD Timer事件的精度

    一.测试环境 iPhoneX 真机+Debug模式,Timer代码工作在主线程,主线程空闲不阻塞 在子线程统计每3秒tick计数,逐步减小inteval,看能达到多大精度. 忽略原子计数值操作的影响 ...

  4. Qt程序运行报错

    报错内容 PC环境为Ubuntu20.04,Qt版本是Qt5.12.9,AsensingViewer是编译好的程序 ./AsensingViewer: error while loading shar ...

  5. NOIP模拟54

    我觉得,不改变也很好. 前言 这题太难了,场上竟然无人切题..(听说别的学校切题的人不少.. T1 选择 解题思路 范围比较小,并且每个边的度也比较小,因此考虑 树形DP+状压 . 大概就是对于每一个 ...

  6. vscode设置护眼色

    参考链接:https://blog.csdn.net/qq_39233554/article/details/105639331?depth_1- 打开VS code选择'文件'→'首选项'→'设置' ...

  7. 详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项

    为什么会突然想到写这么一个大杂烩的博文呢,必须要从笔者几年前的一次面试说起 当时的我年轻气盛,在简历上放了自己的博客地址,而面试官应该是翻了我的博客,好几道面试题都是围绕着我的博文来提问 其中一个问题 ...

  8. vue带有参数的路由跳转 动态路由

    先定义好路由在router文件下面创建一个新的文件夹里面写上自己定义的路由 export default {   path: '/detail/:id',   component: () =>  ...

  9. Manim使用心得

    Manim 使用心得 manim 做视频还是挺方便的. 当然,如果你每一次都从 0 开始写,那么你会崩溃. 所以需要找到自己做视频的风格,以此总结出一套通用的 python 模板代码,然后调用. 例如 ...

  10. 燕千云 YQCloud 数智化业务服务管理平台 发布1.13版本

    2022年6月10日,燕千云 YQCloud 数智化业务服务管理平台发布1.13版本.本次燕千云1.13版本新增了远程桌面.知识库多人在线协作.移动端疫苗核酸信息管理.单据委托代理.技能管理.产品自助 ...