(五)消息队列
1 消息队列的优势
1.1 异步
假设系统A需要直接调用系统B、C、D,其中,系统A是主要业务,B、C、D为非主要业务,系统A调用系统B的接口需要200ms,调用系统C的接口需要200ms,调用系统D的接口需要200ms,那么这次请求就需要600ms,如果加入一些其他的业务,执行时间可能会更长,多达数十秒都有可能。此时,为了提高用户体验和吞吐量,其实可以异步地调用系统B、C、D的接口。所以,我们可以通过引入消息中间件,再系统A执行完后将数据写入到消息队列中直接返回,而BCD系统则负责监听执行。
但是这里需要注意的是,为什么异步问题我们不考虑使用线程来处理,基于可扩展性和紧耦合两个点。首先在可扩展性上是极为不便的,一个全链路流程本身是比较长的,需要接很多接口,并且这种添加是动态的,这样会导致添加一次就得重新发布一次。其次系统是紧耦合的,出问题排查也很麻烦,流程里面随便一个地方出问题搞不好会影响其他点。
1.2 解耦
在异步基础上,通过引入消息中间件,即解决了流程RT过高的问题,同时解耦系统,提高了系统的可扩展性。
1.3 削峰
我们再来一个场景,假设我们每个月要搞一次大促,大促期间的并发可能会很高的,比如每秒3000个请求。假设我们现在有两台机器处理请求,并且每台机器只能每次处理1000个请求。那多出来的1000个请求,可能就把我们整个系统给搞崩了。所以,有一种办法,我们可以写到消息队列中。各个子系统根据自己的处理能力去消息队列中拿数据,即便有每秒有8000个请求,那只是把请求放在消息队列中,去拿消息队列的消息由系统自己去控制,这样就不会把整个系统给搞崩。
2 消息队列的问题
消息队列的优势在前面介绍了,但是技术是把双刃剑,使用之后问题也是接踵而至,具体的问题包括系统复杂性、数据一致性与可用性:
- 系统复杂性:本来很简单的一个系统,现在因为接入一个中间件需要考虑维护,并且使用的过程中需要考虑各种问题,特别是消息重复消费、消息丢失、消息的顺序消费问题。
- 数据一致性:以下单为例,包括优惠卷的立减和积分的满减,只有所有的服务都成功才能算这一次下单是成功的,因此应该将下单、优惠卷、积分等都放在一个事务里面一样,要成功一起成功,要失败一起失败。
- 高可用性:原先的系统正常稳定,现在突然接入一个中间件在那放着,一但消息不可用会导致整个系统不可用,因此必须要考虑中间件的高可用性。
3 技术选型
市面上比较流行的消息中间件主要有:ActiveMQ、RabbitMQ、RocketMQ、Kafka等,具体如下:
- 吞吐量:ActiveMQ和RabbitMQ比RocketMQ以及Kafka少了一个量级,在现在大数据的时代吞吐量是真的很重要,比如现在突发一个大新闻,APP注册用户数高达数亿,要想办法在第一时间把突发的新闻全部推送到每个人手上,没有高吞吐量的消息队列很难做到,因此前两者远不如后面两个。
- 稳定性:使用消息中间件最重要的问题之一是确保该中间件的稳定性,前两者远不如后面两个分布式部署的架构,而且多副本的数据能够做到零丢失。稳定性对于一个互联网公司极其重要,拿消息中间件来说,开源产品和商业化消息产品核心功能是没有差别的,两种的区别在于易用性、稳定性、成本方面的竞争力,易用性上的代表是腾讯,稳定性上的代表是阿里,成本竞争力上的代表是华为。从一个系统来说,我们在确保成本符合预算的前提下,应该重保的是系统的稳定性,不然出个P0可以提前打包回家过年了。
- 维护成本:RabbitMQ使用erlang作为开发语言,开发维护成本较高。
- 应用场景:RocketMQ的消息功能是最为完善的,分布式部署,可扩展性强,而Kafaka在消息上的功能比较简单,侧重于大数据领域的实时计算和日志采集等场景。
通过以上分析可知,消息中间件最佳选型为RocketMQ。