RocketMQ-消息中间件选型

1,451 阅读18分钟

应用场景/消息中间件选型

我觉得,消息中间件的选型,主要是看发展历史,一个消息中间件诞生的最初目的是要解决啥问题,了解这个就了解了应用场景,了解了应用场景就知道如何选型。


总的来说

1.ActiveMQ //2010年之前
单体应用,就是比较传统的企业应用程序。

2.RabbitMQ
中小型公司和项目

3.kafka //2010年开源
互联网时代的应用:大规模日志、大数据。//非业务场景 适合水平扩展即集群数量超级大1000个节点以上的分布式应用。

4.阿里metaQ/RocketMQ //完全模仿kafka的设计和架构 和kafka差不多,但是应用场景是具体的业务场景,因为阿里的要求是交易、业务数据比较多,所以对数据可靠性要求特别高,因为这个原因才有了或者说诞生了阿里自己的消息中间件,要不然就直接使用kafka了,而且实际上早期确实是一开始就使用的kakfa。大概是这么一个流程:kafka——》阿里Notify——》阿里metaQ——》阿里RocketMQ。

这个发展历史就是本质原因,也是应用场景和选型的本质原因,其他的细节都只是在阐述这些观点,实现这些观点。


综合上面的材料得出以下两点:

(1)中小型软件公司,建议选RabbitMQ
一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便。正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?所幸,RabbitMQ的社区十分活跃,可以解决开发过程中遇到的bug,这点对于中小型公司来说十分重要。不考虑rocketmq和kafka的原因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,所以kafka排除。不考虑rocketmq的原因是,rocketmq是阿里出品,如果阿里放弃维护rocketmq,中小型公司一般抽不出人来进行rocketmq的定制化开发,因此不推荐。

(2)大型软件公司
根据具体使用在rocketMq和kafka之间二选一。
一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。 www.cnblogs.com/rjzheng/p/8…


与其他消息系统(如ActiveMQ、HornetQ)相比,MetaQ有哪些优势或特点?

1.ActiveMQ和HornetQ都是符合Java EE中JMS规范的MQ实现,两者都是很优秀的开源MQ。同时两者也不局限在JMS规范,同时也支持其他一些MQ协议,如stomp协议、AMQP协议等。相比来说,就我当时了解的情况来看,HornetQ的性能会比ActiveMQ更强,因为HornetQ使用JNI基于异步IO做了更多优化,而对于MQ来说,最终的瓶颈都是落在IO存储上。MetaQ的性能是远远超过这两个MQ的,有一个网友做的比较可以说明一定问题(www.blogjava.net/livery/arti…

ActiveMQ和HornetQ,这两个MQ从诞生起就是为了企业应用而设计的,JMS规范本身也是企业应用系统的规范。这一套东西,我个人认为并不适合互联网应用。互联网应用通常面对的是海量的数据,并且通常对事务一致性的要求相对较弱,而企业应用对事务一致性的要求就相对很高。互联网应用为了处理大量请求,通常采用集群处理的方式,而JMS规范并不重视分布式应用。我说的这个集群不仅仅是服务端broker的集群,还包括生产者和消费者都可能是一个又一个集群,而传统的JMS规范是没有明确处理这些情况的。互联网应用还有一个问题是异构系统特别多,而JMS规范只是Java EE这个平台上的规范,对异构系统的接入也是一个比较麻烦的地方,不同的实现有很大的差异。

2.综合来讲,HornetQ和ActiveMQ是为了企业级应用设计的消息中间件,而MetaQ从一开始就是为了大规模互联网应用设计的消息中间件,两者面对的场景和需求不同。开发者可根据实际的需求,选择合适的产品。 //一个是面向企业级应用,一个是面向大规模分布式互联网的巨大应用

从MQ的发展来看,我们可以看到,出现了越来越多特定领域的消息中间件,例如memcacheq、kestrel、beanstalkd甚至redis,它们很轻量级,并且不想做到全能,而只是解决一个领域的问题,我觉得这是未来的趋势。

总结
一个是面向企业级应用,一个是面向大规模分布式互联网的巨大应用。

kafka

应用场景
1.日志
2.大数据

主要是非业务场景,数据量超级大的那种应用场景。

一开始是为了处理日志。和ElasticSearch差不多。//处理日志的特点就是可靠性不高,因为日志并不需要数据可靠

RabbitMQ

在金融支付领域使用RabbitMQ居多,而在日志处理、大数据等方面Kafka使用居多。

阿里RocketMQ

1.Java编程语言 //其他都是非java语言
2.无需依赖第三方注册中心,因为自己内部实现了简单注册中心 //其他都需要引入第三方注册中心中间件

选型

1.流量小,不需要那么多集群
ActiveMQ
RabbitMQ //因为他们功能丰富,简单易用

2.流量大-集群数量超级大1000以上-且是非业务场景
kafka //比如日志,为什么?因为kafka一开始就为了日志和大数据处理的,日志是非业务场景,所以不需要高可靠,只需要高性能。

3.流量大
阿里 //适合业务场景,为什么?因为业务场景要求高可靠。即消息可靠。


那么,消息中间件性能究竟哪家强?

带着这个疑问,我们中间件测试组对常见的三类消息产品(Kafka、RabbitMQ、RocketMQ)做了性能比较。

Kafka是LinkedIn开源的分布式发布-订阅消息系统,目前归属于Apache定级项目。Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务。

RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。

RocketMQ是阿里开源的消息中间件,它是纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。RocketMQ思路起源于Kafka,但并不是Kafka的一个Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景。//在kafka的基础上,着重解决两点1.消息的可靠性2.事务(本地和分布式)

总结
阿里,在kafka的基础上,着重解决两点1.消息的可靠性2.事务(本地和分布式)。

为什么要同步刷盘?作用是什么?

确保数据可靠性。


同步刷盘是增强一个组件可靠性的有效方式,消息中间件也不例外,Kafka和RabbitMQ都可以支持同步刷盘,但是笔者对同步刷盘有一定的疑问:绝大多数情景下,一个组件的可靠性不应该由同步刷盘这种极其损耗性能的操作来保障,而是采用多副本的机制来保证。


broker丢失消息
当生产者将消息发送到 broker 之后,其实只是将消息缓存到内存中,再由一个线程定时刷入磁盘。这时候如果 broker 宕机,那么这部分存在内存中的数据就丢失了。要杜绝这种情况的发生,我们可以设置log.flush.interval.messages参数为1,这样每有一条消息,broker 就会立刻将消息刷入磁盘,这样就不会发生消息丢失。但是这种方式非常消耗磁盘性能,如果这么做了,那么基本上 Kafka 就没有任何吞吐量优势了。

kafka-水平扩展能力超级强,为什么超级强?

这里还要提及的一个方面是扩展能力,这里我狭隘地将此归纳到可用性这一维度,消息中间件的扩展能力能够增强其用可用能力及范围,比如前面提到的RabbitMQ支持多种消息协议,这个就是基于其插件化的扩展实现。还有从集群部署上来讲,归功于Kafka的水平扩展能力,其基本上可以达到线性容量提升的水平,在LinkedIn实践介绍中就提及了有部署超过千台设备的Kafka集群。


笔者鄙见:RabbitMQ在于routing,而Kafka在于streaming,


框架 特点 业务场景 redis 功能简单 简单的业务场景、规模小 RabbitMQ、ActiveMQ 功能丰富、吞吐量和可用性适中 稍微复杂的业务场景、规模适中(中小公司) RocketMQ 功能丰富、定制化强、吞吐量和可用性高 复杂的业务场景、规模大(大型公司的业务场景) Kafka 吞吐量、可用性超高 规模超大的非业务场景(大型公司的非业务场景)

消息中间件-写读数据的细节

wely.iteye.com/blog/237869…

写读速度快

基于内存文件直接映射。为什么内存文件直接映射速度快?因为没有经过内核进程的切换和调用。

高可用

1.服务器本身集群
2.注册中心
监控挂和新增节点

如何监控异常消息?

消费者重复消费

两种方法
1.基于唯一标识id来避免重复消费
2.基于幂等,幂等的原理仍然是基于唯一标识id

消息可靠性

次数
1.消息至少发送成功一次
2.消息至少被消费一次


1.重复发送
? 2.重复消费


以上的细节,要滚瓜烂熟。

几大要求

消息顺序性
顺序性指的是在一些具体的业务中,前后的业务操作必须有顺序,否则会导致业务处理错误。例如在电商系统中,订单和支付通常是两个不同的业务逻辑,我们通常会将其分拆开来处理。这两个业务逻辑之间存在非常清晰的依赖关系:需要先生成订单,然后才能支付订单。对于这种情况,我们就说订单消息和支付消息是有顺序性的。

对于消息中间件的消息顺序性问题,一般通用的处理方案是保证局部的消息有序。例如对于 Kafka 来说,我们会保证 Partition 区域的消息有序性。对于上面所说的订单消息、支付消息的例子,我们一般会将订单消息和支付消息里的用户ID作为key,将其分配到同一个 partition 中,这样它们就是有序的。

www.cnblogs.com/chanshuyi/p…

重复消费的问题

5、如何保证消息不被重复消费?
分析:这个问题其实换一种问法就是,如何保证消息队列的幂等性?这个问题可以认为是消息队列领域的基本问题。换句话来说,是在考察你的设计能力,这个问题的回答可以根据具体的业务场景来答,没有固定的答案。

回答:先来说一下为什么会造成重复消费?
其实无论是那种消息队列,造成重复消费原因其实都是类似的。正常情况下,消费者在消费消息时候,消费完毕后,会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不同的消息队列发送的确认信息形式不同,例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS成功标志,kafka实际上有个offset的概念,简单说一下(如果还不懂,出门找一个kafka入门到精通教程),就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset,让消息队列知道自己已经消费过了。那造成重复消费的原因?,就是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将该消息分发给其他的消费者。

如何解决?这个问题针对业务场景来答分以下几点
(1)比如,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
(2)再比如,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。
(3)如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。

消费消息的本质是什么?

消费者消费之后,消息队列的数据被会删除,不然消息队列的消息堆积那就是无限多了,内存也不能放得下。

丢数据-消息队列

(2)消息队列丢数据
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。

那么如何持久化呢,这里顺便说一下吧,其实也很容易,就下面两步
1、将queue的持久化标识durable设置为true,则代表是一个持久的队列
2、发送消息的时候将deliveryMode=2 这样设置以后,rabbitMQ就算挂了,重启后也能恢复数据

丢数据-无限重试

可以配置为无限重试

丢数据-消费者

(3)消费者丢数据
这种情况一般是自动提交了offset,然后你处理程序过程中挂了。kafka以为你处理好了。再强调一次offset是干嘛的

offset:指的是kafka的topic中的每个消费组消费的下标。简单的来说就是一条消息对应一个offset下标,每次消费数据的时候如果提交offset,那么下次消费就会从提交的offset加一那里开始消费。 比如一个topic中有100条数据,我消费了50条并且提交了,那么此时的kafka服务端记录提交的offset就是49(offset从0开始),那么下次消费的时候offset就从50开始消费。 解决方案也很简单,改成手动提交即可。//console手动处理

消息中间件-不同模式?广播,单个。主题。这个一定要深入理解,否则,你根本都没有理解消息中间件。

阿里中间件发展历史

为什么选择RocketMQ消息中间件?
主流的MQ有很多,比如ActiveMQ、RabbitMQ、RocketMQ、Kafka、ZeroMQ等。

之前阿里巴巴也是使用ActiveMQ,随着业务发展,ActiveMQ IO 模块出现瓶颈,后来阿里巴巴 通过一系列优化但是还是不能很好的解决,之后阿里巴巴把注意力放到了主流消息中间件kafka上面,但是kafka并不能满足他们的要求,尤其是低延迟(速度快。kafka日志/大数据不是速度更快吗?)和高可靠性(消息可靠)

失败重试次数

消费失败重试
卡夫卡消费失败不支持重试。

RocketMQ消费失败支持定时重试,每次重试间隔时间顺延

总结:例如充值类应用,当前时刻调用运营商网关,充值失败,可能是对方压

力过多,稍后再调用就会成功,如支付宝到银行扣款也是类似需求。

这里的重试需要可靠的重试,即失败重试的消息不因为Consumer宕机导致丢失。

严格的消息顺序

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

RocketMQ支持严格的消息顺序,在顺序消息场景下,一台Broker宕机后,发送消息会失败,但是不会乱序

MySQL的二进制日志分发需要严格的消息顺序

消息堆积能力

理论上Kafka要比RocketMQ的堆积能力更强,不过RocketMQ单机也可以支持亿级(单个消息大小10个字节)的消息堆积能力,我们认为这个堆积能力已经完全可以满足业务需求。

性能

测试结论
在服务端处理同步发送的性能上,Kafka>RocketMQ>RabbitMQ。


测试结论
在消息发送端,消费端共存的场景下,随着Topic数的增加Kafka吞吐量会急剧下降,而RocketMQ则表现稳定。因此Kafka适合Topic和消费端都比较少的业务场景,而RocketMQ更适合多Topic,多消费端的业务场景。

测试结论
Topic数的增加对RocketMQ无影响,长时间运行服务非常稳定。

Kafka 的Topic数量建议不要超过8个。8个以上的Topic会导致Kafka响应时间的剧烈波动,造成部分客户端的响应时间过长,影响客户端投递的实时性以及客户端的业务吞吐量。


测试结论
在Broker进程被Kill的场景, Kafka和RocketMQ都能在保证吞吐量的情况下,不丢消息,可靠性都比较高。

在宿主机掉电的场景,Kafka与RocketMQ均能做到不丢消息,此时Kafka的吞吐量会急剧下跌,几乎不可用。RocketMQ则仍能保持较高的吞吐量。

在单机可靠性方面,RocketMQ综合表现优于Kafka。

参考

mp.weixin.qq.com/s/KfBruI-tO…? //阿里中间件作者 //写的特别好,还有测试结果

www.cnblogs.com/chanshuyi/c… //陈树义

www.cnblogs.com/rjzheng/p/8… //孤独烟 //不是因为这些文章写得有多好,而是实在没有更好的资料。最大的作用是,概括了哪些知识点。

blog.didispace.com/消息中间件选型分析/ mp.weixin.qq.com/s?__biz=MzU… mp.weixin.qq.com/s/ppnfys0sH… //朱小厮

xhrong.github.io/2018/06/13/… //比较总结

www.spring4all.com/article/416

xhrong.github.io/2018/06/13/…

www.flypeng.com/shujuku/red…

blog.didispace.com/消息中间件选型分析/