在分布式消息中,消息队列中应用最广泛的是 Kafka 和 RocketMQ,故今天我们就一起来看一下,Kafka 是如何实现高性能的。

Kafka 的高性能

不知道你有没有了解过自己电脑的配置?

我们一般会认为高性能是和高配置联系在一起的,比如大内存比小内存快,8 核的机器比 4 核的机器快。我身边也有一些朋友是攒机爱好者,对各种硬件配置如数家珍。

对于服务器来说,家用电脑的性能与配置的关系也同样适用——价格更昂贵的服务器会有更好的性能——这并不是一件需要大张旗鼓去讲述的事情。但 Kafka 所实现的高性能不需要太高配置的机器,它使用普通服务器就能实现 TB 级别的传输性能。这一点也是 Kafka 对外宣传的一个特性,也正是因为这一点,Kafka 被广泛运用于大数据处理、流式计算、各类日志监控等需要处理海量数据的场景。

Kafka 实现高性能的手段,是面试中经常被问到的问题。下面我从 Kafka 的磁盘读写、批量优化、零拷贝等方面,对 Kafka 的高性能特性进行分析。

分析 Kafka 的高性能会涉及操作系统的一些知识,比如文件系统、PageCache等,作为大学计算机专业的必修课,这些概念就不展开了。如果你觉得这方面比较生疏,可以回顾下操作系统课程的相关知识,找一些经典教材来学习。

磁盘顺序读写

Kafka 消息是存储在磁盘上的,大家都知道,普通的机械磁盘读取是比较慢的,那 Kafka 文件在磁盘上,如何实现高性能的读写呢?

Kafka 对磁盘的应用,得益于消息队列的存储特性。与普通的关系型数据库、各类 NoSQL 数据库等不同,消息队列对外提供的主要方法是生产和消费,不涉及数据的 CRUD。所以在写入磁盘时,可以使用顺序追加的方式来避免低效的磁盘寻址。

我们知道,数据存储在硬盘上,而硬盘有机械硬盘和固态硬盘之分。机械硬盘成本低、容量大,但每次读写都会寻址,再写入数据(在机械硬盘上,寻址是一个物理动作,耗时最大);SSD 固态硬盘性能很高,有着非常低的寻道时间和存取时间,但成本也特别高。

为了提高在机械硬盘上读写的速度,Kafka 使用了顺序读写。在一个分区内,Kafka 采用 append 的方式进行顺序写入,这样即使是普通的机械磁盘,也可以有很高的性能。

除了顺序读写,在提到磁盘写入的时候,还有一个问题避免不了,那就是何时进行刷盘。

在 Linux 系统中,当我们把数据写入文件系统之后,其实数据是存放在操作系统的 page cache 里面,并没有刷到磁盘上,如果服务器宕机,数据就丢失了。

写到磁盘的过程叫作 Flush。刷盘一般有两种方式,一种是依靠操作系统进行管理,定时刷盘,另一种则是同步刷盘,比如调用 fsync 等系统函数。

同步刷盘保证了数据的可靠性,但是会降低整体性能。Kafka 可以配置异步刷盘,不开启同步刷盘,异步刷盘不需要等写入磁盘后返回消息投递的 ACK,所以它提高了消息发送的吞吐量,降低了请求的延时,这也是 Kafka 磁盘高性能的一个原因。

批量操作优化

批量是一个常见的优化思路,比如大家熟悉的 Redis,就实现了 pipeline 管道批量操作。Kafka 在很多地方也应用了批量操作进行性能优化。

Kafka 的批量包括批量写入、批量发布等。它在消息投递时会将消息缓存起来,然后批量发送;同样,消费端在消费消息时,也不是一条一条处理的,而是批量进行拉取,提高了消息的处理速度。

除了批量以外,Kafka 的数据传输还可以配置压缩协议,比如 Gzip 和 Snappy 压缩协议。虽然在进行数据压缩时会消耗少量的 CPU 资源,但可以减少网络传输的数据大小、优化网络 IO、提升传输速率。

Sendfile 零拷贝

零拷贝是什么?它是操作系统文件读写的一种技术。

零拷贝不是不需要拷贝,而是减少不必要的拷贝次数,这里会涉及 Linux 用户态和内核态的区别。

用户进程是运行在用户空间的,不能直接操作内核缓冲区的数据。所以在用户进程进行系统调用的时候,会由用户态切换到内核态,待内核处理完之后再返回用户态。

传统的 IO 流程,需要先把数据拷贝到内核缓冲区,再从内核缓冲拷贝到用户空间,应用程序处理完成以后,再拷贝回内核缓冲区。这个过程中发生了多次数据拷贝。

为了减少不必要的拷贝,Kafka 依赖 Linux 内核提供的 Sendfile 系统调用。 在 Sendfile 方法中,数据在内核缓冲区完成输入和输出,不需要拷贝到用户空间处理,这也就避免了重复的数据拷贝。在具体的操作中,Kafka 把所有的消息都存放在单独的文件里,在消息投递时直接通过 Sendfile 方法发送文件,减少了上下文切换,因此大大提高了性能。

MMAP 技术

Kafka 是使用 Scala 语言开发的。Scala 运行在 Java 虚拟机上,也就是说 Kafka 节点运行需要 JVM 的支持,但是 Kafka 并不直接依赖 JVM 堆内存。如果 Kafka 所有的数据操作都在堆内存中进行,则会对堆内存造成非常大的压力,影响垃圾回收处理,增加 JVM 的停顿时间和整体延迟。

因此,除了 Sendfile 之外,还有一种零拷贝的实现技术,即 Memory Mapped Files。

Kafka 使用 Memory Mapped Files 完成内存映射,Memory Mapped Files 对文件的操作不是 write/read,而是直接对内存地址的操作。如果是调用文件的 read 操作,则把数据先读取到内核空间中,然后再复制到用户空间。 但 MMAP 可以将文件直接映射到用户态的内存空间,省去了用户空间到内核空间复制的开销,所以说 MMAP 也是一种零拷贝技术。

那 MMAP 和上面的 Sendfile 有什么区别呢?

MMAP 和 Sendfile 并没有本质上的区别,它们都是零拷贝的实现。零拷贝是一种技术思想,除了我们说到的这两种,还有DMA,以及缓冲区共享等方式,感兴趣的同学可以去扩展了解一下。

总结

这一课时讲解了 Kafka 如何实现高性能,介绍了顺序读写、批量优化、零拷贝等技术,对于大部分业务开发的同学,这部分知识了解即可。

Kafka 的高性能实现原理,在很多地方都有应用,比如 Netty 中也有零拷贝技术。Linux 中,一切皆文件,Netty 关注的是网络 IO 的传输,Kafka 等存储关注的是文件 IO 的传输,但在操作系统中都是 IO 操作,在优化手段上非常类似。

另外,上面提到的 Sendfile 可以大幅提升文件传输性能,在 Apache、Nginx 等 Web 服务器当中,都有相关的应用。感兴趣的同学可以了解下 Netty 等网络组件的性能优化方式,欢迎留言进行分享。

参考:《拉勾教育-分布式技术原理与实战45讲》

Kafka是如何实现高性能的?相关推荐

  1. kafka的c/c++高性能客户端librdkafka简介/使用librdkafka的C++接口实现简单的生产者和消费者

    Librdkafka是c语言实现的apachekafka的高性能客户端,为生产和使用kafka提供高效可靠的客户端,并且提供了c++接口 性能: Librdkafka 是一款专为现代硬件使用而设计的高 ...

  2. kafka的c/c++高性能客户端librdkafka简介

    Librdkafka是c语言实现的apachekafka的高性能客户端,为生产和使用kafka提供高效可靠的客户端,并且提供了c++接口 性能: Librdkafka 是一款专为现代硬件使用而设计的高 ...

  3. kafka是存储到本地磁盘么_【漫画】Kafka是如何实现高性能的?

    宏观架构层面利用Partition实现并行处理 Kafka中每个Topic都包含一个或多个Partition,不同Partition可位于不同节点. 同时Partition在物理上对应一个本地文件夹, ...

  4. weblogic jms消息 删除_利用 Kafka 设置可靠的高性能分布式消息传递基础架构

    世界已经迈进"移动"时代,现在应用程序必须能够实时提供数据,这不仅包括数据库表中存储的重要最终结果,还包括用户使用应用程序时执行的所有操作.任何可用信息,例如,用户点击量.日志数据 ...

  5. Android 开发必备知识点及面试题汇总(Android+Java,Kafka是如何实现高性能的

    执行相应地任务,因为线程池的大小问题,所以 AsyncTask 只应该用来执行耗时时间较短的任务, 比如 HTTP 请求,大规模的下载和数据库的更改不适用于 AsyncTask,因为会导致线程池堵塞, ...

  6. 深入理解分布式技术 - Kafka 高性能原理剖析

    文章目录 概述 磁盘顺序读写 批量操作优化 Sendfile 零拷贝 MMAP 技术 小结 概述 Kafka 所实现的高性能不需要太高配置的机器,它使用普通服务器就能实现 TB 级别的传输性能.这一点 ...

  7. 闫燕飞:Kafka的高性能揭秘及优化

    大家下午好,我是来自腾讯云基础架构部ckafka团队的高级工程师闫燕飞.今天在这里首先为大家先分享一下开源Kafka在高性能上面的一些关键点,然后我会分享一下我们腾讯云ckafka对社区Kafka所做 ...

  8. Redis、Kafka 和 Pulsar 消息队列对比

    点击关注公众号,Java干货及时送达 导语 | 市面上有非常多的消息中间件,rabbitMQ.kafka.rocketMQ.pulsar. redis等等,多得令人眼花缭乱.它们到底有什么异同,你应该 ...

  9. 2 万字长文深入详解 Kafka,从源码到架构全部讲透

    -     消息队列的核心价值    -  解耦合. 异步处理 例如电商平台,秒杀活动.一般流程会分为:1: 风险控制.2:库存锁定.3:生成订单.4:短信通知.5:更新数据. 通过消息系统将秒杀活动 ...

最新文章

  1. 线性支持向量机、线性可分支持向量机、非线性支持向量机是怎么区分的?
  2. 知道这20个正则表达式,能让你少写1,000行代码
  3. 用命令行在控制台里玩斗地主,试过没?
  4. JUC并发编程一 并发架构
  5. 如何查看长文本的标识和对象(读长文本)。
  6. create new page group - ST05
  7. C++判断是否为素数、求一个数的因数、质因数分解
  8. 微信小程序 - 用户进入客服会话会在右下角显示可能要发送的小程序提示
  9. UIViewAnimationOptions
  10. vb升级工作笔记001---VB.NET升级到VB.NET 随时更新
  11. webstorm+node之debug
  12. linux端更新pip
  13. mysql 添加 删除索引(index) alter table 修改字段 修改列
  14. 博士论文-基于生成对抗网络的图像合成-阅读笔记
  15. 完美平台反复正在连接至服务器,完美世界无法连接服务器是什么原因
  16. 开源工业缺陷数据集汇总,持续更新中(已更新28个)
  17. 管理经济学学习之初探
  18. SQL Server 2016详细安装步骤,后附链接
  19. 人脸识别系统——Dlib人脸检测
  20. 微信小程序之----视频上传

热门文章

  1. 大三保研夏令营须知及前期准备工作
  2. Flash应用安全规范
  3. 短信阅读率接近100%?短信营销用“短链接”提升推广效果
  4. EMP平台简介(转载)
  5. Compact set,紧集,闭集,开集
  6. 嵌入式系统的软件看门狗和硬件看门狗
  7. scala安装及环境配置
  8. 神雕2暂无服务器信息,神雕侠侣2手游4月2日停服维护公告_神雕侠侣2手游4月2日更新了什么_玩游戏网...
  9. HTML基础笔记笔记
  10. c++实验3—定期存款利息计算器