Skip to content

5. Memory Management

约 1230 个字 预计阅读时间 6 分钟

Introduction

DBMS 负责管理内存,并从磁盘中来回移动数据。在大多数情况下,数据不能直接在磁盘中操作,数据库系统需要有效地将磁盘中的数据移动到内存中。

DBMS 面临的一个障碍是尽可能减少移动数据速度的影响,在理想情况下,数据"看起来"好像全部在内存中,Execution Engine 不需要担心数据如何移动到内存中。

考虑该问题的角度分为 Spatial 和 Temporal:

  • Spatial Control: 考虑 Pages 在磁盘上的物理位置
    • 目标是使经常一起使用的 Pages 在磁盘上尽可能靠近
  • Temporal Control: 考虑什么时候读取 Pages 到内存中,什么时候将 Pages 写回磁盘
    • 目标是尽可能减少读取数据造成的 Stalls

Buffer Pool

缓冲池是从磁盘读取 Pages 的 in-memory cache,它本质是数据库内部分配的一个大型内存区域,用于存储从磁盘获取的 Pages。

缓冲池被划分组织为固定大小的 Pages 数组,每一个数组项被称为 Frame。数据库请求页面时,会先扫描一遍缓冲池,如果未能找到该 Page,则从磁盘中将其副本加载进 Frame 中。

缓冲池必须维护一些元数据才能被高效、正确地使用。

Page Table 是位于内存中的一个哈希表,用于跟踪当前处于内存中的 Page,它将 Page ID 映射到缓冲池中对应的帧位置。

区分 Page Directory: 从 Page ID 映射到 File 内 Page 位置

Page Table 还需要维护每个 Page 的额外元数据、Dirty Flag、pin/reference counter等。

每当线程修改 Page,其 Dirty Flag 都会被该线程重新设置。pin/reference counter 跟踪当前正在访问该 Page 的线程数,线程在访问 Page 时必须先递增计数器。

如果计数器大于 0,则不允许 Storage Manager 从内存中移除该 Page

数据库中的内存根据两个策略分配给缓冲池:

  • Global Policies: 全局策略要求 DBMS 作出能够使正在执行的全部工作负载整体受益的决策,它考虑所有活动事务以找到分配内存的最佳决策。
  • Local Policies: 局部策略使得单个查询运行得更快,并且有可能不利于全局最优实现。本地策略会将 Frame 分配给一些特定的事务,而不考虑并发行为。

大多数系统同时采用全局策略和局部策略。

OS Page Cache

大多数对磁盘操作需要用 OS 的 API 进行,这将产生 OS 自己的 filesystem cache。而 DBMS 一般需要使用直接 I/O 操作来绕过操作系统的缓存,以避免 Page 的冗余副本和额外的驱逐策略。

Buffer Pool Optimizations

有多种方法可以优化缓冲池,使其适应应用程序的工作负载。

Multiple Buffer Pool

DBMS 可以维护多个缓冲池用于不同目的,每个缓冲池都可以采用为其内部存储数据量身定做的本地策略。这种方式可以减少 Latch 争用以及改善局部性(Locality)。

我们可以通过额外维护一个 Object ID 或者直接使用哈希表来选择某一 Page 要访问的缓冲池。

Pre-fetching

DBMS 可以根据查询计划预取 Page 来进行优化。然后,在处理第一组 Pages 时,预先将第二组 Pages 取到缓冲池中。

DBMS 在顺序访问多个 Pages 时经常使用此方法

Scan Sharing (Synchronized Scan)

允许多个查询共用一个查询游标。如果查询扫描启动时,已经有别的扫描在进行中,则可以将第二个查询游标附加到现有游标上,以节省扫描成本。

Buffer Pool Bypass

The sequential scan operator will not store fetched pages in the buffer pool to avoid overhead.

  • Memory is local to running query
  • Works well if operator needs to read a large sequence of pages that are contiguous on disk
  • Can also be used for temporary data (sorting, jsons, ...)

Buffer Replacement Policies

当 DBMS 需要释放一个 Frame 来为 Page 腾出空间,它必须决定从缓冲池中驱逐哪个 Page。

  • LRU
    • 维护上一次访问的时间戳,驱逐时间戳最早的 Page
  • CLOCK
    • LRU 的变种,不再需要维护时间戳,改为一个 Reference Bit。
    • 访问时设置 Reference Bit 为 1。当需要驱逐 Page 时,循环访问 Buffer,如果当前游标指向的 Page 的 Ref 为 1,则将其设置为 0,游标移动;否则,驱逐它
  • Dirty Pages
    • 处理带 Dirty Bit 的 Page 有两个方法,较快的方法是删除缓冲池中所有非脏页面,另一个是将脏页面写回磁盘,以确保更改持久化保存
    • 避免不必要写回的一种方法是 background writing。DBMS 定期遍历 Page Table 并将脏页面写回磁盘
Comments: