浅出消息队列Kafka

·2591·6 分钟·
AI摘要: 本文介绍了消息队列Kafka的工作原理、使用和重要性。Kafka是互联网企业常用的中间件,用于实现业务解耦和处理性能。文章解释了其关键概念如Topic、Partition和Broker,并讨论了高可用性和可靠性的实现方式。同时,还提到了如何通过分拆策略提高系统性能,以及Kafka特有的高性能和扩展性优化措施,如零拷贝技术。

消息队列是当今广泛应用的中间件,几乎成为每场面试的必问内容。互联网企业常用消息队列来实现"削峰填谷"和复杂业务间的解耦。作为最著名的消息队列之一,Kafka拥有出色的处理性能。因此,我们需要深入理解其工作原理和使用方法。

名词扫盲

  • Topic:消息队列中的分组容器,具有相同Topic的消息将会集中存储在一起。Topic可以类比成图书馆的书籍分类(科幻主题、小说主题、历史主题)

  • Partition:每个Topic可以被分为多个Partition、Partition可以跨多个服务器存储,从而提高吞吐量和容错能力。Partition可以类比成图书馆的书架、某个Topic主题(科幻主题)下面有很多书(类比成消息),因为一个书架无法容纳这个Topic下面的所有书籍,所以需要多个互相独立的书架来存储,书架内部存放书籍也是井然有序的。多个Partition也保证了可靠性,即使其中一个Partition挂掉了,也有其他Partition继续工作。

  • Broker:消息队列集群中的一个节点,负责接受来自生产者的消息和处理来自消费者的请求。Broker可以类比成图书馆的不同楼栋,每个楼栋相互独立,各自有一套管理系统和管理员。

高可用性

任何大型系统为了确保高可用性,通常都会实施备份策略,以此来规避因单点故障导致的系统中断风险。Kafka通过实现数据冗余的方式增强了其可靠性——它会将分区(Partition)的多个副本分散存储在不同的Broker上,并保持这些副本的实时同步。这样一来,如果主Broker出现故障,系统可以迅速切换至备用Broker,从而保证服务的高可用性。

数据备份会遇到大量消息的快速复制问题,也就是计算机中常见的IO瓶颈,在其他应用如MySQL和Redis中均有类似的解决机制、比如MySQL中的binlog和Redis的AOF日志,主要是为了提供数据备份能力

高可靠性

消息队列需要保证消息不会在传输过程中丢失,主要在三个阶段:生产者将消息发送给Kafka不能丢失、消息堆积在Kafka中不能丢失、消息发送给消费者不能丢失。

  1. Producer发送阶段

    生产者向Kafka发送消息,Kafka在成功接受之后,会返回一个ACK,所以生产者只要收到了ACK就说明消息发送成功

  2. Broker存储阶段

    Broker会定期将一组消息异步地刷入磁盘中持久化

  3. consumer消费阶段

    消费者从Broker消费消息,一旦消费成功就会发送状态给Broker。但是由于网络问题,可能出现不可避免的重复消费问题,因此消费者需要实现消费幂等性。

Kafka是典型的一个IO密集型应用,大量技术细节都在解决IO性能瓶颈。与之类似的应用如mysql、redis都采用了类似的解决方案。MySQL中的binlog实现异步刷盘、redis中的AOF日志,甚至内核中的零拷贝

高性能

为了实现消息的高效快速收发,Kafka基于Topic对消息进行分类,从而分布在不同的队列中,降低了单个队列的处理压力。单个Topic的消息队列处理能力依然有限,那么可以将消息分拆到不同的Partition中,不同的消费者分别在不同的Partition中去消费消息,又大大减少了处理压力 。

上述的高性能方案都基于"分拆"的思想。由于单点处理能力有限,将单点内容分拆到不同的小部分可以降低压力。这体现在两个层面:从单个队列拆分成不同Topic的队列,以及从单个Topic队列拆分出不同的Partition分区。从类比的角度来看,这与前文提到的图书馆比喻是一脉相承的。

分拆策略在所有消息队列(如RocketMQ、Kafka)中都是常见的("人有我有")。然而,Kafka相比RocketMQ还拥有其他独特的性能优化措施("人无我有"),能够实现高达17w/s的数据处理速度。零拷贝就是其中一个重要的性能优化措施。

消息的发送过程中,一般发生四个步骤:

  1. (read调用)磁盘数据读到内核的缓冲区

  2. (read返回)内核的缓冲区的数据拷贝到用户空间

  3. (write调用)用户空间的数据拷贝到socket缓冲区

  4. (write返回)socket发送缓冲区发送到网卡

这里一共发生了4次用户空间和内核空间的切换和4次数据拷贝,可以发现,同样一份数据来回拷贝的效率很低,所以操作系统内核提供了两种优化方案:mmap、sendfile

  • mmap:将内核空间映射到用户空间,这样就不会发生内核空间向用户空间的数据拷贝。通过mmap优化,整个过程只发生2次系统调用(mmap、write),4次用户空间和内核空间的切换,3次数据拷贝。mmap的”零拷贝”是指避免了内核空间向用户空间的一次拷贝。

  • sendfile:同样是内核提供的一个优化方案,可以直接将磁盘的数据拷贝到内核缓冲区,然后从内核缓冲区拷贝到网卡,整个过程只发生了1次系统调用(sendfile)、2次用户空间和内核的切换(sendfile调用和返回),2次数据拷贝(磁盘→内核缓冲区→网卡)。sendfile的”零拷贝”是指零CPU拷贝,两次数据拷贝都由DMA搬运,CPU不干涉

回到消息队列中,RocketMQ使用了mmap技术,而Kafka使用了sendfile技术,因此性能更好。

虽然mmap的性能稍差,但是相比于sendfile这种CPU完全没有参与技术,mmap能够知道网卡发送的消息的具体内容,这为RocketMQ的某些功能提供了基础,因此RocketMQ的功能更加强大。

高扩展性

扩展性为系统提供了应对不同流量的伸缩能力,流量高峰可通过临时增加机器来缓解。Kafka也具备这种弹性伸缩能力,它可以将Partition分散到新加入的Broker中,从而降低单台机器的处理负载。

Kaggle学习赛初探