java面试---消息中间件之kafka、activemq、ribbitmq、rocketmq详解与区别
首先我们说说为什么要使用队列,什么情况下才会使用队列?
实时性要求不高,且比较耗时的任务,是队列的最佳应用场景。
比如说我在某网站注册一个账号,当我的信息入库注册成功后,网站需要发送一封**邮件,让我**账号,而这个发邮件的操作并不是需要实时响应的,没有必要卡在那个注册界面,等待邮件发送成功,再说发送邮件本来就是一个耗时的操作(需要调用第三方smtp服务器),此时,选择消息队列去处理。注册完成,我只要向队列投递一个消息,消息的内容中包含我要发送邮件的一些设置,以及发送时间,重试次数等消息属性。这里的投递操作(可以是入库,写入缓存等)是要消息进入一个实体的队列。其中应该有一进程(消费者)一直在后台运行,他不断的去轮训队列中的消息(按照时间正序,队列是先进先出),看有没有达到执行条件的,如果有就取出一条,根据消息配置,执行任务,如果成功,则销毁这条消息,继续轮训,如果失败,则重试,知道达到重试次数。这时用户已经收到注册成功的提示,但是已经去做其他事了,邮件也来了,用户点击邮件,注册成功。这就是消息队列的一个典型应用。
再说一个场景,点赞,这个在高并发的情况下,很容易造成数据库连接数占满,到时整个网站响应缓慢,才是就是想到要解决数据库的压力问题,一般就是两种方案,一是提高数据库本身的能力(如增加连接数,读写分离等),但是数据库总是有极限的,到达了极限是没有办法在提升了的,此时就要考虑第二种方案,释放数据库的压力,将压力转移到缓存里面。就拿实际的点赞来说吧,用户的点赞请求到来,我只是将点赞请求投递到消息队列里面,后续的点赞请求可以将消息合并,即只更新点赞数,不产生新的任务,此时有个进行再不断的轮训消息队列,将点赞消息消耗,并将值更新到数据库里面,这样就有效的降低了数据库的压力,因为在缓存层将数个数据库更新请求合并成一个,大大提高了效率,降低了负载。
Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
点对点与发布订阅最初是由JMS定义的。这两种模式主要区别或解决的问题就是发送到队列的消息能否重复消费(多订阅)
消息队列的两种模式及kafka、activemq、ribbitmq的俩种模式区别
JMS规范目前支持两种消息模型:点对点(point to point, queue)和发布/订阅(publish/subscribe,topic)。
1.1、点对点:Queue,不可重复消费
消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。
消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。
1.2、发布/订阅:Topic,可以重复消费
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。
支持订阅组的发布订阅模式:
发布订阅模式下,当发布者消息量很大时,显然单个订阅者的处理能力是不足的。实际上现实场景中是多个订阅者节点组成一个订阅组负载均衡消费topic消息即分组订阅,这样订阅者很容易实现消费能力线性扩展。可以看成是一个topic下有多个Queue,每个Queue是点对点的方式,Queue之间是发布订阅方式。
生产者发送一条消息到queue,一个queue可以有很多消费者,但是一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有 一个可用的消费者,所以Queue实现了一个可靠的负载均衡。
发布者发送到topic的消息,只有订阅了topic的订阅者才会收到消息。topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到这个消息的拷贝。
传统企业型消息队列ActiveMQ遵循了JMS规范,实现了点对点和发布订阅模型,但其他流行的消息队列RabbitMQ、Kafka并没有遵循JMS规范。
RabbitMQ实现了AQMP协议,AQMP协议定义了消息路由规则和方式。生产端通过路由规则发送消息到不同queue,消费端根据queue名称消费消息。
RabbitMQ既支持内存队列也支持持久化队列,消费端为推模型,消费状态和订阅关系由服务端负责维护,消息消费完后立即删除,不保留历史消息。
(1)点对点
生产端发送一条消息通过路由投递到Queue,只有一个消费者能消费到。
(2)多订阅
当RabbitMQ需要支持多订阅时,发布者发送的消息通过路由同时写到多个Queue,不同订阅组消费不同的Queue。所以支持多订阅时,消息会多个拷贝。
Kafka只支持消息持久化,消费端为拉模型,消费状态和订阅关系由客户端端负责维护,消息消费完后不会立即删除,会保留历史消息。因此支持多订阅时,消息只会存储一份就可以了。但是可能产生重复消费的情况。
(1)点对点&多订阅
发布者生产一条消息到topic中,不同订阅组消费此消息。
kafka、activemq、ribbitmq、rocketmq的区别
1.单机吞吐量
ActiveMQ:万级,吞吐量比RocketMQ和Kafka要低一个数量级。
RabbitMQ:万级,吞吐量比RocketMQ和Kafka要低一个数量级。
RocketMQ:10万级,RocketMQ也是可以支撑高吞吐的一种MQ。
Kafka:10万级,这是Kafka最大的优点,就是吞吐量高;一般配合大数据类的系统来进行实时数据基数按、日志采集等场景。
2.Topic数量对吞吐量的影响
ActiveMQ:
RabbitMQ:
RocketMQ:topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降;这是RocketMQ的一大优势,在同等机器下,可以支撑大量的topic。
Kafka:topic从几十个到几百个的时候,吞吐量会大幅度下降所以在同等机器下,kafka尽量保证topic数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源。
3.时效性
ActiveMQ:ms级;
RabbitMQ:微妙级,这是Rabbitmq的一大特点,延迟是最低的;
RocketMQ:ms级;
Kafka:在ms级内。
4.可用性
ActiveMQ:高,基于主从架构实现高可用性;
RabbitMQ:高,基于主从架构实现高可用性;
RocketMQ:非常高,分布式架构;
Kafka:非常高,Kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用。
5.消息可靠性
ActiveMQ:有较低的概率丢失数据;
RabbitMQ:
RocketMQ:参数经过优化配置,可以做到0丢失;
Kafka:参数经过优化配置,可以做到0丢失;
6.功能支持
ActiveMQ:MQ领域的功能及其完备;
RabbitMQ:基于erlang语言开发,并发性能极其好,延时很低;
RocketMQ:MQ功能较为完善,还是分布式的,扩展性能好;
Kafka:功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准;
ActiveMQ社区也不是很活跃。 Kafka 是业内标准的,绝对没问题,社区活跃度很高
activemq因为他是用java开发的,不支持跨语言的这种形式。ribbitmq的话他主要是用在事务级别的,对大数据的处理性能比较弱一点。
ActiveMQ:
1.非常成熟,功能强大,在业内大量的公司以及项目都有应用;
2.偶尔会有较低概率丢失消息;
3.现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ5.x维护越来越少,几个月才发布一个版本;
4.确实主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用。
RabbitMQ:
1.erlang语言开发的,性能极其好,延时很低;
2.吞吐量到万级,MQ功能比较完备;
3.开源提供管理界面非常棒,用起来很好用;
4.社区很活跃,几乎每个月发布几个版本;
5.国内一些互联网公司近几年用RabbitMQ比较多一些;
6.问题是RabbitMQ的吞吐量也会低一些,这是应为它做的实现机制比较重;
7.而且erlang开发,国内有几个公司有实力做erlang源码级别的研究和定制?如果说你没这个实力的话,确实偶尔会有一些问题,很难去看懂源码,公司对这个东西的掌控很弱,基本只能依赖于开源社区的快速维护和修复bug;
8.而且Rabbitmq集群动态扩展会很麻烦,不过这个我觉得还好。其实主要是erlang语言本身带来的问题。很难读源码,很难定制和掌控。
RocketMQ:
1.接口简单易用,而且毕竟在阿里大规模应用过,有阿里品牌保障;
2.日处理消息上百亿之多,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是ok的,还可以支撑大规模的topic数量,支持复杂MQ业务场景;
3.而且一个很大的优势在于,阿里出品都是java系的,我们可以自己阅读源码,定制自己公司的MQ,可以掌控;
4.社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码;
5.还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ挺好的;
1.kafka的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展;
2.同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量;
3.而且kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略;
4.这个特性天然适合大数据实时计算以及日志收集。
消息会有消费失败的情况吗;消费失败系统怎么处理;
kafka的底层是怎么实现的;怎么可以达到这么高的吞吐量
他的话 底层也是使用的多路复用的这种形式 就是我作为一个数据的提供者我去发消息 那么他的话把topic分成一个个postion然后提高并发量所以他的一个性能的话 其实也跟这个有很大的关系 其实postion底层的话 数据的存储也是根据.log文件 跟日志也比较容易混淆 里面的话使用sengment对底层存储分段就是它里面有一个偏移量offset 然后发送他kafka服务器brock上 我们要进行一个存储 我们会根据我们的业务场景进行一个设计来保证我们数据丢失的一个情况 他的话我们平常的话也会设置成为1的一个情况 1的话就是我当前的一个lander接收到就行了 -1的话可能是这个lrp里面所有的从节点都接受到这个数据之后我们才给反馈 客户这边的话发数据也会分这种buffer 我们会给buffer定义一个长度 还有就是分批的一个处理 我给他每次手机达到一个batch 也会去设计一个批处理的量 达到这个数据量之后每一个时间段我给他发送 想这些都可以提高性能
你们用kafka有遇到什么问题吗;
kafka几个基本的概念:
broker: 消息处理结点,多个broker组成kafka集群。
topic: 一类消息,如page view,click行为等。
partition: topic的物理分组,每个partition都是一个有序队列。
replica:partition 的副本,保障 partition 的高可用。
producer: 产生信息的主体,可以是服务器日志信息等。
consumer: 消费producer产生话题消息的主体。
Consumer group:high-level consumer API 中,每个 consumer 都属于一个 consumer group,每条消息只能被 consumer group 的一个 Consumer 消费,但可以被多个 consumer group 消费。
segment: 多个大小相等的段组成了一个partition。
offset: 一个连续的用于定位被追加到分区的每一个消息的***,最大值为64位的long大小,19位数字字符长度。
massage: kafka中最基本的传递对象,有固定格式。
zookeeper:kafka 通过 zookeeper 来存储集群的 meta 信息。
controller:kafka 集群中的其中一个服务器,用来进行 leader election 以及 各种 failover。
partition、segment、offset都是为topic服务的,每个topic可以分为多个partition,一个partition相当于一个大目录,每个partition下面有多个大小相等的segment文件,这个segment是由message组成的,而每一个的segment不一定由大小相等的message组成。segment大小及生命周期在server.properties文件中配置。offset用于定位位于段里的唯一消息,这个offset用于定位partition中的唯一性。
kafka如何保证发的消息是有序的
客户端获取到的每一个postion的数据 其实都是有序的 但是我们客户端这边可能说是并发的这种情况那我们会给他加一个内存优化之类的
方案一,kafka topic 只设置一个partition分区
方案二,producer将消息发送到指定partition分区
解析:
方案一:kafka默认保证同一个partition分区内的消息是有序的,则可以设置topic只使用一个分区,这样消息就是全局有序,缺点是只能被consumer group里的一个消费者消费,降低了性能,不适用高并发的情况
方案二:既然kafka默认保证同一个partition分区内的消息是有序的,则producer可以在发送消息时可以指定需要保证顺序的几条消息发送到同一个分区,这样消费者消费时,消息就是有序。
kafka和activemq和ribbitmq的区别
activemq因为他是用java开发的,不支持跨语言的这种形式。ribbitmq的话他主要是用在事务级别的,对大数据的处理性能比较弱一点。