kafka服务端之日志磁盘存储

news/2025/2/9 5:39:21 标签: kafka, kafka日志磁盘存储

文章目录

  • 页缓存
  • 顺序写
  • 零拷贝

Kafka依赖于文件系统(更底层地来说就是磁盘)来存储和缓存消息 。 那么kafka是如何让自身在使用磁盘存储的情况下达到高性能的?接下来主要从3各方面详细解说。

页缓存

页缓存是操作系统实现的一种主要的磁盘缓存, 以此用来减少对磁盘I/0 的操作。 具体来说, 就是把磁盘中的数据缓存到内存中, 把对磁盘的访间变为对内存的访问。 为了弥补性能上的差异, 现代操作系统越来越 “ 激进地 ” 将内存作为磁盘缓存, 甚至会非常乐意将所有可用的内存用作磁盘缓存, 这样当内存回收时也几乎没有性能损失, 所有对于磁盘的读写也将经由统一的缓存。

当一个进程准备读取磁盘上的文件内容时, 操作系统会先查看待读取的数据所在的页
(page)是否在页缓存(pagecache)中, 如果存在(命中)则直接返回数据, 从而避免了对物理磁盘的I/O操作;如果没有命中, 则操作系统会向磁盘发起读取请求并将读取的数据页存入页缓存, 之后再将数据返回给进程。 同样, 如果 一个进程需要将数据写入磁盘, 那么操作系统也会检测数据对应的页是否在页缓存中, 如果不存在, 则会先在页缓存中添加相应的页, 最后将数据写入对应的页。 被修改过后的页也就变成了脏页, 操作系统会在合适的时间把脏页中的数据写入磁盘, 以保持数据的一致性。

Linux操作系统中的vm.dirty_background_ra巨o参数用来指定当脏页数量达到系统
内存的百分之多少之后就会触发pdflush/flush/kdmflush等后台回写进程的运行来处理脏页, 一般设置为小千10 的值即可,但不建议设置为0。与这个参数对应的还有一个vm.dirty_ratio参数, 它用来指定当脏页数量达到系统内存的百分之多少之后就不得不开始对脏页进行处理,在此过程中, 新的VO请求会被阻挡直至所有脏页被冲刷到磁盘中。

对一个进程而言, 它会在进程内部缓存处理所需的数据, 然而这些数据有可能还缓存在操作系统的页缓存中, 因此同 一份数据有可能被缓存了两次。 并且, 除非使用DirectI/0的方式,否则页缓存很难被禁止。 此外, 用过Java的人一般都知道两点事实: 对象的内存开销非常大,通常会是真实数据大小的几倍甚至更多, 空间使用率低下; Java的垃圾回收会随着堆内数据的增多而变得越来越慢。 基千这些因素, 使用文件系统并依赖于页缓存的做法明显要优于维护 一个进程内缓存或其他结构, 至少我们可以省去了一份进程内部的缓存消耗, 同时还可以通过结构紧凑的字节码来替代使用对象的方式以节省更多的空间。如此, 我们可以在32GB的机器上使用28GB至30GB的内存而不用担心GC所带来的性能间题。 此外, 即使Kafka服务重启,页缓存还是会保持有效, 然而进程内的缓存却需要重建。 这样也极大地简化了代码逻辑, 因为维护页缓存和文件之间的一致性交由操作系统来负责, 这样会比进程内维护更加安全有效。

Kafka 中大量使用了页缓存, 这是Kafka 实现高吞吐的重要因素之一。 虽然消息都是先被写入页缓存, 然后由操作系统负责具体的刷盘任务的, 但在Kafka中同样提供了同步刷盘及间断性强制刷盘( fsync )的功能,这些功能可以通过 log.flush.interval . messages 、log.flush .int erval .m s 等参数来控制。同步刷盘可以提高消息的可靠性,防止由于机器掉电等异常造成处于页缓存而没有及时写入磁盘的消息丢失。不过笔者并不建议这么做,刷盘任务就应交由操作系统去调配,消息的可靠性应该由多副本机制来保障,而不是由同步刷盘这种严重影响性能的行为来保障 。

Linux 系统会使用磁盘的 一部分作为 swap 分区,这样可以进行进程的调度:把当前非活跃的进程调入 swap 分区,以此把内存空出来让给活跃的进程。对大量使用系统页缓存的 Kafka而言,应当尽量避免这种内存的交换,否则会对它各方面的性能产生很大的负面影响 。我们可以通过修改 vm.swappiness 参数 ( Linux 系统参数〉来进行调节 。 vm. swappiηess 参数的上限为 100,它表示积极地使用 swap 分区,并把内存上的数据及时地搬运到 swap 分区中;vm.swappiness 参数的下限为 0 ,表示在任何情况下都不要发生交换( vm . swappiness=0的含义在不同版本的 Linux 内核中不太相同,这里采用的是变更后的最新解释) ,这样一来 ,当内存耗尽时会根据一定的规则突然中止某些进程。可以将这个参数的值设置为 1 ,这样保留了 swap 的机制而又最大限度地限制了它对 Kafka 性能的影响 。

顺序写

Kafka顺序写磁盘是其实现高性能数据存储的关键技术之一。

  • 日志分段:Kafka的每个分区在磁盘上以日志文件的形式存储,这些日志文件会被切分成多个日志段。新消息会不断追加到当前活跃的日志段末尾,当达到一定条件(如文件大小达到阈值或时间间隔),就会创建新的日志段。

  • 顺序追加:生产者发送到Kafka的消息会按照到达的顺序依次追加到分区日志文件中,不会随机插入或修改中间的内容,保证了磁盘写入是顺序的。

优势

  • 提升写入性能:与随机写相比,顺序写磁盘时磁头移动距离小,减少了寻道时间和旋转延迟,能充分利用磁盘的顺序读写带宽,大幅提升写入速度,使Kafka能处理大量并发写入请求。

  • 提高数据可靠性:顺序写的方式使数据在磁盘上连续存储,降低了数据碎片化和存储错误的风险,同时也便于Kafka进行日志的分段、清理和压缩等管理操作,有助于保证数据的完整性和一致性。

实现条件

  • 底层文件系统支持:Kafka依赖底层文件系统提供的顺序写支持,如常见的ext4、XFS等文件系统都能很好地配合Kafka实现顺序写。

  • 合理配置参数:通过合理设置 log.segment.bytes (日志段大小)、 log.roll.hours (日志滚动时间间隔)等参数,能确保Kafka按预期进行日志分段和顺序写入,避免因参数设置不当导致的写入性能下降。

零拷贝

Kafka 还使用零拷 贝 ( Zero-Copy )技术来进一步提升性能 。 所谓的零拷贝是指将数据直接从磁盘文件复制到网卡设备中,而不需要经由应用程序之手 。零拷贝大大提高了应用程序的性能,减少了内核和用户模式之间的上下文切换 。 对 Linux操作系统而言,零拷贝技术依赖于底层的 sendfile() 方法实现 。 对应于 Java 语言,
FileChannal.transferTo()方法的底层实现就是 sendfile()方法 。

传统的文件读写中 文件经历了 4 次复制的过程:

  • (1)调用read()时, 文件A中的内容被复制到了内核态下的Read Buffer中。
  • (2)CPU控制将内核模式数据复制到用户模式下。
  • (3)调用write()时, 将用户模式下的内容复制到内核模式下的SocketBuffer中。
  • (4)将内核模式下的SocketBuffer的数据复制到网卡设备中传送。
    在这里插入图片描述

从上面的过程可以看出, 数据平白无故地从内核模式到用户模式 “ 走了一 圈 ” , 浪费了2次复制过程: 第一次是从内核模式复制到用户模式;第二次是从用户模式再复制回内核模式,即上面4次过程中的第2步和第3步。 而且在上面的过程中, 内核和用户模式的上下文的切换也是4次。

如果采用了零拷贝技术, 那么应用程序可以直接请求内核把磁盘中的数据传输给Socket,如图所示。

在这里插入图片描述

零拷贝技术通过 DMA (Direct Memory Access) 技术将文件内容复制到内核模式下的 Read Buffer 中。 不过没有数据被复制到 Socket Buffer, 相反只有包含数据的位置和长度的信息的文件描述符被加到 Socket Buffer 中。 DMA 引擎直接将数据从内核模式中传递到网卡设备(协议引擎)。 这里数据只经历了2次复制就从磁盘中传送出去了, 并且上下文切换也变成了2次。零拷贝是针对内核模式而言的, 数据在内核模式下实现了零拷贝。


http://www.niftyadmin.cn/n/5845587.html

相关文章

R包:ggalign调整和组合多个图形的R包

文章目录 介绍案例安装R包教程1教程2参考 介绍 这个包扩展了ggplot2,提供了用于对齐和组织多个图的高级工具,特别是那些自动重新排序观察结果的工具,比如树形图。它提供了对布局调整和情节注释的精细控制,使您能够创建复杂的、出…

模板方法模式(Template)

一、模板方法的定义: 在操作中定义业务逻辑框架,包含业务逻辑的方法就是模板方法,模板方法允许子类在不改变原有业务逻辑的流程下,对某些步骤进行扩展和修改; 是一种基于继承的代码复用技术,是一种类行为…

Django开发入门 – 0.Django基本介绍

Django开发入门 – 0.Django基本介绍 A Brief Introduction to django By JacksonML 1. Django简介 1) 什么是Django? 依据其官网的一段解释: Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. …

pytest.fixture

pytest.fixture 是 pytest 测试框架中的一个非常强大的功能,它允许你在测试函数运行前后执行一些设置或清理代码。以下是关于 pytest.fixture 的详细介绍: 一、定义与用途 pytest.fixture 是一个装饰器,用于标记一个函数为 fixture。Fixture 函数中的代码可以在测试函数运…

基于 AI 智能名片 2+1 链动模式 S2B2C 商城小程序的线下门店同城流量运营策略研究

摘要:本文聚焦于线下门店在利用同城流量售卖产品过程中面临的机遇与挑战,深入探讨如何借助 AI 智能名片 21 链动模式 S2B2C 商城小程序优化运营策略。通过分析该模式与线下门店基于抖音平台开展业务的结合点,为线下门店在抖音流量红利下实现人…

Node.js 应用性能测试:Autocannon 的使用与 Docker 集成

在上一篇文章中,我们探讨了如何通过 PM2 和 Docker 的结合来高效管理和部署 Node.js 应用。本文将进一步介绍如何通过 autocannon 这一强大的性能测试工具,评估和优化 Node.js 应用的性能表现。无论是 API 服务、Web 应用,还是微服务架构&…

基于yolov11的阿尔兹海默症严重程度检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv11的阿尔兹海默症严重程度检测系统是一种创新的医疗辅助工具,旨在通过先进的计算机视觉技术提高阿尔兹海默症的早期诊断和病情监测效率。阿尔兹海默症是一种渐进性的神经退行性疾病,通常表现为认知障碍、记忆丧失和语言障碍等症状…

部署open webui 调用ollama启动的deepseek

以下是 部署Open WebUI并调用Ollama的deepseek-70b模型 的详细步骤,重点讲解部署和配置过程: 一、部署 Open WebUI 1. 安装Docker(如已安装可跳过) # 自动安装Docker curl -fsSL https://get.docker.com | sh # 启动Docker服务 …