在说如何选择消息队列之前?首先要明白一个问题,那就是为什么要使用消息队列?可不可以将消息队列用其他的技术代替?
对于为什么使用消息队列可以从三个方面来看,也就是从消息队列的三个核心特点来看:解耦、削峰、异步。
解耦
对于耦合性,可以先来看这么一例子:现在有A、B、C、D四个系统,其中A系统要分别向BCD三个系统发送消息,进行相应的操作。刚一开始这样的场景是OK的,但是系统运行了一段时间后,又加入了一个新的系统E,E系统也需要A系统发送数据,并条用E的接口,此时A系统不得不修改代码,在代码里面专门处理给E系统发送数据。但是过了一段时间后系统D告诉系统A,不需要A给它发送消息了,A系统又屁颠屁颠的去把代码里面给D发送数据的部分给注释或者删除调。对于A系统可能刚开始的时候,一两个改动很简单,但是如果越来越多的要求,那么此时修改起来就很麻烦,A系统就很严重的各种乱七八糟的系统耦合起来。另外A系统还要考虑它说关联的系统如果挂了怎么办?访问系统D超时怎么办?需不需要做重试的机制?等等问题。让系统A耦合较高,处理也比较繁琐。
此时如果引入MQ之后,情况就会大大的不一样了,同样是上面的场景,新系统E需要系统A的消息,只需要去MQ中读取,并不需要告知系统A,让其进行相应的修改;系统D不需要A的消息了,只需要冲MQ中取消对于系统A发送消息的订阅即可。现在整个流程就成了:
1.系统A产生一条数据,发送到MQ里面。
2.哪个系统需要数据自己去MQ里面消费。
3.如果新系统需要数据自己直接从MQ里面消费。
4.如果某个系统不需要这条数据就取消对MQ消息的消费即可。
有了MQ以后,系统A根本就不需要去考虑给谁发数据,也不需要去维护代码,不需要考虑调用者是否调用成功、失败超时等问题。总之,通过一个MQ,发布和订阅消息的这么一个模型,系统A就跟其他系统彻底解耦了。
流量削峰
流量削峰顾名思义,就是协调处理流量洪峰,让流量分批次处理,从而减轻服务器的压力,很形象的一个比喻就是消息队列就像“水库”一样,拦蓄上游的洪水,削减进入下游河道的洪峰流量,从而达到减免洪水灾害的目的。对于春节火车票抢购,大量的用户同一时间去抢购,又比如大家熟知的阿里双11秒杀,短时间内上亿的用户涌入,瞬间流量巨大。
就用Mysql的请求数来解释流量削峰的好处。Mysql的请求数量是有一定限制的,根据服务器的不同各有不同,就像我的服务器,默认的为151个请求。如果某一时刻,有两百个用户同时的对我的网站进行大量的操作,大量的请求就会涌入我的系统中,高峰期也有可能达到三四百个请求,系统是基于Mysql,所以此时对于Mysql执行的SQL操作也就有三四百条,此时很明显我的Mysql支持不了这么多操作,Mysql就无法正常运行,然后用户就不能对我的网站进行操作。但是平时又不可能会有这么大的并发量,对于系统的运行几乎没有任何压力。当然此处只是做个例子,线上的Mysql的最大请求数不可能会这么低,但是也会存在这么一个问题。
加入了MQ之后的情况又是怎么样呢?当大量的操作和请求涌入服务器,假设每秒有500个请求,将这500个请求写入MQ中,系统因为Mysql的最大并发数量为151,所以每买哦中只能处理151个请求。系统从MQ中慢慢拉取请求,每秒钟就取151个请求就可以了,此时哪怕最高峰值的时候,系统也不会挂掉,因为所有的请求都存在MQ中,Mysql也每秒处理着最大并发数量的请求。虽然对于MQ来说每秒进入500个请求,151请求出去,在高峰期的时间内,可能会积压几千的请求,但是这些都是没有问题的,因为等高峰期过后,Mysql还是会按照每秒151个请求处理,因此,只要高峰期已过,系统就会快速的将积压的信息给解决掉。
异步处理
所谓异步就是一个请求操作的内容分为几个步骤,这几个步骤并不需要是同步的,比如顾客下单创建了一个订单,下了订单还需要去更新库存系统、用户积分系统中的顾客积分等等。如果这些操作都是同步的,那么顾客请求一次,就会产生大量的等待时间,这样对于用户是无法接受的。后面的这些操作可以存入MQ里面,然后去异步操作,这样可以加快系统的访问速度,提供更好的客户体验。
消息队列的优点也是上面所说的三个核心特点。对应的缺点也因为优点所引起。
系统可用性降低: 系统引入外部依赖越多,越容易挂掉,之前就是一个A系统调用BCD三个系统的接口就好了,现在加了一个MQ,如果MQ系统挂掉,那么整套系统就会崩溃。
系统复杂性提高:加入了MQ系统进来,不能保证消息有没有重复消费,消息丢失的情况该如何处理,怎么保证消息传递的顺序等等问题也随之而来。
一致性问题:A系统处理完成之后就返回成功,你以为这个请求成功。但问题是,如果BCD三个系统如果有一个系统的操作失败,那么数据就不会一致。
现在经常的MQ有ActiveMQ、RabbitMQ、RocketMQ和Kafka。这四个MQ各有各自的优缺点。
特性 |
ActiveMQ |
RabbitMQ |
RocketMQ |
Kafka |
单机吞吐量 |
万级,吞吐量比RocketMQ和Kafka要低了一个数量级 |
万级,吞吐量比RocketMQ和Kafka要低了一个数量级 |
10万级,RocketMQ也是可以支撑高吞吐的一种MQ |
10万级别,这是kafka最大的优点,就是吞吐量高。
一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic数量对吞吐量的影响 |
|
|
topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降
这是RocketMQ的一大优势,在同等机器下,可以支撑大量的topic |
topic从几十个到几百个的时候,吞吐量会大幅度下降
所以在同等机器下,kafka尽量保证topic数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源 |
时效性 |
ms级 |
微秒级,这是rabbitmq的一大特点,延迟是最低的 |
ms级 |
延迟在ms级以内 |
可用性 |
高,基于主从架构实现高可用性 |
高,基于主从架构实现高可用性 |
非常高,分布式架构 |
非常高,kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 |
有较低的概率丢失数据 |
|
经过参数优化配置,可以做到0丢失 |
经过参数优化配置,消息可以做到0丢失 |
功能支持 |
MQ领域的功能极其完备 |
基于erlang开发,所以并发能力很强,性能极其好,延时很低 |
MQ功能较为完善,还是分布式的,扩展性好 |
功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准 |
优劣势总结 |
非常成熟,功能强大,在业内大量的公司以及项目中都有应用
偶尔会有较低概率丢失消息
而且现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ 5.x维护越来越少,几个月才发布一个版本
而且确实主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用
|
erlang语言开发,性能极其好,延时很低;
吞吐量到万级,MQ功能比较完备
而且开源提供的管理界面非常棒,用起来很好用
社区相对比较活跃,几乎每个月都发布几个版本分
在国内一些互联网公司近几年用rabbitmq也比较多一些
但是问题也是显而易见的,RabbitMQ确实吞吐量会低一些,这是因为他做的实现机制比较重。
而且erlang开发,国内有几个公司有实力做erlang源码级别的研究和定制?如果说你没这个实力的话,确实偶尔会有一些问题,你很难去看懂源码,你公司对这个东西的掌控很弱,基本职能依赖于开源社区的快速维护和修复bug。
而且rabbitmq集群动态扩展会很麻烦,不过这个我觉得还好。其实主要是erlang语言本身带来的问题。很难读源码,很难定制和掌控。 |
接口简单易用,而且毕竟在阿里大规模应用过,有阿里品牌保障
日处理消息上百亿之多,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是ok的,还可以支撑大规模的topic数量,支持复杂MQ业务场景
而且一个很大的优势在于,阿里出品都是java系的,我们可以自己阅读源码,定制自己公司的MQ,可以掌控
社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码
还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ挺好的 |
kafka的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展
同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量
而且kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略
这个特性天然适合大数据实时计算以及日志收集 |
因此一般的业务系统要引入MQ,最早的时候都用AactiveMQ。但是现在用的不多,没有经过大规模吞吐量场景的验证,社区也不是很活跃。后来开始使用RabbitMQ,但是由于RabbitMQ是由erlang语言阻止了大梁Java工程师的研究,对公司而言,几乎处于不可控的状态,但是确实是开源的,比较稳定的支持,活跃度也高。另外现在也有越来越多的公司会去使用RocketMQ,但是社区万一突然黄掉的风险,所以自己公司没有实力,就还是使用RabbitMQ。如果是大数据领域的实时计算、日志采集等场景,用Kafka是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄。