美文网首页
【PageCache】为啥要聊PageCache?

【PageCache】为啥要聊PageCache?

作者: Bogon | 来源:发表于2023-06-28 00:00 被阅读0次

    一 、 存储介质的性能

    下图左边是磁盘到内存的不同介质,右边形象地描述了每种介质的读写速率。
    一句话总结就是越靠近cpu,读写性能越快。

    image.png

    当前主流存储介质的读写性能,从磁盘到内存、内存到缓存、缓存到寄存器,每上一个台阶,性能就提升10倍。
    如果我们打开一个文件去读里面的内容,你会发现时间读取的时间是远大于磁盘提供的这个时延的,这是为什么呢?
    问题就在内核态和用户态这2个概念后面深藏的I/O逻辑作怪。

    二 、 内核态 & 用户态

    内核态:也称为内核空间。cpu可以访问内存的所有数据,还控制着外围设备的访问,例如硬盘、网卡、鼠标、键盘等。cpu也可以将自己从一个程序切换到另一个程序。

    用户态:也称为用户空间。只能受限的访问内存地址,cpu资源可以被其他程序获取。

    image.png

    坦白地说内核态就是一个高级管理员,它可以控制整个资源的权限,用户态就是一个业务,每个人都可以使用它。
    那计算机为啥要这么分呢?

    由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络。CPU划分出两个权限等级:用户态和内核态。

    32 位操作系统和 64 位操作系统的虚拟地址空间大小是不同的,在 Linux 操作系统中,虚拟地址空间的内部又被分为内核空间和用户空间两部分,如下所示:

    image.png

    通过这里可以看出:

    • 32 位系统的内核空间占用 1G,位于最高处,剩下的 3G 是用户空间;
    • 64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的。

    内核态控制的是内核空间的资源管理,用户态访问的是用户空间内的资源。

    从用户态到内核态切换可以通过三种方式:

    • 系统调用,其实系统调用本身就是中断,但是软件中断,跟硬中断不同。
    • 异常:如果当前进程运行在用户态,如果这个时候发生了异常事件,就会触发切换。例如:缺页异常。
    • 外设中断:当外设完成用户的请求时,会向CPU发送中断信号。
    image.png

    三 、 DMA

    CPU 全程负责内存内的数据拷贝,参考磁盘介质的读写性能,这个操作是可以接受的,但是如果要让内存的数据和磁盘来回拷贝,这个时间消耗就非常的难看,因为磁盘、网卡的速度远小于内存,内存又远远小于 CPU。

    所以计算机体系结构的大佬们就想到了能不能单独地做一个模块来专职负责这个数据的传输,不因为占用cpu而降低系统的吞吐呢?

    方案就是引入了DMA(Direct memory access)

    image.png

    什么是 DMA ?
    没有 DMA ,计算机程序访问磁盘上的数据I/O 的过程是这样的:

    • CPU 先发出读指令给磁盘控制器(发出一个系统调用),然后返回;
    • 磁盘控制器接受到指令,开始准备数据,把数据拷贝到磁盘控制器的内部缓冲区中,然后产生一个中断;
    • CPU 收到中断信号后,让出CPU资源,把磁盘控制器的缓冲区的数据一次一个字节地拷贝进自己的寄存器,然后再把寄存器里的数据拷贝到内存,而在数据传输的期间 CPU 是无法执行其他任务的。
    image.png

    可以看到,整个数据的传输有几个问题:
    一是数据在不同的介质之间被拷贝了多次;
    二是每个过程都要需要 CPU 亲自参与(搬运数据的过程),在这个过程,在数据拷贝没有完成前,CPU 是不能做额外事情的,被IO独占。

    如果I/O操作能比较快的完成,比如简单的字符数据,那没问题。
    如果我们用万兆网卡或者硬盘传输大量数据,CPU就会一直被占用,其他服务无法使用,对单核系统是致命的。

    为了解决上面的CPU被持续占用的问题,大佬们就提出了 DMA 技术,即直接内存访问(Direct Memory Access) 技术。

    那到底什么是 DMA 技术?

    所谓的 DMA(Direct Memory Access,即直接存储器访问)其实是一个硬件技术,其主要目的是减少大数据量传输时的 CPU 消耗,从而提高 CPU 利用效率。

    其本质上是一个主板和 IO 设备上的 DMAC 芯片。
    CPU 通过调度 DMAC 可以不参与磁盘缓冲区到内核缓冲区的数据传输消耗,从而提高效率。

    那有了DMA,数据读取过程是怎么样的呢?
    下面我们来具体看看。

    image.png

    详细过程:

    • 用户进程a调用系统调用read 方法,向OS内核(资源总管)发出 I/O 请求,请求读取数据到自己的内存缓冲区中,进程进入阻塞状态;
    • OS内核收到请求后,进一步将 I/O 请求发送 DMA,然后让 CPU 执行其他任务;
    • DMA 再将 I/O 请求发送给磁盘控制器;
    • 磁盘控制器收到 DMA 的 I/O 请求,把数据从磁盘拷贝到磁盘控制器的缓冲区中,当磁盘控制器的缓冲区被写满后,它向 DMA 发起中断信号,告知自己缓冲区已满;
    • DMA 收到磁盘的中断信号后,将磁盘控制器缓冲区中的数据拷贝到内核缓冲区中,此时不占用 CPU,CPU 可以执行其他任务;
    • 当 DMA 读取了一个固定buffer的数据,就会发送中断信号给 CPU;
    • CPU 收到 DMA 的信号,知道数据已经Ready,于是将数据从内核拷贝到用户空间,结束系统调用;
    image.png image.png

    DMA技术就是释放了CPU的占用时间,它只做事件通知,数据拷贝完全由DMA完成。
    虽然DMA优化了CPU的利用率,但是并没有提高数据读取的性能。
    为了减少数据在2种状态之间的切换次数,因为状态切换是一个非常、非常、非常繁重的工作。
    为此,大佬们就提了零拷贝技术。

    四、 为啥要聊PageCache?

    如果我们总是在磁盘和内存间传输数据,一个大文件的跨机器传输肯定会让你抓狂。那有什么方法加速呢?

    直观的想法就是建立一个离CPU近的一个临时通道,这样就可以加速文件的传输。这个通道就是我们前文提到的「内核缓冲区」,这个「内核缓冲区」实际上是磁盘高速缓存(PageCache)。

    零拷贝就是使用了DMA + PageCache 技术提升了性能,我们来看看 PageCache 是如何做到的。

    从开篇的介质性能看,磁盘相比内存读写的速度要慢很多,所以优化的思路就是尽量的把「读写磁盘」替换成「读写内存」。

    因此通过 DMA 把磁盘里的数据搬运到内存里,转为直接读内存,这样就快多了。但是内存的空间是有限的,成本也比磁盘贵,它只能拷贝磁盘里的一小部分数据。

    那就不可避免的产生一个问题,到底选择哪些磁盘数据拷贝到内存呢?

    从业务的视角来看,业务的数据有冷热之分,我们通过一些的淘汰算法可以知道哪些是热数据,因为数据访问的时序性,被访问过的数据可能被再次访问的概率很高,于是我们可以用 PageCache 来缓存最近被访问的数据,当空间不足时淘汰最久未被访问的数据。

    读 Cache

    当内核发起一个读请求时(例如进程发起read()请求),首先会检查请求的数据是否缓存到了Page Cache中。如果有,那么直接从内存中读取,不需要访问磁盘,这被称为cache命中(cache hit);如果cache中没有请求的数据,即 cache 未命中(cache miss),就必须从磁盘中读取数据。然后内核将读取的数据缓存到 cache 中,这样后续的读请求就可以命中 cache 了。
    page 可以只缓存一个文件部分的内容,不需要把整个文件都缓存进来。

    写 Cache

    当内核发起一个写请求时(例如进程发起write()请求),同样是直接往cache中写入,后备存储中的内容不会直接更新(当服务器出现断电关机时,存在数据丢失风险)。
    内核会将被写入的page标记为dirty,并将其加入dirty list中。内核会周期性地将dirty list中的page写回到磁盘上,从而使磁盘上的数据和内存中缓存的数据一致。
    当满足以下两个条件之一将触发脏数据刷新到磁盘操作:

    • 数据存在的时间超过了 dirty_expire_centisecs (默认300厘秒,即30秒) 时间;
    • 脏数据所占内存 > dirty_background_ratio,也就是说当脏数据所占用的内存占总内存的比例超过dirty_background_ratio(默认10,即系统内存的10%)的时候会触发pdflush刷新脏数据。

    还有一点,现在的磁盘是擦除式读写,每次需要读一个固定的大小,随机读取带来的磁头寻址会增加时延,为了降低它的影响,PageCache 使用了「预读功能」。

    在某些应用场景下,比如我们每次打开文件只需要读取或者写入几个字节的情况,会比Direct I/O多一些磁盘的读取于写入。
    举个例子,假设每次我们要读 32 KB 的字节,read填充到用户buffer的大小是0~32KB,但内核会把其后面的 32~64 KB 也读取到 PageCache,这样后面读取 32~64 KB 的成本就很低,如果在 32~64 KB 淘汰出 PageCache 前,进程需要读这些数据,对比分块读取的方式,这个策略收益就非常大。

    Page Cache 的优势与劣势

    优势:

    • 加快对数据的访问
    • 减少磁盘I/O的访问次数,提高系统磁盘寿命
    • 减少对磁盘I/O的访问,提高系统磁盘I/O吞吐量(Page Cache的预读机制)

    劣势:

    • 使用额外的物理内存空间,当物理内存比较紧俏的时候,可能会导致频繁的swap操作,最终会导致系统的磁盘I/O负载上升。
    • Page Cache没有给应用层提供一个很好的API。导致应用层想要优化Page Cache的使用策略很难。因此一些应用实现了自己的Page管理,比如MySQL的InnoDB存储引擎以16KB的页进行管理。

    另外,由于文件太大,可能某些部分的文件数据已经被淘汰出去了,这样就会带来 2 个问题:

    • PageCache 由于长时间被大文件的部分块占据,而导致一些「热点」的小文件可能就无法常驻 PageCache,导致频繁读写磁盘而引起性能下降;
    • PageCache 中的大文件数据,由于没有全部常驻内存,只有部分无法享受到缓存带来的好处,同时过多的DMA 拷贝动作,增加了时延;

    因此针对大文件的传输,不应该使用 PageCache。

    参考

    用户态、内核态及零拷贝
    https://www.cnblogs.com/koushr/p/5873404.html

    图解零拷贝Zero-Copy技术
    https://zhuanlan.zhihu.com/p/483879791

    计算机内核态、用户态和零拷贝技术
    https://mp.weixin.qq.com/s/sudVOxs8T6JsJk_dAeOXEg

    相关文章

      网友评论

          本文标题:【PageCache】为啥要聊PageCache?

          本文链接:https://www.haomeiwen.com/subject/smzgydtx.html