简单记录下消息队列的使用场景,以及优缺点还有使用中需要注意的问题。

常见MQ对比

MQ使用场景

解耦

分布式系统时经常会有某个系统调用其他系统的情况,如下图,用户下了一个订单,会在订单系统生成记录,然后用户系统要添加积分,商品系统需要修改销量库存等一系列操作,在没引入消息队列前,各系统间耦合严重,每当修改需求,其他系统不需要订单系统的数据,或者又有新的系统需要订单系统的数据,则每次都要修改订单系统的代码。引入消息队列后,其他系统只需要订阅队列,订单系统则可以不管其他系统如何操作,从而使各系统解耦。

异步

在没有引入MQ前,因为是同步的,所以用户一个请求需要等待所有系统调用成功后才能返回结果,引入MQ后,用户完成下订单操作后就可以直接返回,不用等待其他系统的操作,降低了该请求的耗时。

削峰

当并发量很大的时候,如果程序直接写数据库,数据库会宕机,这时候引入MQ来进行削峰,先把请求写入MQ中,当高峰期后在消费队列中的数据,以防数据库宕机。

MQ产生的问题

系统复杂度

引入MQ,会使系统复杂度大大提高,要额外的维护MQ,而且一般生产环境不会只部署一个MQ服务,为了可用性,都会部署多台MQ做集群。

系统可用性

引入MQ后,如果MQ服务挂了,那整个系统就挂了,所以为了防止某个MQ宕机导致系统挂掉,一般都会做MQ集群,主流的MQ都提供了集群部署模式。

重复数据

一般MQ都会存在出现重复数据的情况,所以要保证系统不重复消费数据,一般都要在消费方操作前查询该消息是否被消费。并且把自动提交已消费改成手动提交,例如kafka自动提交offset改成手动提交,在消息消费成功后手动提交。

消息丢失

如图,生产者P向队列中生产消息,C1和C2消费队列中的消息,默认情况下,MQ会平均的分发消费给C1C2(Round-robin dispatching),假设一个任务的执行时间非常长,在执行过程中,客户端挂了(连接断开),那么,该客户端正在处理且未完成的消息,以及分配给它还没来得及执行的消息,都将丢失。因为默认情况下,MQ分发完消息后,就会从内存中把消息删除掉。


通常的解决办法是使用消息确认机制。基本每个MQ都用类似的机制配置。

消息堆积

如果消费方出现了BUG,消息就会堆积在消息队列中,堆积到消息队列承载的极限,准备挂的时候,通常此时就应该增加机器,然后把原来队列中的数据分发到临时的队列中,然后添加多个消费方来快速消费数据。

按顺序执行

有时候消息需要按顺序消费,可以以某个字段来分发到同一个队列中。消费方如果需要使用多线程来消费,则可以新建临时的内存队列,同理以某个字段分组放到同一个内存队列中消费