为什么要使用消息队列?
使用消息队列的主要目的主要记住这几个关键词:解耦、异步、削峰填谷。
解耦: 在一个复杂的系统中,不同的模块或服务之间可能需要相互依赖,如果直接使用函数调用或者 API 调用的方式,会造成模块之间的耦合,当其中一个模块发生改变时,需要同时修改调用方和被调用方的代码。而使用消息队列作为中间件,不同的模块可以将消息发送到消息队列中,不需要知道具体的接收方是谁,接收方可以独立地消费消息,实现了模块之间的解耦。
异步: 有些操作比较耗时,例如发送邮件、生成报表等,如果使用同步的方式处理,会阻塞主线程或者进程,导致系统的性能下降。而使用消息队列,可以将这些操作封装成消息,放入消息队列中,异步地处理这些操作,不影响主流程的执行,提高了系统的性能和响应速度。
削峰填谷:削峰填谷是一种在高并发场景下平衡系统压力的技术,通常用于平衡系统在高峰期和低谷期的资源利用率,提高系统的吞吐量和响应速度。在削峰填谷的过程中,通常使用消息队列作为缓冲区,将请求放入消息队列中,然后在系统负载低的时候进行处理。这种方式可以将系统的峰值压力分散到较长的时间段内,减少瞬时压力对系统的影响,从而提高系统的稳定性和可靠性。
另外消息队列还有以下优点:
1**.可靠性高:**消息队列通常具有高可靠性,可以实现消息的持久化存储、消息的备份和故障恢复等功能,保证消息不会丢失。
2.**扩展性好:**通过增加消息队列实例或者添加消费者实例,可以实现消息队列的水平扩展,提高系统的处理能力。
**3.灵活性高:**消息队列通常支持多种消息传递模式,如点对点模式和发布/订阅模式,可以根据不同的业务场景选择不同的模式。
扩展知识
消息队列实现
市面上有很多成熟的消息队列中间件可以供我们使用,其中比较常用的有kafka、activeMQ、RabbitMQ和RocketMQ等。
Kafka、ActiveMQ、RabbitMQ和RocketMQ都有哪些区别?
典型回答
Kafka、ActiveMO、RabbitMQ和RocketMQ都是常见的消息中间件,它们都提供了高性能、高可用、可扩展的消息传递机制,但它们之间也有以下一些区别:
1.消息传递模型:Kafka主要支持发布-订阅模型,ActiveMQ、RabbitMQ和RocketMQ则同时支持点对点和发布-订阅两种模型。
2.性能和吞吐量:Kafka在数据处理和数据分发方面表现出色,可以处理每秒数百万条消息,而ActiveMQ、RabbitMQ和RocketMQ的吞吐量相对较低。
3.消息分区和负载均衡:Kafka将消息划分为多个分区,并分布在多个服务器上,实现负载均衡和高可用性。ActiveMQ、RabbitMQ和RocketMQ也支持消息分区和负载均衡,但实现方式不同,例如RabbitMQ使用了一种叫做Sharding的机制。
4.开发和部署复杂度:Kafka相对比较简单,易于使用和部署,但在实现一些高级功能时需要进行一些复杂的配置。ActiveMQ、RabbitMQ和RocketMQ则提供了更多的功能和选项,也更加灵活,但相应地会增加开发和部署的复杂度。
5.社区和生态:Kafka、ActiveMQ、RabbitMQ和RocketMQ都拥有庞大的社区和完善的生态系统,但Kafka和RocketMQ目前的发展势头比较迅猛,社区活跃度也相对较高。
6.功能支持:
总的来说,这些消息中间件都有自己的优缺点,选择哪一种取决于具体的业务需求和系统架构。
扩展知识
如何选型
在选择消息队列技术时,需要根据实际业务需求和系统特点来选择,以下是一些参考因素:
1.性能和吞吐量:如果需要处理海量数据,需要高性能和高吞吐量,那么Kafka是一个不错的选择
2.可靠性:如果需要保证消息传递的可靠性,包括数据不丢失和消息不重复投递,那么RocketMQ和RabbitMQ都提供了较好的可靠性保证。
3.消息传递模型:如果需要支持发布-订阅和点对点模型,那么RocketMQ和RabbitMQ是一个不错的选择。如果只需要发布-订阅模型,Kafka则是一个更好的选择
4.消息持久化:如果需要更快地持久化消息,并且支持高效的消息查询,那么Kafka是一个不错的选择。如果需要更加传统的消息持久化方式,那么RocketMO和RabbitMO可以满足需求
5.开发和部署复杂度:Kafka比较简单,易于使用和部署,但在实现一些高级功能时需要进行一些复杂的配置RocketMQ和RabbitMQ提供了更多的功能和选项,也更加灵活,但相应地会增加开发和部署的复杂度。
6.社区和生态:Kafka、RocketMQ和RabbitMQ都拥有庞大的社区和完善的生态系统,但Kafka和RocketMO目前的发展势头比较迅猛,社区活跃度也相对较高。
7.实现语言方面,kafka是基于scala和java开发的,rocketmg、activemg等都是基于iava语言的,rabbitmg是基于erlang的。
8.功能性,上面列举过一些功能,我们在选型的时候需要看哪个可以满足我们的需求,
需要根据具体情况来选择最适合的消息队列技术。如果有多个因素需要考虑,可以进行性能测试和功能评估来辅助选择。
Kafka 为什么这么快?
kafka是一个成熟的消息队列,一直以性能高著称,它之所以能够实现高吞吐量和低延迟,主要是由于以下几个方面的优化,我试着从发送端,存储端以及消费端分别介绍一下。
消息发送
1.批量发送:Kafka 通过将多个消息打包成一个批次,减少了网络传输和磁盘写入的次数,从而提高了消息的吞吐量和传输效率。
2.异步发送:生产者可以异步发送消息,不必等待每个消息的确认,这大大提高了消息发送的效率。
3.消息压缩:支持对消息进行压缩,减少网络传输的数据量。
4.并行发送:通过将数据分布在不同的分区(Partitions)中,生产者可以并行发送消息,从而提高了吞吐量。
消息存储
1.零拷贝技术:Kafka 使用零拷贝技术来避免了数据的拷贝操作,降低了内存和 CPU 的使用率,提高了系统的性能。
2.磁盘顺序写入:Kafka把消息存储在磁盘上,且以顺序的方式写入数据。顺序写入比随机写入速度快很多,因为它减少了磁头寻道时间。避免了随机读写带来的性能损耗,提高了磁盘的使用效率。
3.页缓存:Kafka 将其数据存储在磁盘中,但在访问数据时,它会先将数据加载到操作系统的页缓存中,并在页缓存中保留一份副本,从而实现快速的数据访问。
4.稀疏索引:Kafka 存储消息是通过分段的日志文件,每个分段都有自己的索引文件。这些索引文件中的条目不是对分段中的每条消息都建立索引,而是每隔一定数量的消息建立一个索引点,这就构成了稀疏索引。稀疏索引减少了索引大小,使得加载到内存中的索引更小,提高了查找特定消息的效率
5.分区和副本:Kafka 采用分区和副本的机制,可以将数据分散到多个节点上进行处理,从而实现了分布式的高可用性和负载均衡。
消息消费
1.消费者群组:通过消费者群组可以实现消息的负载均衡和容错处理
2.并行消费:不同的消费者可以独立地消费不同的分区,实现消费的并行处理。
3.批量拉取:Kafka支持批量拉取消息,可以一次性拉取多个消息进行消费。减少网络消耗,提升性能
Kafka的架构是怎么样的?
典型回答
Kafka 的整体架构比较简单,是显式分布式架构,主要由 Producer(生产者)、broker(Kafka集群)和consumer(消费者)组成
生产者(Producer):生产者负责将消息发布到Kafka集群中的一个或多个主题(Topic),每个Topic包含一个或多个分区(Partition)。
主题:Topic。主题是承载消息的逻辑容器,在实际使用中多用来区分具体的业务。
分区:Partition。一个有序不变的消息序列。每个主题下可以有多个分区。
消费者(Consumer):消费者负责从Kafka集群中的一个或多个主题消费消息,并将消费的偏移量(Offset)提交回Kafka以保证消息的顺序性和一致性。
偏移量:Offset。表示分区中每条消息的位置信息,是一个单调递增且不变的值。
Kafka集群:Kafka集群是由多个Kafka节点(Broker)组成的分布式系统。每个节点都可以存储一个或多个主题(topic)的分区(partition)副本,以提供高可用性和容错能力。
如下图中,包含了 Broker1、Broker2和 Broker3组成了一个集群。用来提升高可用性。
**在集群中,每个分区(partition)都可以有多个副本。这些副本中包含了一个Leader(也可以叫做LeaderPartition 或者 Leader Replication)和多个Follower(也可以叫做Follower Partition 或者 FollowerReplication),****只有Leader 才能处理生产者和消费者的请求,而Follower 只是Leader 的备份,用于提供数据的冗余备份和容错能力。**如果 Leader 发生故障,Kafka 集群会自动将 Follower 提升为新的 Leader,从而实现高可用性和容错能力。
ZooKeeper:ZooKeeper是Kafka集群中使用的分布式协调服务,用于维护Kafka集群的状态和元数据信息,例如主题和分区的分配信息、消费者组和消费者偏移量等。
Kafka如何保证消息不丢失?
典型回答
Kafka作为一个消息中间件,他需要结合消息生产者和消费者一起才能工作,一次消息发送包含以下是三个过程
1)Producer 端发送消息给 Kafka Broker
2)Kafka Broker 将消息进行同步并持久化数据.
3)Consumer端从Kafka Broker 将消息拉取并进行消费,
Kafka只对已提交的消息做最大限度的持久化保证不丢失,但是没办法保证100%。
但是,Kafka还是提供了很多机制来保证消息不丢失的。要想知道Kafka如何保证消息不丢失,需要从生产者、消费者以及kafka集群三个方面来分析。
1、生产者:当我们采用异步发送的时候,可以设置一个回调函数,如果发送失败,会进行重试。并且使用acks机制,比如acks=-1,就必须保证消息写入了所有的同步副本才写入成功,否则就会重试。
2、Broker集群:①具有消息的持久化机制,当消息被写入消息队列后,会被持久化到磁盘。②有同步副本:每个分区都有多个副本,副本可以分布在不同的节点上。当一个节点宕机时,其他节点上的副本仍然可以提供服务,保证消息不丢失。
3、消费者:①消费者记录每个分区消息消费的偏移量,每次都会记录下来,为了保证消息不丢失,建议使用手动提交偏移量的方式,避免拉取了消息以后,业务逻辑没处理完,提交偏移量后但是消费者挂了的问题。②Kafka消费者还可以组成消费者组,每个消费者组可以同时消费多个分区。当一个消费者组中的消费者宕机或者不可用时,其他消费者仍然可以消费该组的分区,保证消息不丢失,
Producer
消息的生产者端,最怕的就是消息发送给Kafka集群的过程中失败,所以,我们需要有机制来确保消息能够发送成功,但是,因为存在网络问题,所以基本没有什么办法可以保证一次消息一定能成功。
所以,就需要有一个确认机制来告诉生产者这个消息是否有发送成功,如果没成功,需要重新发送直到成功。
我们通常使用Kafka发送消息的时候,通常使用的 producer.send(msg)其实是一种异步发送,发送消息的时候,方法会立即返回,但是并不代表消息一定能发送成功。(producer.send(msg).get() 是同步等待返回的。)
那么,为了保证消息不丢失,通常会建议**使用 producer.send(msg,callback)方法,**这个方法支持传入一个callback,我们可以在消息发送时进行重试。
同时,我们也可以通过给producer设置一些参数来提升发送成功率:
Broker
Kafka的集群有一些机制来保证消息的不丢失,比如复制机制、持久化存储机制以及ISR机制。
·持久化存储:Kafka使用持久化存储来存储消息。这意味着消息在写入Kafka时将被写入磁盘,这种方式可以防止消息因为节点宕机而丢失。
·ISR复制机制:Kafka使用ISR机制来确保消息不会丢失,Kafka使用复制机制来保证数据的可靠性。每个分区都有多个副本,副本可以分布在不同的节点上。当一个节点宕机时,其他节点上的副本仍然可以提供服务,保证消息不丢失。
在服务端,也有一些参数配置可以调节来避免消息丢失:
Consumer
作为Kafka的消费者端,只需要确保投递过来的消息能正常消费,并且不会胡乱的提交偏移量就行了。
Kafka消费者会跟踪每个分区的偏移量,消费者每次消费消息时,都会将偏移量向后移动。当消费者宕机或者不可用时,Kafka会将该消费者所消费的分区的偏移量保存下来,下次该消费者重新启动时,可以从上一次的偏移量开始消费消息。
另外,Kafka消费者还可以组成消费者组,每个消费者组可以同时消费多个分区。当一个消费者组中的消费者宕机或者不可用时,其他消费者仍然可以消费该组的分区,保证消息不丢失,
为了保证消息不丢失,建议使用手动提交偏移量的方式,避免拉取了消息以后,业务逻辑没处理完,提交偏移量后但是消费者挂了的问题:
Kafka怎么保证消费只消费一次的?(防止重复消费)
典型回答
Kafka消息只消费一次,这个需要从多方面回答,既包含Kafka自身的机制,也需要考虑客户端自己的重复处理。
可以从以下几个方面回答:
首先,在Kafka中,每个消费者都必须加入至少一个消费者组。同一个消费者组内的消费者可以共享消费者的负载。因此,如果一个消息被消费组中的任何一个消费者消费了,那么其他消费者就不会再收到这个消息了。
另外,消费者可以通过手动提交消费位移来控制消息的消费情况。通过手动提交位移,消费者可以跟踪自己已经消费的消息,确保不会重复消费同一消息。
还有就是客户端自己可以做一些幂等机制,防止消息的重复消费。
另外可以借助Kafka的Exactly-once消费语义,其实就是引入了事务,消费者使用事务来保证消息的消费和位移提交是原子的,而生产者可以使用事务来保证消息的生产和位移提交是原子的。Exactly-once消费语义则解决了重复问题,但需要更复杂的设置和配置。
回答:
1、首先kafka使用消费者组的机制,可以确保如果一个消息被消费组中的任何一个消费者消费了,那么其他消费者就不会再收到这个消息了。
2、使用kafka的消息语义Exactly-once,它是使用了事务来保证消息的消费和位移提交是原子的,不会说消费了消息但是位移提交失败,并且生产者使用事务来保证消息的生产和位移提交是原子的,不会重复发送消息。
3、客户端做一些幂等机制,使得消息即使重复消费了,最后的结果也是一样的。
扩展知识
Kafka的三种消息传递语义
在Kafka中,有三种常见的消息传递语义:At-least-once、At-most-once和Exactly-once。其中At-least-once和Exactly-once是最常用的。
At-least-once消费语义
At-least-once消费语义意味着消费者至少消费一次消息,但可能会重复消费同一消息。在At-least-once语义中,当消费者从Kafka服务器读取消息时,消息的偏移量会被记录下来。一旦消息被成功处理,消费者会将位移提交回Kafka服务器。如果消费消息成功但是提交位移失败,这意味着该消息将在下一次重试时再次被消费。
At-least-once语义通常用于实时数据处理或消费者不能容忍数据丢失的场景,例如金融交易或电信信令。
Exactly-once消费语义
Exactly-once消费语义意味着每个消息仅被消费一次,且不会被重复消费。在Exactly-once语义中,Kafka保证消息只被处理一次,同时保持消息的顺序性。为了实现Exactly-once语义,Kafka引入了一个新的概念:事务。
事务是一系列的读写操作,这些操作要么全部成功,要么全部失败。在Kafka中,生产者和消费者都可以使用事务,以保证消息的Exactly-once语义。具体来说,消费者可以使用事务来保证消息的消费和位移提交是原子的而生产者可以使用事务来保证消息的生产和位移提交是原子的。
在Kafka 0.11版本之前,实现Exactly-once语义需要一些特殊的配置和设置。但是,在Kafka 0.11版本之后Kafka提供了原生的Exactly-once支持,使得实现Exactly-once变得更加简单和可靠。
总之,At-least-once消费语义保证了数据的可靠性,但可能会导致数据重复。而Exactly-once消费语义则解决了重复问题,但需要更复杂的设置和配置。选择哪种消费语义取决于业务需求和数据可靠性要求。