一、什么是消息队列

我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。举个通俗的例子,大学生在学校的时候快递并不是直接送到学生手里,而是暂存到各种代收包裹的站点,再由学生主动取出,而这些站点就相当于一个个消息队列。

二、消息队列的作用

既然要使用消息队列那肯定有他的理由,此时就不得不提三个最经典的场景:异步、削峰、解耦。 以电商平台为例,我们来解释这三个场景

异步:

我们观察下图

消息队列怎么做流量控制 消息队列 知乎_消息队列怎么做流量控制


当业务流程增加时,用户等待支付结束的时间也随之增加,怎么样减少用户等待的时间就成了系统优化的一个重点。

我们小时候应该都有被问过一个问题,小明早晨起床后需要刷牙、煎鸡蛋、背单词…问小明至少需要多少时间才能够完成以上所有任务,到这里我们就应该明白,对于整个业务流程中的多个业务我们没必要一个一个的去完成,完全可以同时进行,这就是异步

消息队列怎么做流量控制 消息队列 知乎_消息队列_02


而使用消息队列就能够轻松实现,用户不需要等待整个流程的结束才得到结果,只需要等待支付所需的时间就可以,这样随着业务的增加也不会影响到用户的体验。

解耦:

当我们知道异步来可以提高效率时,首先我们考虑一下为什么不使用多线程,首先,多线程的代码肯定是需要自己编写,业务少的时候还没什么感觉,但是业务多时候需要编写的代码量也是相当大的。这个时候另一个问题也就出来了,那就是耦合
我们想一下整个业务流程:支付—扣去优惠券—增加积分—发短信。 当其中一个环节出现问题,其他环节很容易受到影响,而且当你想要增加业务的时候,你不仅仅需要编写新的业务逻辑,还需要对原先的代码进行修改,业务越多整个代码就会显得越臃肿。
而使用了消息队列以后就不需要考虑这个问题,就像之前说的快递站点,当快递员将快递放到站点,他的任务就结束了,剩下的就只需要学生去取即可。通过快递站点将原本的快递员运输快递拆解成为快递员将快递放到站点—站点接收—学生取件。 这样也方便在出错时针对特定环节进行错误排查。

削峰:

对于电商平台来说,双十一是让他们又爱又恨,双十一在带来更多的订单的同时也带来了巨大的访问量,尤其是十二点的那一瞬间,如果不好好处理很可能就像一天有多个热点出现的微博,服务直接挂掉(微博:我太难了)。使用消息队列就可以在一定程度上降低这一瞬间的峰值,继续用快递站点的例子,用户访问量就像快递包裹,淘宝网一次性可能无法全部取出,但是我一次不行我分批次不就好了,虽然没有一次取完快但是总比被快递压死好吧,只要服务没断早晚能取完。当然如果你快递太多直接把站点也塞满了那就没办法了,所以消息队列所能做到的也只是将这个峰值压低一些,并不是完全消除。

三、消息队列的两种模式

点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)

消息生产者生产消息发送到Queue中,然后消息消费者从Queue中取出并且消费消息。

消息被消费以后,queue 中不再有存储,所以消息消费者不可能消费到已经被消费的消息。

Queue 支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。

消息队列怎么做流量控制 消息队列 知乎_kafka_03

发布/订阅模式(一对多,消费者消费数据之后不会清除消息)

消息生产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到 topic 的消息会被所有订阅者消费。

消息队列怎么做流量控制 消息队列 知乎_消息队列怎么做流量控制_04

四、消息队列所带来的问题

消息队列虽然有优点,但是我们也不能忽视它所带来的一系列问题

重复消费

对于消费者已经消费过的数据,生产者没有得到反馈所以将消息再次发出,导致消费者消费到相同数据。

消息丢失

生产者发送消息到消息队列,但是可能因为各种故障导致消费者去消费时数据没有了,而生产者也没有再次发出,导致消费者无法消费到这条数据。

消息的顺序消费

加入消费者希望顺序消费十条数据,但是因为网络等原因本该前五条消费的数据变成了后五条消费。

可靠性

如果在系统运行过程中消息队列挂掉而且没有其余的消息队列进行代替,整个系统就会陷入瘫痪。

数据一致性

假设你当前运行的消息队列挂了,你使用备用的消息队列顶上,你怎么保证消费者从备用消息队列消费到的数据能够和原来的消息队列中的数据保持一致?

五、常用消息队列之间的对比

这是四个比较常用的消息队列的对比图:

消息队列怎么做流量控制 消息队列 知乎_大数据_05