• CMU15-445 数据库系统播客:数据库系统的内存管理与缓冲池

CMU15-445 数据库系统播客:数据库系统的内存管理与缓冲池

2025-08-16 12:32:53 栏目:宝塔面板 0 阅读

本次课堂讨论的核心是如何在数据库管理系统(DBMS)中有效地管理内存,特别是如何将磁盘上的数据页(pages)引入内存以便操作,并使其在用户看来所有数据都如同在内存中一样。DBMS 自己管理内存优于操作系统(OS)管理的原因在于,DBMS 拥有关于查询计划和数据访问模式的 语义知识 ,这使得它能够做出更优化的决策,从而最大限度地减少从磁盘读取数据导致的停顿。

缓冲池(Buffer Pool)与帧(Frame)

  • 帧(Frame)的定义 :  是缓冲池内固定大小的内存块。当 DBMS 需要一个数据页时,它会将该页的精确副本放入缓冲池中的一个帧内。
  • DBMS 为何要自己管理帧/内存 : DBMS 会自行分配一大块内存区域作为 缓冲池 ,并完全由数据库系统管理这块内存,而不是依赖于操作系统进行细粒度的内存管理。主要原因是:

超越内存容量的数据库 :DBMS 能够支持数据库大小远超过物理内存的情况。

最小化磁盘 I/O 影响 :通过精心管理内存,DBMS 可以最大限度地减少因从磁盘读取数据而导致的查询停顿或问题。

空间与时间控制 :DBMS 不仅关注数据在磁盘上的物理位置( 空间控制 ),还关注何时将数据页读入内存以及何时将其写回磁盘( 时间控制 )。操作系统无法理解数据页的上下文和查询意图,而 DBMS 可以利用这些信息进行优化。

缓冲池元数据(Meta-data)

缓冲池管理器会维护一些额外的元数据来跟踪当前在内存中的页面状态:

  • 页面表(Page Table) :这是一个 哈希表 ,用于跟踪当前在内存中的页面。它将页面 ID 映射到缓冲池中对应的 帧 ID 或内存地址。页面表是临时的内存结构,不需要持久化到磁盘。
  • 脏页标志(Dirty Flag) :这是一个 单比特标志 ,指示自页面从磁盘读入缓冲池以来是否已被修改。如果页面被修改,它必须在被驱逐回磁盘前安全地写回。
  • 引用计数(Pin Count / Reference Counter) :这个计数器跟踪当前有多少个线程或查询正在使用(读取或修改)该页面。如果一个页面的引用计数大于零,则缓冲池管理器 不允许 将其从内存中驱逐出去。

并发控制:锁(Locks)与栓锁(Latches)

理解锁和栓锁的区别对于并发控制至关重要。

  • 锁(Locks)

保护对象 :保护数据库的 逻辑内容 ,如元组(tuples)、表(tables)、整个数据库。

持有时间 :通常由事务持有,持续整个事务的执行期间,可能长达数毫秒、数秒,甚至数分钟或数小时。

回滚需求 :需要支持 回滚 操作,以防事务失败。

  • 栓锁(Latches)

保护对象 :保护 DBMS 内部数据结构的 关键区域 ,例如缓冲池中的页面表条目或物理数据结构。

持有时间 :持有时间极短,仅限于单个操作的持续时间。一旦操作完成,栓锁就会立即释放。

回滚需求 :通常 不需要 回滚,因为它们是用于保护内部物理数据结构,而非逻辑数据。

实现 :在操作系统层面,栓锁通常通过 互斥量(mutexes) 实现。

缓冲池优化手段

为了提高性能,DBMS 采用多种优化策略:

  • 多缓冲池(Multiple Buffer Pools) DBMS 可以拥有多个缓冲池实例,而不是一个单一的全局缓冲池。这样做有几个好处:

减少栓锁竞争 :不同的线程可以访问不同的缓冲池,减少了对单一页面表栓锁的争用,从而提高并发性能和可伸缩性。

改善局部性 :可以针对不同类型的数据(例如,为索引单独设置一个缓冲池,为表数据设置另一个)或访问模式(例如,点查询与顺序扫描)定制不同的 替换策略 。

  • 预取(Pre-fetching) : DBMS 可以根据查询计划 预先读取 页面,将它们从磁盘加载到缓冲池中。这可以减少查询因等待磁盘 I/O 而导致的停顿。

顺序扫描 :对于顺序扫描,DBMS 可以轻松预测接下来将访问的页面。

索引扫描 :对于索引扫描,DBMS 能够理解索引结构(例如 B+ 树)并提前预测需要跳跃读取哪些非连续的页面,这是操作系统无法做到的。

  • 扫描共享(Scan Sharing) :多个查询可以 共享 同一个数据扫描游标,从而复用从磁盘读取的数据页。

这与 结果缓存 (result caching,缓存查询结果)不同,扫描共享发生在更低的存储层级。

查询不一定需要完全相同,只要它们扫描相同的页面,就可以共享。

这种技术可以有效避免 颠簸(thrashing) ,即因一个查询驱逐了另一个查询很快又需要的页面而导致反复的磁盘 I/O。

例如,DB2 和 SQL Server 完全支持此功能,而 Oracle 的游标共享(cursor sharing)只对完全相同的查询有效。

  • 缓冲池旁路(Buffer Pool Bypass) :某些查询操作(特别是顺序扫描)可以选择 不将读取的页面放入主缓冲池 ,而是将它们放入一个 查询本地的临时内存区域 。

这有助于避免 污染(pollute) 缓冲池中的“热点”数据,即那些可能在短期内不再需要的页面。

适用于需要读取大量连续页面或处理临时数据(如排序、连接)的操作。

减少了查询页面表和获取栓锁的开销。

页面替换策略(Replacement Policies)

当缓冲池满且需要为新页面腾出空间时,DBMS 必须决定驱逐哪个页面。目标是正确性、准确性、速度和元数据开销。

  • 最近最少使用(Least Recently Used, LRU)

跟踪每个页面最后一次访问的时间戳,驱逐时间戳最老的页面。

可以通过维护一个按时间戳排序的队列来加速查找。

  • Clock 算法

LRU 的一种 近似算法 ,不需要为每个页面精确跟踪时间戳。

每个页面有一个 引用位(reference bit) 。当页面被访问时,其引用位设为 1。

页面被组织成一个 环形缓冲区 ,有一个“时钟指针”扫过这些页面。

当指针扫到一个页面时:如果引用位为 1,则将其设为 0 并跳过;如果引用位为 0,则说明该页面自上次检查以来未被访问,可以被驱逐。

  • 顺序洪泛(Sequential Flooding)问题 : LRU 和 Clock 算法都容易受到 顺序洪泛 的影响。当一个查询执行顺序扫描并读取大量页面时,这些页面都会被标记为“最近使用”,从而导致缓冲池中真正有用的(但暂时未被访问的)热点页面被驱逐出去。
  • 更优的替换策略

LRU-K :跟踪页面过去 K 次 访问的历史时间戳,并计算访问间隔,以更好地预测页面下次被访问的时间。这使得驱逐决策更准确。

本地化(Localization) :DBMS 可以根据每个事务或查询的访问模式来决定驱逐哪些页面,从而减少对全局缓冲池的污染。例如,Postgres 维护一个小的 环形缓冲区 作为查询的私有缓存。

优先级提示(Priority Hints) :DBMS 利用其对查询执行上下文的了解,向缓冲池提供提示,指出哪些页面是重要的(例如,索引的根页、频繁写入的页),应尽量保留在内存中。

脏页(Dirty Pages)处理与后台写入

  • 脏页处理

如果缓冲池中的页面 未被修改 (干净页),DBMS 可以直接“丢弃”它,并将其帧用于新页面,这是 最快 的。

如果页面 已修改 (脏页),则在驱逐之前,必须将其安全地写回磁盘以确保数据持久性,这会比较  ,因为它涉及到额外的磁盘 I/O。

替换策略需要在“快速驱逐干净页”和“支付写入脏页的成本以保留未来可能需要的干净页”之间做出权衡。

  • 后台写入(Background Writing)

为了避免在需要空闲空间时才被迫写入脏页,DBMS 可以定期运行一个后台线程,扫描缓冲池并主动将脏页写入磁盘。一旦脏页安全写入,就可以将其标记为干净,从而在需要驱逐时有更多干净的页面可供选择。

重要限制 :后台写入必须确保在写入脏页之前,与该修改相关的 日志记录 已经安全地写入了磁盘。这是为了确保崩溃恢复时的正确性。

PostgresQL 与操作系统页面缓存的利用

  • 操作系统页面缓存(OS Page Cache) :默认情况下,操作系统会维护自己的文件系统缓存(OS Page Cache)。当程序从磁盘读取文件时,OS 会在自己的缓存中保留一份副本。
  • 大多数 DBMS 的做法

大多数主流的数据库系统(如 Oracle, MySQL, SQL Server, DB2, Sybase)都会使用 O_DIRECT(Direct I/O)等 POSIX 标志, 绕过 操作系统的页面缓存。它们自己管理所有的内存和缓存。

避免 冗余数据副本 (数据在 OS 缓存和 DBMS 缓冲池中都有),节省内存。

确保 一致的性能 和行为,因为不同操作系统的缓存策略可能不同。

对 写入操作有完全控制 ,确保数据以正确的顺序持久化(如先写日志再写数据),OS 的缓存可能无法提供这种保证。

  • PostgresQL 的做法

Postgres 是一个显著的例外,它是少数 依赖于 操作系统页面缓存的主流数据库系统。

Postgres 的开发者认为这可以减少 工程开销 ,因为他们不需要像其他 DBMS 那样管理一个巨大的缓冲池,可以将部分缓存管理的工作交给 OS。

虽然会带来一些细微的性能损失,但他们认为是可以接受的。

在演示中,即使重启 Postgres 清空了其自身的缓冲池,但如果 OS 页面缓存中仍有数据,查询执行时间仍然会比完全从磁盘读取快得多,这证明了 OS 页面缓存对 Postgres 的性能影响。然而,为了达到最佳性能(如 700 毫秒),仍然需要将整个表(345MB)加载到 Postgres 自身的共享缓冲区(shared buffers,Postgres 的缓冲池)中(从 128MB 增加到 360MB),并执行预热操作(PG Warm 扩展),才能实现几乎 100% 的缓存命中。

本文地址:https://www.yitenyun.com/329.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 Deepseek 宝塔面板 Linux宝塔 Docker 生命周期 JumpServer JumpServer安装 堡垒机安装 Linux安装JumpServer 序列 核心机制 esxi esxi6 root密码不对 无法登录 web无法登录 SSL 堡垒机 跳板机 HTTPS Windows Windows server net3.5 .NET 安装出错 宝塔面板打不开 宝塔面板无法访问 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 连接控制 机制 HTTPS加密 Windows宝塔 Mysql重置密码 无法访问宝塔面板 HexHub 运维 Oracle 处理机制 Serverless 无服务器 语言 Spring Redis 异步化 ES 协同 技术 group by 索引 InnoDB 数据库锁 监控 开源 PostgreSQL 存储引擎 分页查询 高可用 SQL 动态查询 响应模型 缓存方案 缓存架构 缓存穿透 R edis 线程 数据 主库 自定义序列化 服务器 管理口 scp Linux的scp怎么用 scp上传 scp下载 scp命令 日志文件 MIXED 3 查询 SVM Embedding 存储 OB 单机版 Linux 安全 工具 电商 系统 SQLark SQLite-Web SQLite 数据库管理工具 架构 Rsync Postgres OTel Iceberg RocketMQ 长轮询 配置 Recursive 云原生 流量 共享锁 修改DNS Centos7如何修改DNS • 索引 • 数据库 防火墙 黑客 向量数据库 大模型 聚簇 非聚簇 sftp 服务器 参数 PG DBA 缓存 业务 AI 助手 Ftp ​Redis 机器学习 推荐模型 场景 GreatSQL 连接数 优化 万能公式 Netstat Linux 服务器 端口 数据备份 MySQL 9.3 RDB AOF openHalo 数据分类 加密 同城 双活 信息化 智能运维 INSERT COMPACT 窗口 函数 人工智能 推荐系统 核心架构 订阅机制 事务 Java 开发 MVCC 磁盘架构 线上 库存 预扣 redo log 重做日志 mini-redis INCR指令 网络架构 网络配置 Doris SeaTunnel prometheus Alert Redisson 锁芯 向量库 Milvus Undo Log 高效统计 今天这篇文章就跟大家 Python 引擎 性能 网络故障 B+Tree ID 字段 模型 IT运维 Canal Web PostGIS Redis 8.0 不宕机 数据脱敏 加密算法 R2DBC Hash 字段 分布式 集中式 崖山 新版本 自动重启 Pottery OAuth2 Token JOIN Entity ZODB 微软 SQL Server AI功能 容器化 虚拟服务器 虚拟机 内存 MongoDB 数据结构 DBMS 管理系统 容器 数据类型 读写 sqlmock 启动故障 悲观锁 乐观锁 分库 分表 LRU SpringAI 数据页 StarRocks 数据仓库 数据集成工具 分页 单点故障 QPS 高并发 传统数据库 向量化 工具链 Testcloud 云端自动化 Redka filelock 排行榜 排序 发件箱模式 事务隔离 部署 聚簇索引 非聚簇索引 分页方案 排版 大表 业务场景 意向锁 记录锁 速度 服务器中毒 Web 接口 1 SSH 池化技术 连接池 Caffeine CP 仪表盘 分布式架构 分布式锁​ dbt 数据转换工具 日志 原子性 EasyExcel MySQL8 AIOPS MCP 开放协议 优化器 网络 InfluxDB Order IT 双引擎 RAG HelixDB 频繁 Codis Go 数据库迁移 字典 单线程 Ansible 对象 Crash 代码 LLM 事务同步 订单 线程安全 Pump List 类型 UUIDv7 主键 锁机制 语句 服务器性能 TIME_WAIT 负载均衡 播客 行业 趋势 技巧 Weaviate MGR 分布式集群 分布式锁 Zookeeper 解锁 调优 并发控制 恢复机制 ReadView 国产数据库 闪回 产业链 兼容性 Next-Key 国产 用户 快照读 当前读 视图 RR 互联网 关系数据库 编程 数据字典 算法 主从复制 代理 GitHub Git count(*) count(主键) 行数 UUID ID 神经系统 慢SQL优化 千万级 表空间 拦截器 动态代理 Valkey Valkey8.0 矢量存储 数据库类型 AI代理 查询规划 恢复数据 CAS 失效 多线程