【问题标题】:Block based storage基于块的存储
【发布时间】:2011-09-19 00:21:55
【问题描述】:

我想将几个条目存储到一个文件中(针对读取进行了优化),一个好的数据结构似乎是 B+ 树。它提供 O(log(n)/log(b)) 访问时间,其中 b 是一个块中的条目数。

有很多论文等描述了 B+ 树,但总体上我在理解基于块的存储系统方面仍然存在一些问题。也许有人可以为我指出正确的方向或回答几个问题:

  1. (所有常见的)文件系统是否会在新块的开头创建新文件?那么,我可以确定 seek(0) 会将读/写头设置为设备块大小的倍数吗?
  2. 我应该只使用像pread(fd, buf, n * BLOCK_SIZE, p * BLOCK_SIZE) 这样的调用(n,p 是整数)来确保我总是读取完整的块,这对吗?
  3. 是 read() BLOCK_SIZE 字节到数组还是 mmap() 更好?或者,如果我映射许多块并且只访问几个块,那么只有区别吗?什么更好?
  4. 我是否应该通过在每个块的末尾添加填充字节来避免键生成多个块?我是否也应该通过在数据之间添加填充字节来对叶节点执行相同的操作?

非常感谢,
克里斯托夫

【问题讨论】:

    标签: linux filesystems io b-tree


    【解决方案1】:
    1. 是的。否则会导致 FS 设计出现不必要的复杂情况。
    2. 选项(作为“仅”的替代)是...?
    3. 在 Windows 中,内存映射文件比文件 API (ReadFile) 运行得更快。我猜在 Linux 上是一样的,但你可以进行自己的测量

    【讨论】:

      【解决方案2】:
      1. 支持延迟分配的文件系统不会在磁盘上任何地方创建新文件。许多较新的文件系统支持将非常小的文件打包到自己的页面中或与元数据共享(例如,reiser 将非常小的文件放入 inode 中?)。但对于较大的文件,大多数情况下,是的。

      2. 您可以这样做,但操作系统页面缓存将始终读取整个块,并将您请求的位复制到应用程序的内存中。

      3. 这取决于您使用的是直接 IO 还是非直接 IO。

      如果您使用绕过操作系统缓存的直接 IO,则不要使用 mmap。大多数数据库不使用mmap,使用直接IO。

      直接 IO 意味着页面不经过操作系统的页面缓存,它们根本不会被操作系统缓存,也不会将其他块推出操作系统缓存。这也意味着所有的读取和写入都需要在块边界上完成。块边界有时可以通过文件系统上的 statfs 调用来确定。

      大多数数据库似乎都认为它们应该自己管理自己的页面缓存,并且仅将操作系统用于物理读/写。因此,它们通常使用直接和同步 IO。

      著名的 Linus Torvalds 不同意这种方法。我认为供应商确实这样做是为了在不同操作系统之间实现更好的行为一致性。

      【讨论】:

      • 是的。尽管对此愤世嫉俗的事情(Torvalds 先生不同意......)是数据库供应商别无选择,除非他们只想为磁盘 IO 生成一个线程,因为madvise/msync 被故意破坏Linux,manpages 对你撒谎,如果没有给出 O_DIRECT,KAIO 会恢复为同步操作。
      • 非常感谢您指出 Direct IO(以及如何确定块大小)。在我看来,Direct IO 可能对 DBMS 非常有用,因为它可以为您提供更多控制权,并且在正确完成时速度更快,尽管您会失去很多舒适度(缓冲、预读......)。
      【解决方案3】:
      1. 通常,文件系统会在新块的开头创建新文件,因为这是底层设备的工作方式。硬盘是块设备,因此只能处理“块”或“扇区”以外的任何内容。此外,操作系统根据页面来处理内存和内存映射,页面通常更大(扇区通常为 512 或 1024 字节,页面通常为 4096 字节)。
        想到的这个规则的一个例外是 ReiserFS,它将小文件直接放入文件系统结构中(如果我没记错的话,它顺便是一棵 B+ 树!)。对于非常小的文件,这实际上是一种可行的优化,因为数据已经在 RAM 中而无需再次搜索,但它同样可以是一种反优化,具体取决于具体情况。

      2. 这并不重要,因为操作系统无论如何都会以完整页面(通常为 4kB)为单位将数据读取到页面缓存中。读取一个字节将传输 4kB 并返回一个字节,读取另一个字节将从页面缓存中为您提供服务(如果它是同一页面或在预读范围内)。

      3. read 是通过从页面缓存复制数据来实现的,而mmap 只是将页面重新映射到您的地址空间(可能将它们标记为写时复制,具体取决于您的保护标志)。因此,mmap 总是至少和通常一样快。 mmap 也更舒服,但缺点是当它需要获取更多不在 RAM 中的页面时,它可能会在意外时间阻塞(不过,对于任何未锁定到内存中的应用程序或数据通常都是如此) . read另一方面,当你告诉它时会阻止,否则不会。
        在 Windows 下也是如此,只是在 Vista 之前的 Windows 下的内存映射文件在高并发下不能很好地扩展,因为缓存管理器会序列化所有内容。

      4. 通常人们会尽量保持数据紧凑,因为更少的数据意味着更少的页面,更少的页面意味着它们在页面缓存中并适合预读范围的可能性更高。因此我不会添加填充,除非出于其他原因(对齐)有必要。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-15
        • 2012-12-15
        • 2018-09-15
        • 2020-03-11
        • 2014-02-18
        • 1970-01-01
        • 1970-01-01
        • 2021-04-07
        相关资源
        最近更新 更多