电子商务网站建设 概念,网页加速器,自己的主机做网站服务器,江宁区建设工程质量监督站网站目录 1. RocketMQ如何保证消息不丢失
1.1 分析消息丢失场景
1.2 解决方案
1.2.1 保证消息生产不丢失
1.2.1.1 生产消息时不使用单向发送消息发送模式
1.2.1.2 生产者使用事务消息机制
1.2.2 保证消息存储不丢失
1.2.3 保证消息消费不丢失
1.2.4 RocketMQ特有的问题NameServer挂了如何保证消息不丢失
2. 使用RocketMQ如何快速处理积压消息
2.1 如何确定RocketMQ有大量的消息积压
2.2 如何处理大量积压的消息 1. RocketMQ如何保证消息不丢失
1.1 分析消息丢失场景
下图是一个MQ的通用场景图 从上图中我们可以得到消息流转的4个环节
1生产者发送消息到MQ服务2主从同步3同步磁盘4消费者消费消息 其中1、3、4这3个环节都是跨网络的而跨网络那就可能会丢失消息。 关于3这个环节通常MQ存盘时都会先写入操作系统的缓存page cache中然后再由操作异步的将消息写入硬盘。这个中间有个时间差就可能会造成消息丢失。如果服务挂了缓存中还没有来得及写入硬盘的消息就会丢失。
1.2 解决方案 接下来我们看一下当我们用RocketMQ时,如何解决上述4个环节丢失消息的场景
1.2.1 保证消息生产不丢失
1.2.1.1 生产消息时不使用单向发送消息发送模式 我们想一下消息生产时为什么会丢失消息。当生产者发送消息时如果出现了网络抖动或者消息异常那么消息就有可能丢失。那么这个问题解决思路是什么呢其实简单的来说就是4个字应答重试。 怎么理解应答重试呢 其实就是当生产者发送消息成功后返回成功确认消息如果发送失败客户端就尝试自动重试避免网络抖动导致消息发送不成功。如果超过一定超时时间还是失败那就抛出异常由开发者自己在应用层面进行处理手动重试发送 或者 记录失败。 不过我们需要特别注意是RocketMQ支持多种「消息类型」但是并不是对所有「消息类型」 都会有应答重试机制消息确认机制和失败重试机制。 RocketMQ生产消息时支持多种「消息类型」和「消息发送模式」。有兴趣同学可以参考org.apache.rocketmq.client.producer.MQProducer这个接口定义即可。接下来我们看一下rocketMQ的消息类型和消息发送模式又哪些以及各自的特点 消息类型 普通消息发送普通消息异常时默认重试。普通有序消息发送普通有序消息通过指定「消息筛选器selector」动态决定发送哪个队列。异常默认不重试可以用户自己重试并发送到其他队列。严格有序消息发送严格有序消息通过指定队列保证严格有序异常默认不重试。 消息发送模式 同步调用发送消息方法后同步阻塞直到返回SendResult。配置retryTimesWhenSendFailed重试次数。异步调用发送消息方法后立即返回发送结果会通过开发者自己注册的回调函数SendCallback进行处理。配置retryTimesWhenSendAsyncFailed重试次数。单向发送这种方法完全不关心发送后的返回结果。显然它具有最大吞吐量但也存在消息丢失的潜在风险。 消息类型 和 消息发送模式 是 N * M 的关系所以存在9种不同组合RocketMQ也是定义了9种不同接口方法。 这9种方法里面涉及到「单向发送」模式的3种方法都是不可靠的存在丢失消息的风险。其他发送消息的模式和消息类型可以通过 消息确认、mq-client自动「失败重试机制」、业务自定义重试 等方式确保消息发送不丢失。
1.2.1.2 生产者使用事务消息机制 org.apache.rocketmq.client.producer.MQProducer还定义了「事务消息」的发送模式接下来我们理解一下事务机制因为RocketMQ的事务消息机制就是为了保证零丢失来设计的并且经过阿里的 验证肯定是非常靠谱的。所以事务机制也可以报纸生产者生产消息时不丢失消息。接下来我们用一个场景来简单分析一下事务消息机制是如何保证消息不丢失的。我们看下下面这个流程图 1、为什么要发送个half消息有什么用 这个half消息是在订单系统进行下单操作前发送并且对下游服务的消费者是不可见的。那这个消息的作用更多的体现在确认RocketMQ的服务是否正常。相当于嗅探下RocketMQ服务是否正常并且通知RocketMQ我马上就要发一个很重要的消息了你做好准备。 2.half消息如果写入失败了怎么办 如果没有half消息这个流程那我们通常是会在订单系统中先完成下单再发送消息给MQ。这时候写入消息到MQ如果失败就会非常尴尬了。而half消息如果写入失败我们就可以认为MQ的服务是有问题的这时就不能通知下游服务了。我们可以在下单时给订单一个状态标记然后等待MQ服务正常后再进行补偿操作等MQ服务正常后重新下单通知下游服务。 3.订单系统写数据库失败了怎么办 这个问题我们同样比较下没有使用事务消息机制时会怎么办如果没有使用事务消息我们只能判断下单失败抛出了异常那就不往MQ发消息了这样至少保证不会对下游服务进行错误的通知。但是这样的话如果过一段时间数据库恢复过来了这个消息就无法再次发送了。当然也可以设计另外的补偿机制例如将订单数据缓存起来再启动一个线程定时尝试往数据库写。而如果使用事务消息机制就可以有一种更优雅的方案。 如果下单时写数据库失败(可能是数据库崩了需要等一段时间才能恢复)。那我们可以另外找个地方把订单消息先缓存起来(Redis、文本或者其他方式)然后给RocketMQ返回一个UNKNOWN状态。这样RocketMQ就会过一段时间来回查事务状态。我们就可以在回查事务状态时再尝试把订单数据写入数据库如果数据库这时候已经恢复了那就能完整正常的下单再继续后面的业务。这样这个订单的消息就不会因为数据库临时崩了而丢失。 4.half消息写入成功后RocketMQ挂了怎么办 我们需要注意下在事务消息的处理机制中未知状态的事务状态回查是由RocketMQ的Broker主动发起的。也就是说如果出现了这种情况那RocketMQ就不会回调到事务消息中回查事务状态的服务。这时我们就可以将订单一直标记为新下单的状态。而等RocketMQ恢复后只要存储的消息没有丢失RocketMQ就会再次继续状态回查的流程。 5.下单成功后如何优雅的等待支付成功 在订单场景下通常会要求下单完成后客户在一定时间内例如10分钟内完成订单支付支付完成后才会通知下游服务进行进一步的营销补偿。 如果不用事务消息那通常会怎么办 最简单的方式是启动一个定时任务每隔一段时间扫描订单表比对未支付的订单的下单时间将超过时间的订单回收。这种方式显然是有很大问题的需要定时扫描很庞大的一个订单信息这对系统是个不小的压力。 那更进一步的方案是什么呢是不是就可以使用RocketMQ提供的延迟消息机制。往MQ发一个延迟1分钟的消息消费到这个消息后去检查订单的支付状态如果订单已经支付就往下游发送下单的通知。而如果没有支付就再发一个延迟1分钟的消息。最终在第十个消息时把订单回收。这个方案就不用对全部的订单表进行扫描而只需要每次处理一个单独的订单消息。 那如果使用上了事务消息呢我们就可以用事务消息的状态回查机制来替代定时的任务。在下单时给Broker返回一个UNKNOWN的未知状态。而在状态回查的方法中去查询订单的支付状态。这样整个业务逻辑就会简单很多。我们只需要配置RocketMQ中的事务消息回查次数(默认15次)和事务回查间隔时间(messageDelayLevel)就可以更优雅的完成这个支付状态检查的需求。 6、事务消息机制的作用 整体来说在订单这个场景下消息不丢失的问题实际上就还是转化成了下单这个业务与下游服务的业务的分布式事务一致性问题。而事务一致性问题一直以来都是一个非常复杂的问题。而RocketMQ的事务消息机制实际上只保证了整个事务消息的一半他保证的是订单系统下单和发消息这两个事件的事务一致性而对下游服务的事务并没有保证。但是即便如此也是分布式事务的一个很好的降级方案。目前来看也是业内最好的降级方案。 1.2.2 保证消息存储不丢失 1.2.3 保证消息消费不丢失 1.2.4 RocketMQ特有的问题NameServer挂了如何保证消息不丢失 2. 使用RocketMQ如何快速处理积压消息
2.1 如何确定RocketMQ有大量的消息积压
2.2 如何处理大量积压的消息