Kafka为啥这么高吞吐

建议先自行学习 Kafka 的基础知识内容。

通常我们讲 Kafka 是一个高可靠、高吞吐的分布式数据流系统。本文只讨论其高吞吐的特性。思考几个问题:

  • Kafka 的哪些设计促成了其高吞吐的特性
  • 对比一般的消息队列(RabbitMQ等),Kafka 怎么做到高吞吐的情况下还能保存大量消息

Partion 模型带来的高吞吐

Topic 下的 Partion 概念,可以横向扩展,部署到多台服务器上。故此不论网络 I/O 还是服务器的本地 I/O 都能扩展,特别是针对消费端需要高 CPU 计算的场景,通过增加 Partion 数量和对应 Consumer Group 中 Consumer 的数量,来提升系统的吞吐量。

生产环节:

image

消费环节:

image

配合下面的机制,Partion 可以说是 Kafka 并行起来的基础。Partion 内部是由 Segment 文件组成的,这点和 Elasticsearch 相似。

Broker 层面

磁盘顺序读写

一般印象中,内存读写肯定比磁盘读写快。事实上磁盘可能比人们预想的更慢、或者更快,取决于怎么使用它。一个良好设计的磁盘结构通常和我们的网络 I/O 一样快。

磁盘的模型图:

image

说起磁盘慢的主要原因在于其寻道操作,在于磁盘的磁头在盘面上的物理位移。我们来看磁盘调度算法里面经典的 SCAN 算法(又称电梯算法)如下图所示:

image

例如,磁盘请求队列中的请求顺序分别为 55、58、39、18、90、160、150、38、184,磁头初始位置是 100 磁道。釆用 SCAN 算法时,不但要知道磁头的当前位置,还要知道磁头的移动方向,假设磁头沿磁道号增大的顺序移动,则磁头的运动过程如上图所示。磁头共移动了( 50+10+24+94+32+3+16+1+20 ) = 250 个磁道,平均寻找长度 = 250/9 = 27.8。那么对于我们最先想要访问的 55 号位置,要等到磁头第六次真实位移后才能访问到。

如此可见顺序读写对磁盘性能的重要性。如果我们只进行顺序读写,则能极大提高读写效率,甚至能高于内存的随机访问。更多的速度对比在文章《ACM Queue article》中,结论如图:

image

故此,Producer 生产消息是不断追加到磁盘文件的,Consumer 消费消息也是从磁盘顺序读取的,都充分利用到了磁盘的顺序读写性能。

利用Page Cache

Kafka 利用到了现代操作系统的特性,Page Cache。Page Cache 是通过将磁盘中的数据缓存到内存中,从而减少磁盘 I/O 操作,从而提高性能。此外,还要确保在 Page Cache 中的数据更改时能够被同步到磁盘上,后者被称为 page 回写(page writeback)。

当上层有写操作时,操作系统只是将数据写入 Page Cache ,同时标记 Page 属性为 Dirty。当读操作发生时,先从 Page Cache 中查找,如果发生缺页才进行磁盘调度,最终返回需要的数据。实际上 Page Cache 是把尽可能多的空闲内存都当做了磁盘缓存来使用。同时如果有其他进程申请内存,回收 Page Cache 的代价又很小,所以现代的 OS 都支持 Page Cache。

相比于应用程序自己(Kafka 是 Java 程序)做 cache, 使用 Page Cache 有如下优势:

  1. 操作系统会自行将连续的小量写操作批量处理为物理写操作,从而提高 IO 吞吐。
  2. 操作系统会尽量将写操作重新排序以减小写磁盘时的磁头偏移量,从而提高 IO 吞吐。
  3. 所有空闲内存都自动构成 Page Cache。
  4. 如果在应用程序 Heap 内管理缓存,JVM 的 GC 线程会频繁扫描 Heap 空间,带来不必要的开销。如果 Heap 过大,执行一次 Full GC 对系统的可用性来说将是极大的挑战。
  5. 所有在 JVM 内的对象都不免带有一个 Object Overhead(千万不可小视),内存的有效空间利用率会因此降低。
  6. 所有的 In-Process Cache 在OS中都有一份同样的 PageCache。所以通过只在PageCache 中做缓存至少可以提高一倍的缓存空间。
  7. 如果 Kafka 重启,所有的 In-Process Cache都会失效,而 OS 管理的 PageCache 依然可以继续使用。

底层 zero-copy 技术带来的高吞吐

首先来看一下传统的通过网络读取文件涉及到的传输过程:

image

涉及到四次内存拷贝过程:

  1. DMA data from disk to read buffer

  2. Copy data from read buffer to application buffer

  3. Copy data from application buffer to socket buffer

  4. DMA buffer from socket buffer to network

注:read buffer 为 page cache,socket buffer 为内核 socket buffer。

并涉及到四次上下文切换:

image

看上去现代操作系统怎么这么蠢?实际上当初设计这一套机制是为了提高性能,利用操作系统内部 kernel buffer:

  • read 操作可以利用readahead cache机制,提前为应用程序准备好数据,当应用程序所需的数据量小于 kernel buffer 时可以显著地提升性能
  • write 操作可以异步执行

但实际上 Kafka 的场景是要实现高吞吐的文件数据传输,这种机制就成为了系统瓶颈。

利用 zero-copy 技术

上诉内存拷贝的步骤 2 和 3 看起来都是浪费,因为应用程序并没有对数据进行过加工。实际上,数据可以直接从 read buffer 传输到 socket buffer。在 Linux 系统里面的系统调用 sendfile() 对此进行了支持。

image

涉及到三次内存拷贝过程:

  1. DMA data from disk to read buffer

  2. Copy data from read buffer to socket buffer

  3. DMA buffer from socket buffer to network

并且使得上线文切换减少到两次:

image

但这还不是 zero-copy,CPU 依然参与了一次内存拷贝。在网卡支持gather operations特性并且 Linux 2.4 之后,可以进一步优化为:

image

涉及到两次内存拷贝过程:

  1. DMA data from disk to read buffer

  2. No data copied to socket buffer, only the descriptors with information about the location and length

  3. DMA buffer from read buffer to network

优势和劣势

为了使用 zero-copy,很明显的一点劣势就是应用程序即 Kafka 的 Broker 不能对数据进行二次加工,数据进来是什么样子出去就是什么样子。与此同时的优势就是,Producer 到 Consumer 可以做端到端的压缩,反正中间的 Broker 不能修改数据本身。实际上这种端到端的压缩也是构成高吞吐的原因之一。

综合一下 PageCahce 和 zero-copy

热数据就直接读 PageCahce,冷数据就走 zero-copy,性能都很好,完美!

Producer 层面

批量化处理

为了避免「small I/O」带来的性能损失,Kafka 提出了message set的概念来批量化处理消息。这个简单的优化带来了巨大的性能提升,因为批量化处理带来了更大的网络报文、更大的顺序磁盘操作、更大的连续内存空间,由此 Kafka 将「突发式的随机消息」转变为顺序的消息流提供给下游的 Consumer。

批量化处理使得 Producer 的发送变成了异步,那么为了保证消息的可靠性,Kafka 提供了 ack 的机制:

  • 0:这意味着 Producer 无需等待来自 Broker 的确认而继续发送下一批消息。这种情况下数据传输效率最高,但是数据可靠性确是最低的。
  • 1(默认):这意味着 Producer 在 ISR 中的 leader 已成功收到的数据并得到确认后发送下一条消息。如果 leader宕机了 ,则会丢失数据。
  • -1(或者是all): Producer 需要等待 ISR 中的所有 follower 都确认接收到数据后才算一次发送完成,可靠性最高。

数据压缩

Kafka 支持数据端到端的压缩,Producer 可以通过 GZIP 或 Snappy 格式对消息集合进行压缩,以减轻网络传输量和磁盘数据量。Producer 压缩之后,在 Consumer 需进行解压,虽然增加了 CPU 的工作,但在对大数据处理上,瓶颈在网络上而不是 CPU ,所以这个成本很值得。

Consumer 层面

pull 模型

到底是用 push 模型还是 pull 模型,不同的系统有不同的选择。Kafka 使用的 pull 模型,这样有助于 Consumer 自行控制消费速度,不会产生消息积压到 Consumer 的情形。

另一个好处是,Consumer 可以根据自身的情况,选择是否批量去 Broker 拉取消息,以增加整体的吞吐。这在 push 模型里就很难办,因为 Broker 很难知道 Consumer 的负载情况从而不知道是否应该批量推送。

针对传统 pull 模型的一个劣势,即如果 Broker 那里没有消息 Consumer 会一直不断尝试获取,Kafka 这里使用了「long polling」长轮询机制。Consumer 在发起一次请求后立即挂起,一直到 Broker 有更新的时候,Broker 才会主动推送信息到 Consumer。 在 Broker 有更新并推送信息过来之前这个周期内,Consumer 不会有新的多余的请求发生,Broker 对此 Consumer 也啥都不用干,只保留最基本的连接信息,一旦 Broker 有更新将推送给 Consumer,Consumer 将相应的做出处理,处理完后再重新发起下一轮请求。

消息确认机制

以往的消息队列为了记录一条消息是否被消费掉,在其 broker 层做了很多工作:

  1. 记录每条消息的状态,是否发送、是否确认等
  2. 和 consumer 确认之间的 ACK 机制
  3. 异常逻辑的处理,比如消息发送了之后一直没有 ACK 确认要怎么处理

相比之下 Kafka 使用了简单的 offset 机制,摒弃了对消息的状态转换。因为每个 Partition 都只有一个 Consumer 在消费,故每个 Consumer 都只需要记录其本身的消费偏移量 offset,简单有效。老版本的 offset 保存在 zookeeper 中,后面改为存放在一个特殊的 Topic 中。

使用 offset 的另一个好处是 Consumer 可以重复去消费,以适配某些场景。

参考

原文载于Kafka为啥这么高吞吐

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容