为什么DBMS不能依赖于操作系统缓冲池?

6
Stonebraker的论文(操作系统对数据库管理的支持)解释道,“从缓冲池管理器中获取块的开销通常包括系统调用和核心到核心的移动。”忘记缓存替换策略等等。我唯一质疑的是引用的那句话。
我的理解是,当DBMS想要读取块x时,它发出一个普通的读取指令。这与任何其他请求读取的应用程序没有区别。
我不是在寻找通用答案(我已经得到了它们并阅读了论文)。我正在寻找所描述问题的详细答案。 请参见Java应用程序从文件读取是否会调用系统调用?

所以,为了澄清一下,“他所谈论的核心转移是什么?”这是你在这里的问题,对吗? - Andres Jaan Tack
5个回答

2
操作系统磁盘I/O必须被泛化以适应各种情况。DBMS有时可以通过使用针对其自身需求进行优化的不太通用的代码来获得重大性能提升。
DBMS使用自己的缓存,因此不想通过操作系统缓存工作。它“拥有”磁盘路径,因此无需担心与其他进程共享。
更新:链接到论文是有帮助的。
首先,该论文已经近30年了,并且涉及到已经过时的硬件。尽管如此,它仍然很有趣。
首先,要理解磁盘I/O是一个分层的过程。在1981年,它就是这样,现在更是如此。在最低点,设备驱动程序将向硬件发出物理读/写指令。在上面可能是操作系统内核代码、操作系统用户空间代码和应用程序。在C程序的fread()和磁盘头移动之间,至少有三到四个级别,甚至可能更多。DBMS可能试图通过绕过一些层并直接与内核甚至更低层交谈来提高性能。
我记得几年前在Sun机器上安装Oracle。它有一个选项,可以将磁盘专用为“原始”分区,其中Oracle会以自己的方式格式化磁盘,然后直接与设备驱动程序通信。操作系统根本无法访问该磁盘。

我无法对答案进行投票。我理解一般的答案,但我想要一个详细的答案来解决上述问题。为什么在所引用的语句描述方面,自己进行缓存/缓冲区管理会更好(我理解访问模式等问题)? - simpatico
这个问题已经进行了五次编辑,并且自从我回答它以来发生了很大的变化。我的答案与原始版本的问题有关。 - Michael J
我正在寻找更多细节。据我了解,数据库管理系统必须像其他应用程序一样发出读取请求(我正在考虑原始分区选项)。为了读取,它必须有一个地址,而且这个地址必须是虚拟内存地址。 - simpatico
为什么磁盘I/O必须与VM管理器链接?如果设置了这种方式,DBMS可以直接向物理磁盘控制器发出命令。我不确定现代的DBMS是否真的这样做,但这肯定是可能的。 - Michael J

2

根据您的另一个问题,以下是进一步了解:

当DBMS必须从磁盘读取页面时,它涉及至少一个系统调用。此时,大多数DBMS将页面放入其自己的缓冲区中。(它们也会出现在操作系统的缓冲区中,但这不重要。)

因此,我们有一个系统调用。但是,我们可以避免任何进一步的系统调用。这是可能的,因为DBMS正在将页面缓存在其自己的内存空间中。当DBMS决定需要某个页面时,它将首先检查并查看它是否在其缓存中。如果是,它将从那里检索而不使用任何系统调用。

DBMS可自由以最有利于其IO需求的方式过期其缓存中的页面。由于操作系统还有其他事情要处理,因此操作系统的缓存以更一般的方式过期。例如,DBMS通常会使用大量内存来缓存页面,因为它知道磁盘IO是它可以执行的最昂贵的操作之一。操作系统不会这样做,因为它必须平衡磁盘IO的成本与为其他应用程序留出内存的成本。


1
总之,数据库管理系统维护自己的缓冲区而不是使用操作系统的缓冲区,以便它们控制何时释放其中的页面。这也避免了每个操作系统缓冲区读取的系统调用,尽管这甚至可以通过操作系统设计来避免。 - simpatico

1

这主要是性能问题。数据库管理系统具有高度特定和不寻常的I/O需求。

操作系统可能有许多进行I/O并填充其缓冲区以产生各种缓存数据的进程。

当然,还有一个问题是大小和何时缓存(与更通用的设备缓存相比,数据库管理系统可以更好地为其需要执行高效缓存)。

此外,一般“块”可能实际上会产生相当大的I/O负担,而数据库管理系统理想情况下不希望承担这种负担;它自己的缓存可以调整得更好,以使其与磁盘上数据的布局更好地配合,从而能够最小化I/O。

另一个问题是索引和类似手段加速查询的问题,如果缓存实际上“知道”这些意味着什么,这当然会更好。


1

真正的问题在于文件缓存不在DBMS使用的文件系统中;它在内核中并由系统中所有驻留的文件系统共享。从内核读取的任何内存都必须复制到用户空间:这就是你所读到的核心对核心移动。

除此之外,还有一些其他原因,你不能依赖系统缓冲池:

  1. 通常,DBMS非常了解其即将访问的模式,但无法将这些模式传达给内核。这可能会导致性能降低。
  2. 缓冲池通常存储在固定大小的内核内存范围中,因此无法增长或缩小。这也意味着缓存比主内存小得多,因此通过使用缓冲池,DBMS将无法利用系统资源。

哦,糟糕。我对替换策略感到兴奋,但你明确没有问那个。我会看看能否研究出更好的答案。 - Andres Jaan Tack

1

我知道这个问题很老,但它被列为未回答的问题。

基本上:

  1. 操作系统为每个进程使用单独的地址空间。
  2. 任何其他地址空间检索信息都需要进行系统调用或页面错误。**(见下文)
  3. DBMS是具有自己地址空间的进程。
  4. Stonebraker描述的操作系统缓冲池位于内核地址空间中。

所以...要将数据从内核地址空间传输到DBMS的地址空间,无法避免进行系统调用或页面错误。

您正确地指出,访问操作系统缓冲池管理器中的数据不比普通的read()调用更昂贵。(实际上,它是通过普通的read调用完成的。)然而,Stonebraker并没有谈论那个。他特别讨论了DBMS的缓存需求,在数据从磁盘读取并存在RAM中之后。

实际上,他的意思是操作系统的缓冲池缓存对于数据库管理系统来说太慢了,因为它存储在不同的地址空间中。他建议在同一进程(因此在相同的地址空间)中使用本地缓存,这可以为像重度命中缓存的DBMS应用程序提供显着的加速,因为它将消除系统调用开销。
以下是他讨论在同一进程中使用本地缓存的确切段落:
“然而,包括INGRES [20]和System R [4]在内的许多DBMS选择将DBMS管理的缓冲池放置在用户空间中以减少开销。因此,每个系统都费尽心思构建自己的缓冲池管理器以增强性能。”
他还在您引用的摘录中提到了多核问题。类似的效果也适用于这里,因为如果每个核心只有一个缓存,当多个CPU读写相同的数据时,您可能可以避免CPU缓存刷新带来的减速。

顺便提一句,我相信Stonebraker于1981年发表的那篇论文实际上是在mmap之前。他将它提及为未来工作:“将文件系统作为共享虚拟内存的一部分(例如Pilot[16])提供的趋势可能会为这个问题提供一个解决方案。”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接