它可以用于两大类别的应用:
构造实时流数据管道,它可以在系统或应用之间可靠地获取数据。 (相当于message queue)构建实时流式应用程序,对这些流数据进行转换或者影响。 (就是流处理,通过kafka stream topic和topic之间内部进行变化
Kafka有四个核心的API:
The Producer API 允许一个应用程序发布一串流式的数据到一个或者多个Kafka topic。
The Consumer API 允许一个应用程序订阅一个或多个 topic ,并且对发布给他们的流式数据进行处理。
The Streams API 允许一个应用程序作为一个 流处理器 ,消费一个或者多个topic产生的输入流,然后生产一个输出流到一个或多个topic中去,在输入输出流中进行有效的转换。
The Connector API 允许构建并运行可重用的生产者或者消费者,将Kafka topics连接到已存在的应用程序或者数据系统。比如,连接到一个关系型数据库,捕捉表(table)的所有变更内容。
在Kafka中,客户端和服务器使用一个简单、高性能、支持多语言的 TCP 协议.此协议版本化并且向下兼容老版本, 我们为Kafka提供了Java客户端,也支持许多其他语言的客户端。
———————————————————————————————
以上摘自Apache Kafka官网
而本文关注的焦点是:构造实时流数据管道,即message queue部分。也就是我们常使用的“消息队列”部分,这部分本身也是Kafka最初及最基本的底层设计。
让我们回到最初Kafka还没有设计出来的时候,通过重新设计Kafka,一步步了解为什么Kafka是我们现在看到的样子,到时我们将了解到Kafka作为消息队列会高吞吐量、分布式、高容错稳定。我们把这个项目命名为: Kafka-R 。
现在我们开始设计 Kafka-R ,我们正式设计 Kafka-R 之前需要考虑设计目标,也就是我的 Kafka-R 设计出来到底是用来干嘛的,适用于什么业务场景,解决什么需求痛点。
可以很快想到:数据交换。这是消息队列的基本功能与要求。
然后呢?可以作为个大平台,支持多语言,最好能满足大公司的业务需求,而且最好是实时的,至少是低延迟。
概括起来就是:我们设计 Kafka-R 的目标是可以作为一个统一的平台来处理大公司可能拥有的所有实时数据馈送。
为了满足我们的 Kafka-R 的设计目标,那么 Kafka-R 需要具备以下这些特征:具有高吞吐量来支持高容量事件流。能够正常处理大量的数据积压,以便支持来自离线系统的周期性数据加载。系统必须处理低延迟分发,来处理更传统的消息传递用例。数据馈送分区与分布式,以及实时。系统在出现机器故障时能够保证容错。
一、数据的存储方式——in-memory&in-disk
有两种选择:第一种,使用in-memory cache,并在空间不足的的时候将数据flush到文件系统中。
另外一种,使用in-disk,一开始把所有的数据写入文件系统的持久化日志中。
我们的 Kafka-R 采用in-disk。实际上在此情况数据被转移到了内核的pagecache中。
“磁盘速度慢”是人们的普遍印象,那么 Kafka-R 的数据存储和缓存基于文件系统,这样的性能能够接受吗?
而事实是,磁盘的速度比人们预期的要慢得多,也快得多,取决于人们使用磁盘的方式。
我们知道磁盘有顺序读和随机读两种模式,之间的性能差异很大,但具体差距多少呢?
使用6个7200rpm、SATA接口、RAID-5的磁盘阵列在JBOD配置下的顺序写入的性能约为600MB/秒,但随机写入的性能仅约为100k/秒,相差6000倍。
线性的读取和写入是磁盘使用模式中最有规律的,并且操作系统进行了大量的优化。现代操作系统提供了read-ahead和write-behind技术,read-ahead是以大的data block为单位预先读取数据,而write-hehind将多个小型的逻辑写合并成一次大型的物理磁盘写入。
磁盘除了访问模式,还有两个低效率操作影响系统的性能:大量的小型I/O操作,过多的字节拷贝。
那么我们怎么处理这些问题呢?
针对于大量的小型I/O操作, Kafka-R 使用“消息块”将消息合理分组。使网络请求将多个消息打包成一组,而不是每次发送一条消息,从而使整组消息分担网络往返的开销。
另一个过多的字节拷贝, Kafka-R 使用producer,broker和consumer都共享的标准化通用的二进制消息格式,这样数据块不用修改就能在他们之间传递。
保持这种通用的格式有什么用呢?
可以对持久化日志块的网络传输进行优化。现代的unix操作系统提供了一个高度优化的编码方式,用于将数据从pagecache转移到socket网络连接中。
数据从文件到套接字的常见数据传输过程:磁盘->pagecache->用户空间缓存区->套接字缓冲区(内核空间)->NIC缓存区
-
操作系统从磁盘读区数据到内核空间的pagecache
-
应用程序读取内核空间的数据到用户空间的缓存区
-
应用程序将数据(用户空间的缓存区)写会内核空间到套接字缓冲区(内核空间)
-
操作系统将数据从套接字缓冲区(内核空间)复制到能够通过网络发送的NIC缓冲区
共进行了4次copy操作和2次系统调用,显然很低效。在Linux系统中使用zero-copy(零拷贝)优化,其中之一 sendfile ,使用后的数据传输过程是这样:磁盘->pagecache->NIC缓存区。
我们的Kafka-R通过使用zero-copy优化技术,可以用尽可能低的消费代价让多个consumer消费。数据在使用时只会被复制到pagecache中一次,这样消息能够以接近网络连接的速度上限进行消费。
二、数据结构——BTree&日志解决方案
日志解决方案即简单读取与追加来操作文件。
我们的 Kafka-R 采用日志解决方案。
我们知道BTree是通用的数据结构,其广泛用于随机的数据访问。BTree的操作时间复杂度是O(log N),基本等同于常数时间,但在磁盘上则不成立。
每个磁盘同时只能执行一次寻址,并行性受到限制。少量的磁盘寻址也有很高的开销。数据翻倍时性能下降不止两倍。
而日志解决方案的数据存储架构,所有的操作时间复杂度都是O(1),并且读不会阻塞写,读之间也不会相互影响。
由于性能和数据的大小是完全分离的,则服务器可以使用大量廉价、低转速的1+TB SATA硬盘,即使这些硬盘的寻址性能很差,在大规模读写的性能也可以接受,而且三分之一的价格三倍的容量。
三、获取数据方式——push-based&pull-based
由consumer从broker那里pull数据呢?还是从broker将数据push到consumer?
我们的 Kafka-R 采用pull-based方式。
这是大多数消息系统所共享的传统的方式:即producer把数据push到broker,然后consumer从broker中pull数据。
push-based系统优点:
- 让consumer能够以最大速率消费。
push-based系统缺点:
-
由于broker控制着数据传输速率,所以很难处理不同的consumer。
-
当消费速率低于生产速率时,consumer往往会不堪重负(本质类似于拒绝服务攻击)。
-
必须选择立即发送请求或者积累更多的数据,然后在不知道下游的consumer能否立即处理它的情况下发送这些数据。特别系统为低延迟状态下,这样会极度糟糕浪费。
pull-based系统优点:
- 可以大批量生产要发送给consumer的数据。
pull-based系统缺点:
- 如果broker中没有数据,consumer可能会在一个紧密的循环中结束轮询,实际上会busy-waiting直到数据到来。
最后
看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面
小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>
针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺
全都是一丢一丢的收集整理纯手打出来的
更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~
[外链图片转存中…(img-3Kx5cFRQ-1714737177229)]
全都是一丢一丢的收集整理纯手打出来的
更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~
[外链图片转存中…(img-wXRgKE7h-1714737177229)]
[外链图片转存中…(img-0rhqDrDN-1714737177229)]