热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

消息中间件优缺点对比及选型

什么是消息队列?(Messagequeue,简称MQ)从字面理解就是一个保存消息的一个容器。那么我们为何需要这样一个容器呢?其实就是为了解耦各个系统,我们来举个例子:有这么一个简单

什么是消息队列?(Message queue,简称MQ)

从字面理解就是一个保存消息的一个容器。那么我们为何需要这样一个容器呢?

其实就是为了解耦各个系统,我们来举个例子:



有这么一个简单的场景,系统A负责生成userID,并调用系统B、C。如果系统BC频繁变化是否需要userID参数,则系统A的代码就得不断变化,如果哪天又来了系统DEF……也需要这个参数,则系统A又要加入很多业务逻辑,这样子各他系统之间就容易产生相互影响,另外大量的系统与A发生交互也容易产生问题。



加了消息队列后,A只负责产生userID,至于谁要用这个参数,怎么用?系统A不管。对这个数据感兴趣的系统自己去取用即可,各个系统之间就实现了解耦。而且解耦后,整个服务业变成了一个异步的方式,系统A产生数据后,不用依次调用BCD来累计耗时,各系统可以同时来取用消息队列的数据进行处理,加大吞吐。


消息队列的特点



  1. 先进先出:消息队列的顺序在入队的时候就基本已经确定了,一般是不需人工干预的。

  2. 发布订阅:发布订阅是一种很高效的处理方式,如果不发生阻塞,基本可以当成是同步操作。

  3. 持久化:持久化确保消息队列的使用不只是一个部分场景的辅助工具,而是让消息队列能像数据库一样存储核心的数据。

  4. 分布式:在现在大流量、大数据的使用场景下,支持分布式的部署,才能被广泛使用。消息队列的定位就是一个高性能的中间件。


什么是中间件?

非底层操作系统软件,非业务应用软件,不是直接给最终用户使用的,不能直接给客户带来价值的软件统称为中间件。


什么是消息中间件?

关注于数据的发送和接受,利用高效可靠的异步消息传递机制集成分布式系统。


消息中间件的作用(解耦,并发,削峰,异步)



  1. 可以在模块、服务、接口等不同粒度上实现解耦

  2. 订阅/消费模式可以在数据粒度上解耦

  3. 可提高系统的并发能力,集中力量办大事(同步部分),碎片时间做小时(异步部分)

  4. 可提高系统可用性,因为缓冲了系统负载


消息中间件的弊端



  • 系统可用性降低:MQ宕机之后整套系统均不能正常使用,如果要保障队列可用,需要额外机制保障(双活或容灾)

  • 系统复杂性提高:存在消息重复消费、消息丢失、消息传递顺序不能保证的问题

  • 降低数据一致性:多个系统消费存在部分成功部分失败的问题,数据不一致了,如要保持强一致性,需要高代价的补偿(分布式事务,对账)


重复消费:系统发了两条,两条都插入了数据库

消息丢失:系统根本没法请求到目标系统

一致性问题:系统要再ABC三个系统都执行成功之后才返回成功,结果AB成功了,C失败了



消息队列的使用场景

消息队列的使用场景有很多,最核心的有三个:解耦、异步、削峰

解耦:一个系统或者一个模块,调用了多个系统或者模块,相互之间的调用很复杂,维护起来很麻烦。此时可以考虑使用消息队列来实现多个系统之间的解耦

异步:系统A接受一个请求,需要在自己本地写库,还需要在系统BCD三个系统写库,同步操作比较费时。

削峰:高峰时段系统接收到的请求缓存到消息队列,供系统根据负载慢慢消化


秒杀、发邮件、发短信、高并发订单等。

不适合的场景如银行转账、电信开户、第三方支付等。

关键还是要意识到队列的优劣点,然后分析场景是否使用。



MQ的6种工作模式:



  • 简单模式:一个生产者,一个消费者

  • work模式:一个生产者,多个消费者,每个消费者获取到的消息唯一。

  • 订阅模式:一个生产者发送的消息会被多个消费者获取。

  • 路由模式:发送消息到交换机并且要指定路由key ,消费者将队列绑定到交换机时需要指定路由key

  • topic模式:将路由键和某模式进行匹配,此时队列需要绑定在一个模式上,“#”匹配一个词或多个词,“*”只匹配一个词。


市面上常见的消息中间件

ActiveMQ、RabbitMQ、RocketMQ、kafka


消息中间件的对比























































































































特性ActiveMQRabbitMQRocketMQkafka
语言JavaErlangJavaScala
单机吞吐十万,支撑高吞吐十万
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)
管理界面一般比较好一般一般
时效性msus微秒级msms(以内)
功能特性MQ功能齐全,被大量开源项目使用。基础erlang开发,所以并发能力很强,性能极其好,延时很低,管理界面很丰富,支持多语言MQ功能比较完备,扩展性佳,仅适用于Java语言。只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为了大数据准备的,在大数据领域应用广。
适用场景主要场景就是解耦和异步调用,较少在大规模吞吐的场景中使用数据量没有那么大,小公司目前在阿里被广泛应用在订单、交易、充值、流计算、消息推送、日志流式处理、binglog分发消息等场景。一般配合大数据类的系统来进行实时数据计算、日志采集等场景。
broker端消息过滤支持不支持可以支持Tag标签过滤和SQL表达式过滤不支持
消息查询支持根据消息id查询支持Message id或Key查询不支持
消息回溯支持不支持支持按时间来回溯消息,精度毫秒,例如从一天之前的某时某分某秒开始重新消费消息。理论上可以支持时间或offset回溯,但是得修改代码。
路由逻辑基于交换机,可配置复杂路由逻辑根据topic,可以配置过滤消费根据topic
持久化内存、文件、数据库队列基于内存,只能少量堆积磁盘,大量堆积磁盘,大量堆积
顺序消息支持不支持支持支持
消费并行度无影响无影响顺序消费方式并行度同kafka完全一致;乱序方式并行度取决于消费者的线程数,如topic配置10个队列,10台机器消费,每台机器100个线程,那么并行度为1000。kafka的消费并行度依赖topic配置的分区数,如分区数为10,那么最多10机器来并行消费(每台机器只能开一个线程),或者一台机器消费(10个线程并行消费)。即消费并行度和分区数一致。
消息可靠性有较低的概率丢失数据基本不丢经过参数优化配置,可以做到 0 丢失同 RocketMQ

各自的优缺点:

ActiveMQ



  • 采用消息推送方式,所以最适合的场景是默认消息都可在短时间内被消费。数据量越大,查找和消费消息就越慢,消息积压程度与消息速度成反比。

  • 主要场景就是解耦和异步调用,较少在大规模吞吐的场景中使用。

缺点:



  • 吞吐量低。由于ActiveMQ需要建立索引,导致吞吐量下降。

  • 偶尔会有较低概率丢失消息;

  • 不支持消息自动分片机制。这是一个功能缺失,JMS并没有规定消息中间件的集群、分片机制。ActiveMQ初衷并不是为了处理海量消息和高并发请求。如果一台服务器不能承受更多消息,则需要横向拆分。ActiveMQ官方不提供分片机制,需要自己实现。

  • 一般的业务系统要引入MQ,最早大家都用ActiveMQ,但是现在确实大家用的不多了,没经过大规模吞吐量场景的验证,社区也不是很活跃,所以不推荐用这个了。

RabbitMQ



  • 项目开源,社区活跃,管理界面丰富,适用于中小型公司。

  • erlang开发,队列基于内存,并发高,延时低,基于AMQP协议支持多语言接入。

  • 特有的交换机模式,支持很多复杂场景的消息路由。

缺点:



  • 基于erlang也影响java人员的探索和改造,遇到bug调试起来比较麻烦。

  • 队列只能支持主备,不可分布式扩展,单点问题是硬伤,投递消息如果不在某台虚拟机上,还需要虚拟机转发请求。

  • 队列基于内存,导致无法大量堆积消息。

  • 不支持顺序消息,消息消费失败后会重回队列,打乱顺序。

  • 需要学习比较复杂的接口和协议,学习和维护成本较高。

RocketMQ



  • 阿里双十一经受了许多考验,使用广泛,基于Java语言适合大公司自己改造。

  • 对比Kafka,MQ功能较为完善,额外支持消息查询,消息回溯,消息重试,延迟消息,适合复杂业务场景。

  • 吞吐量相比RabbitMQ高,可用性非常高,分布式架构,扩展性好,支持分布式事务,解耦异步调用。

  • 支持10亿级别的消息堆积,不会因为堆积导致性能下降。

  • 消息可靠性:经过参数优化配置,消息可以做到0丢失。

  • 提供 docker 镜像用于隔离测试和云集群部署。




  • 天生为金融互联网领域而生,对于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰,在大量交易涌入时,后端可能无法及时处理的情况。

  • RoketMQ在稳定性上可能更值得信赖,这些业务场景在阿里双11已经经历了多次考验,如果你的业务有上述并发场景,建议可以选择RocketMQ。


缺点:



  • 社区不够活跃,github上讨论不多,社区可能有黄掉的风险。(目前RocketMQ已捐给Apache)

  • 支持的语言不多,只支持java及c++,其中c++不成熟

  • 没有在 mq 核心中去实现JMS等接口,有些系统要迁移需要修改大量代码

kafka



  • 性能卓越,单机写入TPS约在百万条/秒,最大的优点,就是吞吐量高;

  • 可用性非常高,kafka是分布式的,一个数据多个副本,某个节点宕机,Kafka 集群能够正常工作;

  • 持久性、可靠性: Kafka 能够允许数据的持久化存储,消息被持久化到磁盘,并支持数据备份防止数据丢失,Kafka 底层的数据存储是基于 Zookeeper 存储的,Zookeeper 我们知道它的数据能够持久存储;

  • 优秀的第三方Kafka Web管理界面Kafka-Manager;

  • 在日志领域比较成熟,被多家公司和多个开源项目使用;

  • 主要是用来进行实时数据计算的以及日志收集,现在的项目里面很少用它做消息中间件。

kafka高吞吐率的实现:



  1. 顺序读写:kafka将消息读写写入到了分区partition中,而分区消息是顺序读写的。顺序读写要远快于随机读写

  2. 零拷贝:生产者、消费者对于kafka中消息的操作都是采用零拷贝实现的

  3. 批量发送:kafka允许采用批量消息发送模式

  4. 消息压缩:kafka允许对消息集合进行压缩

缺点:



  • Kafka单机超过64个队列/分区,Load会发生明显的飚高现象,队列越多,Load越高,发送消息响应时间越长。

  • 功能比较简单,主要聚集于日志场景和流计算,对业务型场景支持不够。

  • 使用短轮询方式,实时性取决于轮询间隔时间;

  • 消费失败不支持重试;

  • 支持消息顺序,但是一台代理宕机后,就会产生消息乱序;

  • 社区更新较慢。


对MQ的吞吐量与可用性,可靠性上进行比对


单机吞吐量

ActiveMQ、RabbitMQ单机吞吐量为万级;

RocketMQ、Kafka可以达到10万级的吞吐量。


topic数量对吞吐量的影响

RocketMQ和Kafka会受到topic数量的影响。

Kafka的topic从几十到几百个增加的时候,吞吐量会大幅度下降。在同等机器下,kafka尽量保证topic数量不要过多,如果需要支撑大规模的topic,需要增加更多的机器资源。

因为Kafka的每个Topic、每个分区都会对应一个物理文件。当Topic数量增加时,消息分散的落盘策略会导致磁盘IO竞争激烈成为瓶颈。

RocketMQ的topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic。

RocketMQ所有的消息是保存在同一个物理文件中的,Topic和分区数对RocketMQ也只是逻辑概念上的划分,所以Topic数量的增加对RocketMQ的性能不会造成太大的影响。


可用性

ActiveMQ和RabbitMQ在高可用上采用主从架构实现的高可用。

RocketMQ和Kafka采用的分布式架构来保证高可用性。


消息可靠性

ActiveMQ有较低的概念丢失数据。

RabiitMQ基本上不会丢, 但是还是无法得到保证。

RocketMQ与Kafka经过优化配置,可以做到0丢失。


综上,有如下建议:

首先,个人不推荐使用ActiveMQ,社区不活跃,并且没有经过大规模的吞吐量场景的验证。

你永远无法想象MQ消息丢失或者宕机带来的影响有多巨大。

RabbitMQ使用Erlang开发,对JAVA工程师来说较难深入的研究和掌握,对公司而言,几乎是处于不可控的状态。 但是, RabbitMQ开源社区一直都在活跃,并且有稳定的支持。

RocketMQ是阿里的开源产品(但是,阿里自己的内部版本是商业版本,在阿里云可以直接购买服务),阿里的开源产品,如果有使用的同学应该会有较大的感触,有可能会突然黄掉!所以,如果使用RocketMQ的话,需要对自己公司的技术能力有一定的要求。

Kafka主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用。 Kafka目前无法支持如延迟队列(需要额外的业务处理支持), 在较新的版本只支持了事务消息。 但是整体而言,支持的业务场景较少。


总体而言:



  • 中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;

  • 大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。(当然,需要对RocketMQ 进行一定的改造。 如对延迟消息的控制级别)。

  • 如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。

查看更多关于消息队列选型及原理


消息队列常见问题


如何保证消息队列的高可用?

RabbitMQ基于主从的高可用,分为单机模式、普通集群模式、镜像集群模式三种

普通集群模式:多台服务器部署RabbitMQ,一个queue只会保存在一个节点上,其他节点只会同步该queue的元数据,当请求从其他节点获取该queue的数据时,该节点会再次去存储该queue的节点上拉取所需数据。这样就导致使用时要么固定使用其中一个节点,要么随机节点再需要的时候拉取数据。如果存放数据的节点宕机了,其他节点就无法拉取数据,如果开启了消息持久化让RabbitMQ落地存储消息就不一定会丢失消息,得等这个实例恢复后才能继续从这个queue拉取数据。

镜像集群模式(高可用模式):创建的queue会同步到所有实例上来实现高可用。这样会带来同步数据的开销和扩展性降低(扩展机器会导致新增的机器同步queue增加更多同步数据的开销);配置方式可通过控制台配置。

Kafka的高可用:分布式消息队列

Kafka由多个broker组成,每个broker是一个节点,创建的一个topic划分为多个partition,每个partition可放在不同的broker上,每个partition只存放一部分数据。



推荐阅读
author-avatar
杨斜2602934873
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有