• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

理解Kafka

武飞扬头像
珞珈山小杨
帮助1

kafka优点

了解kafka的架构、生产者、消费者、topic与partition等基本概念后,无论我们是否对kafka的实现是否了解,都曾经看到过或自行了解过kafka有以下优点:

  1. 高吞吐量、低延迟。即使在非常廉价的机器上,Kafka也能做到每秒处理几十万条消息,而它的延迟最低只有几毫秒
  2. 持久性。Kafka可以将消息直接持久化在普通磁盘上,且磁盘读写性能优异。
  3. 容错性。Kafka会将数据备份到多台服务器节点中,即使Kafka集群中的某一台Kafka服务节点宕机,也不会影响整个系统的功能。
  4. 扩展性。Kafka集群支持热扩展,Kaka集群启动运行后,用户可以直接向集群添加实例。
  5. 解耦。Kafka具备消息系统的优点,只要生产者和消费者数据两端遵循接口约束,就可以自行扩展或修改数据处理的业务过程。
  6. 支持多种客户端语言。Kafka支持Java、.NET、PHP、Python等多种语言。
    本文主要介绍kafka的这些优点是如何实现的,一遍我们更加深入的理解kafka.
    kafka源码github地址:https://github.com/apache/kafka

高吞吐、低延时

相比于rocketMQ十万级的tps,kafka能打到百万级别的tps,其主要因为kafka再各个层面的策略与优化相关,其主要优化有以下几点:

  • 顺序读写
  • PageCache进行读写缓存。
  • ZeroCopy操作系统层面的零拷贝。
  • 分区分段与索引
  • 批量读写
  • 批量压缩

顺序读写

Kafka与RocketMQ一样都是将消息存储在磁盘上的,但是读写速度依然很快,这与其都是用顺序读写有关,实际上不管是内存与磁盘,快或慢的关键在于寻址方式,都存在顺序读写与随机读写两种方式,虽然磁盘随机读写很慢,但是磁盘的顺序读写性能很高。
Kafaka通过顺序读写将消息messaga追加到本地磁盘文件的末尾,使得kafka的吞吐量得到很大提升,kafka的每个parttion其实都是一个文件,收到消息时会把数据追加到文件的末尾,同时由于顺序读写的原因,kafka时不会删除数据的(高版本已支持,低版本主要处于删除成本考虑),会把所有数据保留下来,而每个消费者consumer会对每一个topic维护一个偏移量的offset用来表示读取到的位置。
kafka虽然不删除数据,但提提供了两种策略来清理数据,分别是基于时间与partition文件大小的策略,可自行查略资料了解。

学新通

PageCache

PageCache是针对文件系统中文件的缓存,不了解的同学可先了解其原理。Kafka正是利用了PageCache提高了数据读写的性能,相比于使用JVM的空间内存,有以下好处:

  • 避免Object消耗:如果是jvm内存,需要创建对象,java对象除了数据外,还需要存储一些对象信息,内存消耗比较大,通常是所存数据的两倍以上。
  • 避免垃圾回收GC问题,熟悉jvm的同学应该知道,随着jvm中对象数据不断增加,垃圾回收可能会变得比较慢,且比较复杂,而使用系统缓存就不存在GC问题。
    除此之外,相比于JVM缓存或in-memory cache其次,操作系统本身也对于Page Cache做了大量优化,提供了 write-behind、read-ahead以及flush等多种机制。再者,即使服务进程重启,系统缓存依然不会消失,避免了in-process cache重建缓存的过程。通过操作系统的Page Cache,Kafka的读写操作基本上是基于内存的,读写速度得到了极大的提升。

零拷贝ZeroCopy

Kafka的消费端性能与ZeroCopy密切相关,系统性能低下的主要原因出去I/O外主要又两个:大量的小型 I/O 操作,以及过多的字节拷贝。其中字节拷贝,在消息量少时,这不是什么问题。但是在高负载的情况下,影响就不容忽视。为了避免这种情况,我们使用 producer ,broker 和 consumer 都共享的标准化的二进制消息格式,这样数据块不用修改就能在他们之间传递。

broker 维护的消息日志本身就是一个文件目录,每个文件都由一系列以相同格式写入到磁盘的消息集合组成,这种写入格式被 producer 和 consumer 共用。保持这种通用格式可以对一些很重要的操作进行优化: 持久化日志块的网络传输。 现代的unix 操作系统提供了一个高度优化的编码方式,用于将数据从 pagecache 转移到 socket 网络连接中;在 Linux 中系统调用 sendfile 做到这一点。

为了理解 sendfile 的意义,了解数据从文件到套接字的常见数据传输路径就非常重要:

  1. 操作系统从磁盘读取数据到内核空间的 pagecache
  2. 应用程序读取内核空间的数据到用户空间的缓冲区
  3. 应用程序将数据(用户空间的缓冲区)写回内核空间到套接字缓冲区(内核空间)
  4. 操作系统将数据从套接字缓冲区(内核空间)复制到通过网络发送的 NIC 缓冲区

这显然是低效的,有四次 copy 操作和两次系统调用。使用 sendfile 方法,可以允许操作系统将数据从 pagecache 直接发送到网络,这样避免重新复制数据。所以这种优化方式,只需要最后一步的copy操作,将数据复制到 NIC 缓冲区。

我们期望一个普遍的应用场景,一个 topic 被多消费者消费。使用上面提交的 zero-copy(零拷贝)优化,数据在使用时只会被复制到 pagecache 中一次,节省了每次拷贝到用户空间内存中,再从用户空间进行读取的消耗。这使得消息能够以接近网络连接速度的 上限进行消费。

pagecache 和 sendfile 的组合使用意味着,在一个kafka集群中,大多数 consumer 消费时,您将看不到磁盘上的读取活动,因为数据将完全由缓存提供。

学新通

分区分段与索引

Kafka的消息message按topic分类存储,每个topic中的数据又按一个一个parttion分区存储到不同的broker的节点中,每个partition与操作系统上一个文件家对应,partition实际上又是按segment分段存储的,符合分布式系统分区分桶的设计思想,kafka实际时存储在一个又一个segment中,每次文件操作也是直接操作的segment。为了进一步的查询优化,Kafka又默认为分段后的数据文件建立了索引文件,就是文件系统上的.index文件。这种分区分段 索引的设计,不仅提升了数据读取的效率,同时也提高了数据操作的并行度。

批量读写

系统性能低下的另一个原因事大量的小型 I/O 操作,为了避免这种情况,Kafka建立在一个 “消息块” 的抽象基础上,合理将消息分组。 这使得网络请求将多个消息打包成一组,而不是每次发送一条消息,从而使整组消息分担网络中往返的开销。Consumer 每次获取多个大型有序的消息块,并由服务端 依次将消息块一次加载到它的日志中。

即kafka在写入或读写消息时支持批量,可以通过批量传递多条消息减少网络上频繁传递单条小消息造成的延迟和带宽,这样极大的提高了发送消息的吞吐量,同时其支持设置超时时间,使得在消息量较小的场景,超过超时时间没有达到批量大小时也发送消息,避免消息一直不发送。

这个简单的优化对速度有着数量级的提升。批处理允许更大的网络数据包,更大的顺序读写磁盘操作,连续的内存块等等,所有这些都使 KafKa 将随机流消息顺序写入到磁盘, 再由 consumers 进行消费。

批量压缩

在很多情况下,系统的瓶颈不是CPU或磁盘,而是网络IO,对于需要在广域网上的数据中心之间发送消息的数据流水线尤其如此。
-如果每个消息都压缩,但是压缩率相对很低,所以Kafka使用了批量压缩,即将多个消息一起压缩而不是单个消息压缩
-Kafka允许使用递归的消息集合,批量的消息可以通过压缩的形式传输并且在日志中也可以保持压缩格式,直到被消费者解压缩
-Kafka支持多种压缩协议,包括Gzip和Snappy压缩协议
  Kafka速度的秘诀在于,它把所有的消息都变成一个批量的文件,并且进行合理的批量压缩,减少网络IO损耗,通过mmap提高I/O速度,写入数据的时候由于单个Partion是末尾添加所以速度最优;读取数据的时候配合sendfile直接暴力输出。

持久性

kafka的数据存储在磁盘上,同时具有极高的性能,人们对于“磁盘速度慢”的普遍印象,使得人们对于持久化的架构能够提供强有力的性能产生怀疑。事实上,磁盘的速度比人们预期的要慢的多,也快得多,这取决于人们使用磁盘的方式。而且设计合理的磁盘结构通常可以和网络一样快。
Kafka的持久化与其性能也有关,由于使用顺序读写的思想,持久化队列可以建立在简单的读取和向文件后追加两种操作之上,这和日志解决方案相同。这种架构的优点在于所有的操作复杂度都是O(1),而且读操作不会阻塞写操作,读操作之间也不会互相影响。这有着明显的性能优势,由于性能和数据大小完全分离开来——服务器现在可以充分利用大量廉价、低转速的1 TB SATA硬盘。 虽然这些硬盘的寻址性能很差,但他们在大规模读写方面的性能是可以接受的,而且价格是原来的三分之一、容量是原来的三倍。

在不产生任何性能损失的情况下能够访问几乎无限的硬盘空间,这意味着我们可以提供一些其它消息系统不常见的特性。例如:在 Kafka 中,我们可以让消息保留相对较长的一段时间(比如一周),而不是试图在被消费后立即删除。正如我们后面将要提到的,这给消费者带来了很大的灵活性。

容错性

即使Kafka集群中的某一台Kafka服务节点宕机,也不会影响整个系统的功能。其容错性主要由Kafka的数据备份保证,Kafka的消息数据对应的partition分布在Kafka集群的服务器上,每个服务器在处理数据和请求时,共享这些partition,每一个partition都会在已配置的服务器上进行备份(当然, 在任何给定时间, leader 节点的日志末尾时可能有几个消息尚未被备份),保证容错性。

每个partition都有一台服务器作为主结单leader,0或多个节点作为followers,主节点leader负责处理一切对parttion的读写请求,而其他follower只需负责同步leader的数据,当leader宕机时,follower会自动推举一台服务器成为leader保证数据可用。每台 server 都会成为某些分区的 leader 和某些分区follower,因此集群的负载是平衡的。

请注意,Kafka 对于数据不会丢失的保证,是基于至少一个节点在保持同步状态,一旦分区上的所有备份节点都挂了,就无法保证了。

但是,实际在运行的系统需要去考虑假设一旦所有的备份都挂了,怎么去保证数据不会丢失,这里有两种实现的方法

  1. 等待一个 ISR 的副本重新恢复正常服务,并选择这个副本作为领 leader (它有极大可能拥有全部数据)。
  2. 选择第一个重新恢复正常服务的副本(不一定是 ISR 中的)作为leader。

这是可用性和一致性之间的简单妥协,如果我只等待 ISR 的备份节点,那么只要 ISR 备份节点都挂了,我们的服务将一直会不可用,如果它们的数据损坏了或者丢失了,那就会是长久的宕机。另一方面,如果不是 ISR 中的节点恢复服务并且我们允许它成为 leader , 那么它的数据就是可信的来源,即使它不能保证记录了每一个已经提交的消息。 kafka 默认选择第二种策略,当所有的 ISR 副本都挂掉时,会选择一个可能不同步的备份作为 leader ,可以配置属性 unclean.leader.election.enable 禁用此策略,那么就会使用第 一种策略即停机时间优于不同步。

这种困境不只有 Kafka 遇到,它存在于任何 quorum-based 规则中。例如,在大多数投票算法当中,如果大多数服务器永久性的挂了,那么您要么选择丢失100%的数据,要么违背数据的一致性选择一个存活的服务器作为数据可信的来源。

扩展性

Kafka消息系统支持集群规模的热扩展,通过上节可了解到,kafka消息传递系统轻松缩放,无需停机,添加一个节点时,可作为多个partition的follower节点轻松加入。

解耦

Kafka具备消息系统的优点,只要生产者和消费者数据两端遵循接口约束,就可以自行扩展或修改数据处理的业务过程,KafKa将数据生成与数据处理解耦,生产者只需产生消息发送到kafka,消费只需从kafka读取消息,多个生产者和消费者之间的数据交互都解耦为与Kafka的数据交互,降低了系统的复杂度,简单来说比如有N个应应用于另外M个影响之间两辆都存在数据交互,系统高度耦合,复杂度为N * M,在使用Kafka消息队列后,系统复杂度为N M,在多对多的复杂系统表现优异。

支持多种客户端语言

在Kafka中,客户端和服务器使用一个简单、高性能、支持多语言的 TCP 协议.此协议版本化并且向下兼容老版本, 我们为Kafka提供了Java客户端,也支持许多其他客户端语言。

相关参考资料

Kafka中文文档

Linux系统中的Page cache和Buffer cache

零拷贝了解

大数据框架(分区,分桶,分片)

顺序、随机IO和Java读写文件性能

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhghfgjj
系列文章
更多 icon
同类精品
更多 icon
继续加载