Clickhouse 系列 - 番外 - 零拷贝

Posted cfcz48

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Clickhouse 系列 - 番外 - 零拷贝相关的知识,希望对你有一定的参考价值。

本文将向读者详细说明第三章中提到的无序存储时,每次读取需要读取 4k 的底层细节。第三章的附录已将向读者说明了 “这个原因是因为操作系统在读取磁盘时,依据数据局部性原理,会按照页为单位读取,每页的大小默认是 4k。“本番外将向读者由此深入到一个计算机领域常用的一个优化——零拷贝技术。

在 linux 系统中,提供了 3 套 API 供应用执行文件操作:

  1. 系统调用
  2. 标准 I/O
  3. mmap

第一种系统调用,是操作系统对外直接提供的文件 API,提供对文件的字节读写操作。操作系统在其内部实现了页缓存机制,对应用端透明,操作系统根据访问页情况自行调整缓冲区大小。

第二种标准 I/O,也就是大名鼎鼎的 <stdio.h>。其通过流的方式实现对文件的操作。开发 stdio 的原因是因为系统调用的页缓存太大(16K~128K), 而一些简单的应用,并不需要这么大的缓存,同时也由于调用系统调用涉及到 CPU 由用户模型向内核模式的切换,时间消耗比较大,因此开发了标准 IO,可以看成是对内核的缓冲。

第三种 mmap,就是所谓的零拷贝了。第二章标准 IO 适合简单的程序使用,但是对于数据库这样的对性能要求高的程序就会有个知名的缺点。标准 IO 本质是对第一种方式的缓冲,是通过在用户空间复制一份数据实现的,标准 IO 会将第一种系统调用 read() 生成的数据复制到用户空间一份,后续操作都在用户空间上进行操作,等待合适时机写会内核。此时,数据就发生了两次拷贝:即内核系统调用 read() 将数据复制到内核空间的内存上,和标准 io 将数据复制到用户空间。这也势必带来了性能损耗,幸好内核提供了 mmap,支持应用将文件地址直接映射到当前进程的内存空间,这样应用就可以直接操作内存,由内核负责将内容同步到磁盘。

大部分数据库都使用 mmap 实现零拷贝,避免标准 IO 出现的两次拷贝的情况。不过 mmap 将文件内容映射到内存,而操作系统的内存管理单元(MMU)管理内存最小单位是页,因此 mmap 必须按照页的整数倍组织映射大小。这就是第三章计算中出现 4K 的原因。

使用 mmap 还有一个好处就是,除了少数的一些缺页异常,对 mmap 的读写都在用户空间进行。不会产生系统调用。此外,操作 mmap 还可以通过 madvise() 系统调用按需控制内核是否使用预读机制从而控制页缓存的大小。

mmap 是现代应用程序应用非常广的一项技术,kafka 的 commitlog、postgresql 的存储引擎…… 这些知名数据库都在大量应用零拷贝技术。但依然像我之前强调的那样,使用 mmap 也不是没有缺点,主要缺点是必须按照页的整数倍来组织大小,容易出现空间浪费。因此在处理大文件或者文件大小正好是 pagesize 的整数倍时,使用 mmap 会获得很大的性能提升。

以上是关于Clickhouse 系列 - 番外 - 零拷贝的主要内容,如果未能解决你的问题,请参考以下文章

Clickhouse 系列

8.JVM系列-零拷贝

百万并发「零拷贝」技术系列之经典案例Netty

六.Netty入门到超神系列-Java NIO零拷贝实战

五.Netty入门到超神系列-零拷贝技术

(转)(终极改良版)python基础番外——赋值与深浅拷贝