- 文档
- 教程
- 知识库
【免费下载链接】CS-Base
图解计算机网络、操作系统、计算机组成、数据库,共 1000 张图 + 50 万字,破除晦涩难懂的计算机基础知识,让天下没有难懂的八股文!🚀 在线阅读:https://xiaolincoding.com
导读
本文是 CS-Base 图解计算机基础仓库《图解系统》网络系统章节的核心内容之一,以「文件传输」为切入点,从 DMA 技术的诞生讲起,逐步拆解传统 I/O 的四大开销(4 次上下文切换 + 4 次数据拷贝),再到mmap + write、sendfile两种零拷贝实现方案,最后落到 PageCache 的缓存与预读机制、大文件场景下「异步 I/O + 直接 I/O」的选型策略。读完本文,你将掌握零拷贝的原理、内核版本与网卡硬件前提(SG-DMA)、ethtool与 Nginx 的实测配置方法,以及 Kafka、Nginx 两大开源项目落地零拷贝的具体代码与配置证据,并能依据文件大小在 Nginx 中做出正确的传输方案选型。
为什么要有 DMA 技术?
磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上。因此针对优化磁盘的技术非常多,比如零拷贝、直接 I/O、异步 I/O 等,这些优化的目的都是为了提高系统的吞吐量;另外,操作系统内核中的磁盘高速缓存区,可以有效地减少磁盘的访问次数。理解这些优化手段,首先要从 I/O 的搬运工——DMA 技术说起。
没有 DMA 的时代:CPU 亲自搬数据
在没有 DMA 技术前,一次 I/O 的过程是这样的:
- CPU 发出对应的指令给磁盘控制器,然后返回;
- 磁盘控制器收到指令后开始准备数据,会把数据放入磁盘控制器的内部缓冲区中,然后产生一个中断;
- CPU 收到中断信号后,停下手头的工作,接着把磁盘控制器缓冲区中的数据一次一个字节地读进自己的寄存器,然后再把寄存器里的数据写入内存——而在数据传输的期间,CPU 是无法执行其他任务的。
可以看到,整个数据的传输过程都需要 CPU 亲自参与搬运数据,而且这个过程中 CPU 不能做其他任何事情。简单的几个字符数据搬运没问题,但如果用千兆网卡或者硬盘传输大量数据时,都用 CPU 来搬运,肯定忙不过来。
DMA 技术的诞生:把搬运交给专门的控制
计算机科学家们发现了问题的严重性后,发明了 DMA 技术,也就是直接内存访问(Direct Memory Access)技术。
什么是 DMA?简单理解就是:在进行 I/O 设备和内存的数据传输时,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。
使用 DMA 控制器进行数据传输的具体过程如下:
- 用户进程调用
read方法,向操作系统发出 I/O 请求,请求读取数据到自己的内存缓冲区中,进程进入阻塞状态; - 操作系统收到请求后,进一步将 I/O 请求发送给 DMA,然后让 CPU 执行其他任务;
- DMA 进一步将 I/O 请求发送给磁盘;
- 磁盘收到 DMA 的 I/O 请求,把数据从磁盘读取到磁盘控制器的缓冲区中,当磁盘控制器的缓冲区被读满后,向 DMA 发起中断信号,告知自己缓冲区已满;
- DMA 收到磁盘的信号,将磁盘控制器缓冲区中的数据拷贝到内核缓冲区中,此时不占用 CPU,CPU 可以执行其他任务;
- 当 DMA 读取了足够多的数据,就会发送中断信号给 CPU;
- CPU 收到 DMA 的信号,知道数据已经准备好,于是将数据从内核拷贝到用户空间,系统调用返回。
可以看到,整个数据传输的过程中,CPU 不再参与数据搬运的工作,而是全程由 DMA 完成。但是 CPU 在这个过程中也是必不可少的:传输什么数据、从哪里传输到哪里,都需要 CPU 来告诉 DMA 控制器——DMA 只是执行者,决策仍由 CPU 做出。
值得补充的历史背景是:早期 DMA 只存在于主板上,如今由于 I/O 设备越来越多,数据传输的需求也不尽相同,所以每个 I/O 设备(磁盘控制器、网卡等)里面都集成了自己的 DMA 控制器。
传统的文件传输有多糟糕?
如果服务端要提供文件传输的功能,我们能想到的最简单方式是:将磁盘上的文件读取出来,然后通过网络协议发送给客户端。
传统 I/O 的工作方式是,数据读取和写入在用户空间与内核空间之间来回复制,而内核空间的数据是通过操作系统层面的 I/O 接口从磁盘读取或写入的。代码通常如下,一般需要两个系统调用:
read(file, tmp_buf, len); write(socket, tmp_buf, len);代码很简单,虽然就两行代码,但是里面发生了不少的事情。
4 次用户态与内核态的上下文切换
期间共发生了4 次用户态与内核态的上下文切换,因为发生了两次系统调用,一次是read(),一次是write()。每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态。
上下文切换的成本并不小,一次切换需要耗时几十纳秒到几微秒,虽然时间看上去很短,但是在高并发的场景下,这类时间容易被累积和放大,从而影响系统的性能。
4 次数据拷贝
其次,还发生了4 次数据拷贝,其中两次是 DMA 的拷贝,另外两次是通过 CPU 拷贝的:
- 第一次拷贝:把磁盘上的数据拷贝到操作系统内核的缓冲区里,这个拷贝过程是通过 DMA 搬运的;
- 第二次拷贝:把内核缓冲区的数据拷贝到用户的缓冲区里,于是应用程序就可以使用这部分数据了,这个拷贝过程由 CPU 完成;
- 第三次拷贝:把刚才拷贝到用户缓冲区里的数据,再拷贝到内核的 socket 缓冲区里,这个过程依然由 CPU 搬运;
- 第四次拷贝:把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程由 DMA 搬运。
我们回过头看这个文件传输的过程:只是搬运一份数据,结果却搬运了 4 次。过多的数据拷贝无疑会消耗 CPU 资源,大大降低了系统性能。
结论很明确:这种简单又传统的文件传输方式,存在冗余的上下文切换和数据拷贝,在高并发系统里是非常糟糕的,多了很多不必要的开销,会严重影响系统性能。要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数。
如何优化文件传输的性能?
方向一:减少上下文切换,本质是减少系统调用
读取磁盘数据的时候,之所以要发生上下文切换,是因为用户空间没有权限操作磁盘或网卡,内核的权限最高,这些操作设备的过程都需要交由操作系统内核来完成,所以一般要通过内核去完成某些任务时,就需要使用操作系统提供的系统调用函数。
而一次系统调用必然会发生 2 次上下文切换:首先从用户态切换到内核态,当内核执行完任务后,再切换回用户态交由进程代码执行。所以,要想减少上下文切换的次数,就要减少系统调用的次数。
方向二:减少数据拷贝,消灭无意义的用户缓冲区
在前面我们知道了,传统的文件传输方式会历经 4 次数据拷贝,其中「从内核的读缓冲区拷贝到用户的缓冲区里,再从用户的缓冲区里拷贝到 socket 的缓冲区里」这个往返过程是没有必要的。
因为在文件传输的应用场景中,用户空间并不会对数据「再加工」,数据实际上可以不用搬运到用户空间,因此用户的缓冲区是没有必要存在的。这也正是零拷贝技术后续得以成立的前提——传输即转发,不做中间加工。
如何实现零拷贝?
零拷贝技术实现的方式通常有 2 种:
mmap + writesendfile
下面分别来看它们是如何减少「上下文切换」和「数据拷贝」次数的。
mmap + write
在前面我们知道,read()系统调用的过程中会把内核缓冲区的数据拷贝到用户的缓冲区里。为了减少这一步开销,可以用mmap()替换read()系统调用函数:
buf = mmap(file, len); write(sockfd, buf, len);mmap()系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样操作系统内核与用户空间就不需要再进行任何的数据拷贝操作。具体过程如下:
- 应用进程调用了
mmap()后,DMA 会把磁盘的数据拷贝到内核的缓冲区里。接着,应用进程跟操作系统内核「共享」这个缓冲区; - 应用进程再调用
write(),操作系统直接将内核缓冲区的数据拷贝到 socket 缓冲区中,这一切都发生在内核态,由 CPU 来搬运数据; - 最后,把内核的 socket 缓冲区里的数据拷贝到网卡的缓冲区里,这个过程由 DMA 搬运。
由此可得:通过使用mmap()来代替read(),可以减少一次数据拷贝的过程(省去了「内核缓冲区 → 用户缓冲区」这一次拷贝,因为用户空间与内核空间共享同一份内核缓冲区)。
但这还不是最理想的零拷贝,因为仍然需要通过 CPU 把内核缓冲区的数据拷贝到 socket 缓冲区里,而且仍然需要4 次上下文切换(系统调用还是 2 次)。
从更底层的视角看,
mmap之所以能做到零拷贝,是因为它把内核缓冲区(PageCache 中的文件页)通过虚拟内存机制映射到进程地址空间,进程通过缺页中断按需访问文件页,而不必像read那样显式地把数据"搬"进用户缓冲区。仓库中 深入理解 Linux 虚拟内存管理 一文对虚拟内存的映射与缺页机制有更详细的图解说明。
sendfile
在 Linux 内核版本2.1中,提供了一个专门发送文件的系统调用函数sendfile(),函数形式如下:
#include <sys/socket.h> ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);它的前两个参数分别是目的端和源端的文件描述符,后面两个参数是源端的偏移量和复制数据的长度,返回值是实际复制数据的长度。
首先,它可以替代前面的read()和write()这两个系统调用,这样就减少了一次系统调用,也就减少了 2 次上下文切换的开销。
其次,该系统调用可以直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态,这样就只有2 次上下文切换和3 次数据拷贝。
但这还不是真正的零拷贝技术——如果网卡支持SG-DMA(The Scatter-Gather Direct Memory Access)技术(和普通的 DMA 有所不同),我们可以进一步减少通过 CPU 把内核缓冲区里的数据拷贝到 socket 缓冲区的过程。
你可以在自己的 Linux 系统通过下面这个命令,查看网卡是否支持 scatter-gather 特性:
$ ethtool -k eth0 | grep scatter-gather scatter-gather: on当输出为scatter-gather: on时,说明该网卡支持 SG-DMA。于是,从 Linux 内核2.4版本开始,对于支持 SG-DMA 技术的网卡,sendfile()系统调用的过程发生了变化:
- 第一步:通过 DMA 将磁盘上的数据拷贝到内核缓冲区里;
- 第二步:缓冲区描述符和数据长度传到 socket 缓冲区,这样网卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里。此过程不需要将数据从操作系统内核缓冲区拷贝到 socket 缓冲区中,这样就减少了一次数据拷贝。
所以这个过程之中,只进行了2 次数据拷贝。
这就是所谓的零拷贝(Zero-copy)技术:我们没有在内存层面去拷贝数据,全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来传输的。
零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数——只需要 2 次上下文切换和 2 次数据拷贝,就可以完成文件的传输,而且这 2 次数据拷贝都不需要经过 CPU,全部由 DMA 来搬运。所以总体来看,零拷贝技术可以把文件传输的性能提高至少一倍以上。
两种零拷贝方案的对比小结
| 实现方案 | 系统调用次数 | 上下文切换 | 数据拷贝 | CPU 参与拷贝 |
|---|---|---|---|---|
传统read + write | 2 | 4 次 | 4 次 | 2 次(CPU)+ 2 次(DMA) |
mmap + write | 2 | 4 次 | 3 次 | 1 次(CPU)+ 2 次(DMA) |
sendfile(无 SG-DMA 网卡) | 1 | 2 次 | 3 次 | 1 次(CPU)+ 2 次(DMA) |
sendfile+ SG-DMA 网卡(真零拷贝) | 1 | 2 次 | 2 次 | 0 次,全部 DMA |
使用零拷贝技术的项目
Kafka:基于 Java NIO 的transferTo
事实上,Kafka 这个开源项目就利用了「零拷贝」技术,从而大幅提升了 I/O 的吞吐率,这也是 Kafka 在处理海量数据为什么这么快的原因之一。
如果追溯 Kafka 文件传输的代码,你会发现它最终调用了 Java NIO 库里的transferTo方法(这里展示的是其transferFrom适配代码,内部委托给FileChannel.transferTo):
@Override public long transferFrom(FileChannel fileChannel, long position, long count) throws IOException { return fileChannel.transferTo(position, count, socketChannel); }如果 Linux 系统支持sendfile()系统调用,那么transferTo()实际上最后就会使用到sendfile()系统调用函数——也就是说,Java 的FileChannel.transferTo在 Linux 上的底层实现正是内核的sendfile,Kafka 正是借由这条链路获得了零拷贝的收益。
曾经有大佬专门写过程序测试过:在同样的硬件条件下对比传统文件传输和零拷贝文件传输的性能差异,使用了零拷贝能够缩短65%的时间(该测试数据出自 IBM 官方 zero-copy 技术专题文章),大幅提升了机器传输数据的吞吐量。
Nginx:默认开启的sendfile配置
另外,Nginx 也支持零拷贝技术,一般默认开启零拷贝技术,这样有利于提高文件传输的效率。是否开启零拷贝技术的配置如下:
http { ... sendfile on ... }sendfile配置的具体含义:
- 设置为
on:使用零拷贝技术来传输文件(sendfile),这样只需要 2 次上下文切换和 2 次数据拷贝; - 设置为
off:使用传统的文件传输技术(read + write),这时就需要 4 次上下文切换和 4 次数据拷贝。
当然,要使用 sendfile,Linux 内核版本必须是 2.1 以上。
PageCache 有什么作用?
回顾前面的文件传输过程,其中第一步都是先把磁盘文件数据拷贝到「内核缓冲区」里,这个「内核缓冲区」实际上是磁盘高速缓存(PageCache)。由于零拷贝使用了 PageCache 技术,可以使得零拷贝进一步提升了性能,接下来看看 PageCache 是如何做到这一点的。
PageCache 的本质:用内存换磁盘
读写磁盘相比读写内存的速度慢太多了,所以我们应该想办法把「读写磁盘」替换成「读写内存」。于是,我们会通过 DMA 把磁盘里的数据搬运到内存里,这样就可以用读内存替换读磁盘。
但是,内存空间远比磁盘要小,内存注定只能拷贝磁盘里的一小部分数据。那问题来了:选择哪些磁盘数据拷贝到内存呢?
两大优势:缓存最近访问的数据 + 预读
我们都知道程序运行的时候具有「局部性」,所以通常,刚被访问的数据在短时间内再次被访问的概率很高,于是我们可以用PageCache 来缓存最近被访问的数据,当空间不足时淘汰最久未被访问的缓存。
所以,读磁盘数据的时候,优先在 PageCache 里找:如果数据存在则可以直接返回;如果没有,则从磁盘中读取,然后缓存到 PageCache 中。
还有一点:读取磁盘数据时需要找到数据所在的位置,对于机械磁盘来说,就是通过磁头旋转到数据所在的扇区,再开始「顺序」读取数据,而旋转磁头这个物理动作非常耗时。为了降低它的影响,PageCache 使用了「预读功能」。
比如,假设read方法每次只会读 32 KB 的字节,虽然 read 刚开始只会读 0 ~ 32 KB 的字节,但内核会把其后面的 32 ~ 64 KB 也读取到 PageCache,这样后面读取 32 ~ 64 KB 的成本就很低。如果在 32 ~ 64 KB 被淘汰出 PageCache 前,进程读取到它了,收益就非常大。
所以,PageCache 的优点主要是两个:
- 缓存最近被访问的数据;
- 预读功能。
这两个做法,将大大提高读写磁盘的性能。
大文件场景:PageCache 反而有害
但是,在传输大文件(GB 级别)的时候,PageCache 会不起作用,那就白白浪费 DMA 多做的一次数据拷贝,造成性能降低,即使使用了 PageCache 的零拷贝也会损失性能。
原因在于:如果有很多 GB 级别文件需要传输,每当用户访问这些大文件时,内核就会把它们载入 PageCache 中,于是 PageCache 空间很快被这些大文件占满。另外,由于文件太大,可能某些部分的文件数据被再次访问的概率比较低,这样就会带来 2 个问题:
- PageCache 由于长时间被大文件占据,其他「热点」的小文件可能就无法充分使用到 PageCache,于是磁盘读写的性能就会下降;
- PageCache 中的大文件数据,由于没有享受到缓存带来的好处,却耗费 DMA 多拷贝到 PageCache 一次。
所以,针对大文件的传输,不应该使用 PageCache,也就是说也不应该使用零拷贝技术。因为可能由于 PageCache 被大文件占据,而导致「热点」小文件无法利用到 PageCache,这样在高并发的环境下,会带来严重的性能问题。
关于 PageCache 更底层的机制,仓库中 进程写文件时,进程发生了崩溃,已写入的数据会丢失吗? 一文做了系统讲解:PageCache 的本质是由 Linux 内核管理的内存区域,由多个 4KB(32/64 位系统默认页大小)的 page 构成,对应磁盘上的若干数据块(file-backed pages);可以通过
cat /proc/meminfo与free命令实时观测 PageCache 占用,公式为Page Cache = Buffers + Cached + SwapCached;PageCache 还承担了脏页回写(write-back)的职责,可用fsync、fdatasync、sync强制落盘,这与本文讨论的缓存 I/O 与直接 I/O 的取舍一脉相承。
大文件传输用什么方式实现?
那针对大文件的传输,应该使用什么方式呢?
先看阻塞 I/O 的问题
先来看最初的例子:当调用read方法读取文件时,进程实际上会阻塞在read方法调用,因为要等待磁盘数据的返回。具体过程:
- 当调用
read方法时,会阻塞着,此时内核会向磁盘发起 I/O 请求,磁盘收到请求后便会寻址;当磁盘数据准备好后,就会向内核发起 I/O 中断,告知内核磁盘数据已经准备好; - 内核收到 I/O 中断后,就将数据从磁盘控制器缓冲区拷贝到 PageCache 里;
- 最后,内核再把 PageCache 中的数据拷贝到用户缓冲区,于是
read调用就正常返回了。
异步 I/O:发起请求不等待,就绪后通知
对于阻塞的问题,可以用异步 I/O来解决。它把读操作分为两部分:
- 前半部分:内核向磁盘发起读请求,但是可以不等待数据就位就可以返回,于是进程此时可以处理其他任务;
- 后半部分:当内核将磁盘中的数据拷贝到进程缓冲区后,进程将接收到内核的通知,再去处理数据。
而且可以发现,异步 I/O 并没有涉及到 PageCache,所以使用异步 I/O 就意味着要绕开 PageCache。
补充同步 / 异步 I/O 的概念边界:无论
read是阻塞还是非阻塞,都属于同步调用——因为内核将数据从内核空间拷贝到用户空间的过程都需要等待;而真正的异步 I/O 是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程都不用等待,发起请求后立即返回,由内核自动完成数据拷贝后再通知应用程序。这一组概念在仓库的 高性能网络模式:Reactor 和 Proactor 一文中有更完整的辨析,文中还提到 Linux 下的aio系列函数仅支持本地文件、不支持 socket,因此本文讨论的「异步 I/O + 直接 I/O」正是针对大文件磁盘读取场景的有效组合。
绕开 PageCache:直接 I/O
绕开 PageCache 的 I/O 叫直接 I/O,使用 PageCache 的 I/O 则叫缓存 I/O。通常,对于磁盘,异步 I/O 只支持直接 I/O。
前面也提到,大文件的传输不应该使用 PageCache,因为可能由于 PageCache 被大文件占据,而导致「热点」小文件无法利用到 PageCache。于是,在高并发的场景下,针对大文件的传输方式,应该使用「异步 I/O + 直接 I/O」来替代零拷贝技术。
直接 I/O 应用场景常见的两种:
- 应用程序已经实现了磁盘数据的缓存,那么可以不需要 PageCache 再次缓存,减少额外的性能损耗。在 MySQL 数据库中,可以通过参数设置开启直接 I/O,默认是不开启;
- 传输大文件的时候,由于大文件难以命中 PageCache 缓存,而且会占满 PageCache 导致「热点」文件无法充分利用缓存,从而增大了性能开销,因此这时应该使用直接 I/O。
另外,由于直接 I/O 绕过了 PageCache,就无法享受内核的这两点优化:
- 内核的 I/O 调度算法会缓存尽可能多的 I/O 请求在 PageCache 中,最后「合并」成一个更大的 I/O 请求再发给磁盘,这样做是为了减少磁盘的寻址操作;
- 内核也会「预读」后续的 I/O 请求放在 PageCache 中,一样是为了减少对磁盘的操作。
于是,传输大文件的时候,使用「异步 I/O + 直接 I/O」,就可以无阻塞地读取文件了。
按文件大小分流:Nginx 的阈值配置
所以,传输文件的时候,要根据文件的大小来使用不同的方式:
- 传输大文件的时候,使用「异步 I/O + 直接 I/O」;
- 传输小文件的时候,则使用「零拷贝技术」。
在 Nginx 中,可以用如下配置,根据文件的大小来使用不同的方式:
location /video/ { sendfile on; aio on; directio 1024m; }当文件大小**大于directio值(示例为 1024m)**后,使用「异步 I/O + 直接 I/O」;否则使用「零拷贝技术」。
总结
回顾整条文件传输优化的演进脉络,可以梳理出如下结论:
1. DMA 解放了 CPU。早期 I/O 操作中,内存与磁盘的数据传输工作都由 CPU 完成,此时 CPU 不能执行其他任务,会特别浪费 CPU 资源。DMA 技术出现后,每个 I/O 设备都有自己的 DMA 控制器,CPU 只需要告诉 DMA 控制器"要传输什么数据、从哪里来、到哪里去",就可以放心离开,后续的实际数据传输都由 DMA 控制器完成。
2. 传统 I/O 的开销是 4 + 4。传统 I/O 的工作方式,从硬盘读取数据再通过网卡向外发送,需要进行4 次上下文切换和4 次数据拷贝:其中 2 次数据拷贝发生在内存缓冲区和对应硬件设备之间(由 DMA 完成),另外 2 次发生在内核态和用户态之间(由 CPU 完成)。
3. 零拷贝用一次系统调用换掉两次。为了提高文件传输性能,零拷贝技术通过一次系统调用(sendfile方法)合并了磁盘读取与网络发送两个操作,降低了上下文切换次数;另外,拷贝数据都发生在内核中,天然就降低了数据拷贝的次数。在支持 SG-DMA 的网卡上,全程无 CPU 参与搬运,仅 2 次上下文切换 + 2 次 DMA 拷贝。
4. Kafka 与 Nginx 是落地的标杆。Kafka 通过 Java NIO 的transferTo(底层映射 Linuxsendfile)大幅提升 I/O 吞吐率;Nginx 默认开启sendfile on,两种开关对应的性能开销差异清晰可测。
5. 零拷贝的根基是 PageCache。零拷贝技术是基于 PageCache 的,PageCache 会缓存最近访问的数据,提升了访问缓存数据的性能;同时,为了解决机械硬盘寻址慢的问题,它还协助 I/O 调度算法实现了I/O 合并与预读,这也是顺序读比随机读性能好的原因。这些优势进一步提升了零拷贝的性能。
6. 零拷贝有明确的适用边界。需要注意,零拷贝技术不允许进程对文件内容做进一步的加工(比如压缩数据再发送);另外,当传输大文件时不能使用零拷贝,因为 PageCache 可能被大文件占据导致「热点」小文件无法利用 PageCache,且大文件的缓存命中率不高,这时就需要使用「异步 I/O + 直接 I/O」的方式。在 Nginx 里,可以通过directio配置设定文件大小阈值,针对大文件使用异步 I/O 和直接 I/O,对小文件使用零拷贝。
延伸阅读
- CS-Base 图解系统:网络系统章节总览:查看《图解系统》网络系统章节的完整目录,零拷贝与 I/O 多路复用、Reactor/Proactor 同属网络系统性能优化主题;
- 进程写文件时,进程发生了崩溃,已写入的数据会丢失吗?:深入 PageCache 本质、缓存 I/O 与直接 I/O 的取舍、脏页回写机制;
- I/O 多路复用:select/poll/epoll:理解高性能网络服务并发处理大量连接的系统调用基础;
- 高性能网络模式:Reactor 和 Proactor:辨析阻塞/非阻塞、同步/异步 I/O 概念,理解异步网络模式为何在 Linux 上受限于本地文件 I/O;
- 深入理解 Linux 虚拟内存管理:理解
mmap映射机制背后的虚拟内存与缺页中断原理。
- 文档
- 教程
- 知识库
【免费下载链接】CS-Base
图解计算机网络、操作系统、计算机组成、数据库,共 1000 张图 + 50 万字,破除晦涩难懂的计算机基础知识,让天下没有难懂的八股文!🚀 在线阅读:https://xiaolincoding.com
相关推荐
konyshe/gogo的DMA零拷贝网络传输优化:从内核态到用户态的性能革命
konyshe/gogo的DMA零拷贝网络传输优化:从内核态到用户态的性能革命 ? 性能瓶颈:传统网络传输的4次CPU拷贝 在传统Linux网络协议栈中,数据包
后端Web框架Go语言精进之路网络编程深度解析:TCP/UDP、HTTP/2与WebSocket
Go语言精进之路网络编程深度解析:TCP/UDP、HTTP/2与WebSocket Go语言凭借其卓越的并发模型和简洁的语法,在网络编程领域展现出强大实力。本文
Apache Fury零拷贝技术揭秘:为什么它比传统序列化快170倍
Apache Fury零拷贝技术揭秘:为什么它比传统序列化快170倍 Apache Fury是一个基于JIT和零拷贝技术的多语言序列化框架,能够提供极致的性能表
基础架构开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考