举个栗子看看消息队列有什么好

消息队列已经逐渐成为企业IT系统内部通信的核心手段;

消息队列消息推送 消息队列发短信_消息队列


上图讲解,我们用最常见的商城系统中的下单成功发送短信场景为例:

(1) 上图中的开始流程A我们假定为用户下单成功, A 到消息A1 呢,是下单成功后,给用户发一条短信通知一下;假如没有使用消息队列,我们一般是下单成功后,系统同步调用发短信的接口来执行短信的发送,并等待短信发送成功.

正常情况下,这样看着是没有什么问题的,这个时候,我们假设一下,假设我们在发短信的时候除了一些问题,如短信实现出问题了, 短信调用端超时了. 又或者短信发送短时间内达到上限了, 这个时候我们无论选择重试,还是放弃又或者将失败信息存入数据库,过几秒再重试, 无论何种设计都让下单逻辑变的负责,而且和短信逻辑耦合过高,不符合设计原则.

(2) 但此时如果使用消息队列,整件个操作就会变得很简单, 我们将发送短信的操作,封装成一条消息,放入消息队列中,此时下单逻辑就完成了,不需要再关心短信发送是否成功. 而消息队列按照一定的顺序(比如最常用的FIFO)处理消息, 通过专门的短信发送系统去发送短信. 如果发送短信出现了问题, 这个时候可以选择把该消息重新放入队列重新执行发送短信. 另外需要其他的配置或者代码逻辑来规定短信失败的次数,以及消息队列处理消息的频率;

使用消息队列,它有了什么好处呢?

  • 首先,异步解耦

第一个做到的就是, 使用消息队列,可以将下单逻辑和发短信逻辑,进行解耦合

  • 业务逻辑的设计变得更加简单

我们无需再在下单逻辑中过多的考虑发送短信的问题,而是放到队列中,让队列去关心发送短信的事情;

  • 保证了业务的最终一致性

我们通过消息队列的这样的设计,保证了消息肯定能最终发送给用户,即使发送短信的功能暂时出现了问题,但消息队列在短信系统恢复之后能够保证将短信成功的发送出去;

  • 如果还需发送邮件…

如果业务要求我们发送完短信,需要发送邮件,如果是接口的逐次调用,是不是就会觉得很耦合很耦合, 太繁杂太繁杂?
但是消息队列的存在, 却能够让发短信和发邮件并行处理两不耽误. 增强了系统的业务处理能力,真棒~~~

消息队列的特性

  1. 业务无关:只做消息分发

消息队列无需关心上层的业务模型, 它只需要做好业务的分发就好了,系统业务的不同模块之间反而需要遵循消息队列制定的规范来进行通信;

  1. FIFO:先投递先到达
  2. 容灾:节点的动态增删和消息的持久化
  3. 性能:吞吐量提升,系统内部通信效率提高

为什么需要消息队列

  1. 生产消费 的速度或稳定性等因素不一致;
  2. 使用消息队列最常见的好处:业务解耦,最终一致性,广播与错峰流控…
  3. 使用消息队列可以做到 业务解耦

所谓解耦,就是一个事务只关心核心的流程, 而需要依赖其它系统但不那么重要的事情呢 有通知即可,无需等待结果. 换句话说,基于消息的模型关心的是通知而不是处理;

  1. 使用消息队列可以做到最终一致性

最终一致性指的是两个系统的状态保持一致, 如阿里的notify, 去哪儿的Q-MQ这两个消息队列框架就是专门为最终一致性而设计的;它们涉及的初衷就是为了交易系统中的高可靠通知;最终一致性不是消息队列必备的,但是我们可以通过消息队列做最终一致性的事情

  1. 使用消息队列可以做到广播

消息队列的基本功能之一就是进行广播,如果没有消息队列,每当有新的业务方接入,我们都需要联调一次新接口. 有了消息队列我们只需要关系消息是否送达到消息队列.新接入的接口订阅相关的消息然后自己进行处理就OK了;

  1. 使用消息队列可以做到错峰与流控

系统上下游,对于业务的处理能力是不同的, 比如:web前端勉强承受上千万的请求是可以做到的, 但是数据库的处理却十分的有限, 处于成本的考虑我们不能奢求数据库的机器数量追上前端;

处理能力的不同还可能表现在系统与系统之间, 由于资源有限,我们分配给边缘业务系统的资源就十分有限,比如短信发送系统,它跟核心业务系统可处理的并发量就完全不是一个数量级的了,但是用户晚个几十秒收到短信问题也不会很大.

以上如果没有消息队列,需要实现需求的话,系统的复杂性比使用消息队列会呈指数倍的增长.我们势必在上游或者下游做些存储,并且要处理定时,阻塞等一系列的问题, 而且每当上下游或者系统之间处理能力有差异的时候,都需要单独开发并维护一套逻辑来处理这个差异;

因此利用中间系统如消息队列,以其作为通信的漏斗,转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候去处理,是一套相对比较通用的方式;

ps:拓展:

  1. 如果需要强一致性,关注业务逻辑的处理结果,RPC会更加合适, RPC即远程调用
  2. 所有跨JVM的一致性问题,从技术的角度讲,通用的解决方案包括两个:(1) 强一致性,(2) 最终一致性
  • 强一致性:是指分布式事务,在这里不做具体讲解;
  • 最终一致性:主要是用记录和补偿的方式来处理,在做所有不确定的事情之前,先把事情记录下来,然后去做不确定的事. 其结果往往有三种, 成功,失败,不确定(如超时…),不确定等价为失败. 如果成功,则可清理掉所有的记录, 如果是失败或者不确定,那我们可以通过定时任务将其重新处理一遍,直到成功为止;