用于随机读取的 mmap 与 O_DIRECT(涉及哪些缓冲区?)

Posted

技术标签:

【中文标题】用于随机读取的 mmap 与 O_DIRECT(涉及哪些缓冲区?)【英文标题】:mmap vs O_DIRECT for random reads (what are the buffers involved?) 【发布时间】:2013-11-23 09:18:49 【问题描述】:

我正在实现一个基于磁盘的哈希表,支持大量键(26+ 百万)。该值被反序列化。整个文件的读取基本上是随机的,值小于页面大小,我正在针对 SSD 进行优化。安全/一致性不是那么大的问题(性能问题)。

我当前的解决方案是使用 mmap() 文件并设置 MADV_RANDOM | MADV_DONTNEED 以禁用内核预取,并且仅按需加载数据。

我知道内核从磁盘读取到内存缓冲区,然后我从那里反序列化。

O_DIRECT 呢?如果我调用read(),我仍在复制到缓冲区(我从中反序列化)所以我可以获得任何优势吗?

我在哪里可以找到有关mmap() 文件和在使用O_DIRECT 打开的文件上调用read() 的缓冲区的更多信息?

我对预读或缓存不感兴趣。它对我的用例没有任何好处。

【问题讨论】:

【参考方案1】:

O_DIRECT 是读/写操作的选项,当数据绕过系统缓冲区并直接从缓冲区复制到磁盘控制器时。为了获得 O_DIRECT 的优势,需要 遵守一些条件——按内存页缓冲区地址保持对齐,按 I/O 块对齐缓冲区大小。

无论如何,如果您使用 mmap,则不使用读/写。此外,在 mmap 之后,您可以关闭文件描述符,映射仍然有效。所以,O_DIRECT 对 mmap 选项没用。

我可以推荐什么来提高性能:

    如果您的子系统有很多搜索缺失键的请求,您可以在内存中创建布隆过滤器。此后,您在 Bloom 过滤器 http://en.wikipedia.org/wiki/Bloom_filter 上匹配您的搜索键,并拒绝丢失的键,而无需对磁盘进行实际请求。

    为了节省内存,请使用 2 级方案,当桶头保存在 mmap 内存中时,但桶本身是通过 pread() 从文件中读取的。

我在我的自动完成子系统中实现了这两个选项,您可以在此处在线查看:http://olegh.ftp.sh/autocomplete.html 并估计慢旧计算机 - Celeron-300 上的性能。

【讨论】:

以上是关于用于随机读取的 mmap 与 O_DIRECT(涉及哪些缓冲区?)的主要内容,如果未能解决你的问题,请参考以下文章

mmap的随机化

mmap()与阅读块

O_DIRECT 与 AIO_RAW

用于矢量化的随机读取上的结构阵列 (AoS) 与阵列结构 (SoA)

使用内存映射文件读取大文件

mmap 的可执行文件可以多次使用吗?