Lecture #6: Buffer Pools
本文是对CMU15-445课程第5节笔记的一个粗略总结和翻译。仅供个人(M1kanN)复习使用。
1. Introduction
-
DBMS的任务是管理内存和从磁盘移入移出数据。由于在大多数情况下,数据不能直接在磁盘上操作,任何数据库都必须能够有效地将其磁盘上表示为文件的数据移动到内存中,以便能够使用。图1显示了这种互动的图示。
DBMS面临的一个障碍是如何将数据移动的速度降到最低。理想情况下,数据应该 "看起来 "是已经在内存中了。执行引擎不应该担心数据是如何被取到内存中的。
Figure 1: Disk-oriented DBMS -
另一种思考这个问题的方式是在空间和时间控制方面。
- 空间控制是指页面在磁盘上的物理写入位置。空间控制的目的是使经常一起使用的页面在磁盘上尽可能地靠近。空间控制的目标是使经常一起使用的页面在磁盘上尽可能地靠近。 spatial locality
- 时间控制是指何时将页面读入内存,何时将其写入磁盘。时间控制的目的是 尽量减少从磁盘上读取数据的停顿次数。 temporal locality
2. Locks vs. Latches
在讨论DBMS如何保护其内部元素时,我们需要对lock和latch进行区分。
- Locks:
Lock是更高层次的逻辑基元(logical primitive),它保护数据库的内容(如tuple,表,数据库)不受其他事务的影响(transactions)。事务将在整个持续时间内持有一个lock。数据库系统可以在运行查询时向用户展示哪些锁正在被用户持有。锁可以回滚变化。 - Latches:
锁存器是一个低级别的保护基元(protection primitive),DBMS在其内部数据结构(例如,哈希表、内存区域)的关键部分使用。锁存器只在所进行的操作的时间内保持。锁存器不需要能够回滚变化。
3. Buffer Pool
-
缓冲池是一个从磁盘上读取页面的内存缓存。它本质上是在数据库内部分配的一个大的内存区域,用来存储从磁盘获取的页面。
-
缓冲池的内存区域被组织成一个固定大小的页面阵列。每个数组条目被称为一个框架。
当DBMS请求一个页面时,一个精确的副本被放置到缓冲池的一个框架中。然后,当一个页面被请求时,数据库系统可以首先搜索缓冲池。如果没有找到该页,那么系统就会从磁盘上获取该页的副本。脏的页面会被缓冲,不会立即写回去。缓冲池的内存组织图见图2。
Figure 2: Buffer pool organization and meta-data
Buffer Pool Meta-data
-
缓冲池必须维持特定的元数据,以便有效和正确地使用。
-
首先,页表是一个内存中的哈希表,用于跟踪当前内存中的页面。它将页面ID映射到缓冲池中的框架位置。由于缓冲池中的页面顺序不一定反映磁盘上的顺序,这个额外的中介层允许识别缓冲池中的页面位置。
-
Note:
页面表(page table)不能与页面目录(page directory)相混淆,后者是从页面ID到数据库文件中的页面位置的映射。所有对页面目录的改变都必须记录在磁盘上,以允许DBMS在重启时发现。 -
页表还维护着每页的额外元数据,一个脏标志(dirty bit)和一个引脚/参考计数器(pin/reference counter)。
-
dirty bit:
每当一个线程修改一个页面时,就会设置dirty-flag。这表明存储管理程序必须将该页写回磁盘
-
pin/reference counter:
pin/reference计数器跟踪当前访问该页面的线程数量(无论是读取还是修改)。一个线程在访问该页之前,必须先递增该计数器。如果一个页面的计数大于零,那么存储管理器不允许将该页从内存中驱逐(evict)出去
-
Memory Allocation Policies
-
数据库中的内存是根据两个策略分配给缓冲池的
-
Global policies: 全局策略
全局策略处理DBMS应该做出的决定,以有利于正在执行的整个工作负载。
它考虑到所有活动的事务,以找到分配内存的最佳决策 -
Local policies: 局部策略
另一个选择是本地策略,它做出的决定将使单个查询或事务运行得更快,即使它对整个工作负载没有好处。本地策略将框架分配给特定的事务,而不考虑并发事务的行为。
Most systems use a combination of both global and local views
-
4. Buffer Pool Optimizations
有许多方法可以优化缓冲池,使其适应应用程序的工作负荷
Multiple Buffer Pools
- DBMS可以维持多个缓冲池用作不同的目的(比如:每个数据库一个缓冲池,每个页种类(per-page type)一个缓冲池)。 然后,每个缓冲池都能根据春初在里面的数据来分情况使用局部策略。这种方法可以帮助减少latch contention(锁存器的争用) 以及提高局部性。
- 将所需页面映射到缓冲池的两种方法是对象ID和散列法
- Object IDs:
对象ID涉及扩展记录标识(extending the record IDs),使其具有一个对象标识符(object identifier)。然后,通过对象标识符,可以维持一个从对象到特定缓冲池的映射关系。 - Hashing:
另一种方法是散列法,DBMS对页面ID进行散列以选择访问哪个缓冲池。
- Object IDs:
Pre-fetching
- DBMS也可以通过基于查询计划的预取页面来进行优化。然后,当第一组页面被处理时,第二组页面可以被预取到缓冲池中。这种方法是DBMS在连续访问许多页面时常用的。
Scan Sharing (Synchronized Scans)
-
查询游标可以重复使用从存储或操作者计算中获取的数据。
这允许多个查询附加到一个扫描表的游标上。如果一个查询开始扫描, 那么DBMS将把第二个查询的游标附加到现有的游标上。DBMS会跟踪第二个查询与第一个查询的连接位置,这样它就可以在到达数据结构的末端时完成扫描
Buffer Pool Bypass
- 顺序扫描操作者不会将获取的页面存储在缓冲池中以避免开销。 Instead, memory is local to the running query(就是说把内存当做运行查询的地方?) 如果操作者需要读取磁盘上连续的大序列页面,这种方法很有效。缓冲池旁路也可用于临时数据(排序、连接)。
5. OS Page Cache
- 大多数磁盘操作是通过操作系统的API进行的。除非被明确告知,操作系统会维护自己的文件系统缓存
- 大多数DBMS使用直接I/O来绕过操作系统的缓存,以避免页面的冗余拷贝和不得不管理不同的驱逐(evict)策略。
- Postgres是一个使用操作系统页面缓存的数据库系统的例子。
6. Buffer Replacement Policies
- 当DBMS需要释放一个框架来为一个新的页面腾出空间的时候,它必须决定从缓冲池驱逐(evict) 哪一个页面。
- 替换策略是DBMS实现的一种算法,当它需要空间时,决定将哪些页面从缓冲池中驱逐出去。
- 替换策略的实施目标是提高正确性、准确性、速度和元数据的开销。
Least Recently Used (LRU)
- 最近最少使用的替换策略保留了每个页面最后被访问的时间戳。
DBMS 挑选驱逐具有最早时间的页面。这个时间戳可以存储在一个单独的数据结构中,比如队列,以便进行排序。 通过减少驱逐时的排序时间来提高效率。
CLOCK
这个LRU感觉跟计组的思想是完全一模一样了。clock,buffer,LRU都跟计组中差不多
-
CLOCK策略是LRU的一个近似值,不需要每页有单独的时间戳。在CLOCK策略中,每个页面被赋予一个参考位。当一个页面被访问时,设置为1。
为了形象地说明这一点,可以用 "时钟指针 (clock hand)"将页面组织在一个圆形的缓冲区中。在清扫时检查一个页面的位是否被设置为1,如果是,则设置为0,如果不是,则驱逐它。通过这种方式,时钟指针在驱逐之间记住了位置。
Figure 3: Visualization of CLOCK replacement policy. Page 1 is referenced and set to 1. When the clock hand sweeps, it sets the reference bit for page 1 to 0 and evicts page 5.
Alternatives
-
LRU和CLOCK替换策略有很多问题。
-
LRU和CLOCK很容易受到顺序泛滥(sequential flooding)的影响。在这种情况下,缓冲池的内容会因为顺序扫描而被破坏。
由于顺序扫描会读取每一个页面,所以读取的页面的时间戳可能并不反映我们真正想要的页面。换句话说,最近使用的页面实际上是最不需要的页面。
-
-
有三种解决方案可以解决LRU和CLOCK策略的缺点。
- LRU-K
它跟踪最后K个引用的历史作为时间戳,并计算出后续访问的间隔。这个历史记录被用来预测一个页面下次被访问的时间。 - Localization per query
DBMS在每个交易/查询的基础上选择哪些页面要被驱逐。这使得每次查询对缓冲池的污染最小化。 - Priority Hints
优先级提示允许事务根据查询执行过程中每个页面的上下文,告诉缓冲池页面是否重要。
- LRU-K
Dirty Pages
- 有两种方法来处理有脏位的页面。最快的方法是丢弃缓冲池中任何不脏的页面。一个较慢的方法是将脏页写回磁盘,以确保其变化被持久化。
- 这两种方法说明了快速驱逐与脏写页(dirty writing pages)之间的权衡,脏写页(dirty writing pages)在未来不会被再次读取。
- 避免不必要地写出页的问题的一个方法是后台写入。
通过后台写入,DBMS可以周期性地走过页表并将脏页写入磁盘。当一个脏页被安全地写入时,DBMS可以驱逐该页或者直接取消脏页标志。
7. Other Memory Pools
- 除了tuples和索引之外,DBMS还需要内存。
这些其他的内存池可能并不总是由磁盘支持,这取决于实现。- Sorting + Join Buffers
- Query Caches
- Maintenance Buffers
- Log Buffers
- Dictionary Caches