关于MQ的一些使用场景

消息队列(MQ)是一种不同应用程序之间(跨进程)的通信方法。应用程序通过写入和检索出入列队的数据(消息)来通信,而无需通过专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用(Remote Procedure Call. RPC)的技术。排队指的是应用程序通过队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。这样就很容易实现一个异步的请求,一下列举消息队列的一些常用场景。

解耦

关于MQ的一些使用场景

  • MQ最直接的使用场景就是可以将两个系统进行解耦,比如我们的货款抵扣业务场景,用户生成订单发送MQ后立即返回,结算系统去消费该MQ进行用户账户金额的扣款。这样订单系统只需要关注把订单创建成功,最大可能的提高订单量,并且生成订单后立即返回用户。而结算系统重点关心的是账户金额的扣减,保证账户金额最终一致。这个场景里面还会涉及到重试幂等性的问题。

削峰填谷

关于MQ的一些使用场景

  • 那么如果通过MQ的方式,将订单存储到MQ队列中,消费端通过拉取的方式,并且拉去速度有消费端来控制,则就可以控制流量趋于平稳。这样对于结算系统来讲,就达到了削峰填谷的目的。或者说起到了流控的目标。

最终一致性

关于MQ的一些使用场景

  • 一致性问题分为强一致性、弱一致性、最终一致性。大多数互联网业务要求实现最终一致性。还是以订单系统和结算系统业务场景举例,订单系统创建成功一个订单后给用户返回的结果即是成功并明确告诉用户会从账户中扣除相应的金额。那么结算系统需要保持跟订单系统相同的状态即从用账户中实际扣除一致的金额。订单系统会涉及两个动作,一个是创建成功订单,一个是发送成功通知到MQ,我们就可以把这两个动作放入到一个本地事务中,要么成功要么失败。当一次发送MQ失败之后,可以结合定时任务进行补偿,这样可以保证生成订单的结果可以落地到mq的存储中。同样结算系统消费端依靠MQ重试机制一直发送消息,直到消费端最终确认扣款业务成功处理完成。这样我们通过消息落地加补偿,消费端从业务上面考虑重复消费的保障,也就是做好幂等性操作,利用MQ实现了最终一致性。

广播消费

  • MQ有两种消息模式一种是点对点模式,一种是发布/订阅模式(最常用的模式)。同时发布/订阅模式按照消费类型又可以分为集群消费和广播消费。大部分情况下我们使用的是集群消费。
    集群消费:MQ发送任何一条消息,集群中只有一台服务器可随机消费到这条消息。如下图:
    关于MQ的一些使用场景

  • 广播消费:MQ发送每一条消息,集群中的每一台服务器至少消费到一次。如下图:

关于MQ的一些使用场景

  • 广播消费注意事项:
    1. 消费进度在消费端管理,比如默认会在主目录下创建offset文件夹,偏移量文件存储在offset目录下,出现重复的概率要大于集群消费。
    2. MQ可以确保每条消息至少被每台消费方服务器消费一次,但是如果消费方消费失败,不会进入重试,因此业务方需要关注消费失败的情况。
    3. 由于广播消费消息不会进行确认,所以管理端上显示的积压数会一直不变,需要以出对数为准。

重试之坑

  • MQ的重试功能可以保证数据结果最终得到处理,但同时也正因为有重试那么在业务处理的时候就需要格外注意幂等性的问题。比如货款抵扣业务,订单系统生成订单之后调用结算平台去扣除用户的账户金额。结算平台要根据流水号去计算,如果订单系统在调用结算平台的时候发生了网络异常,造成了结算平台实际上已经得到请求并且已处理。订单系统一侧认为发生异常需要重试,后续再发送到结算平台的订单就会造成重复扣款问题。所以流水号尤其要注意需要保证重试过程中每次发送的流水号是一致的,结算平台会根据流水号去做业务校验,如果已经处理,则丢弃,最终确保幂等性。

关于MQ的一些使用场景