PostgreSQL shared buffers
  IE5LYMWlmdvL 2023年11月02日 63 0

简介

shared buffers是数据库内存共享缓冲区。

当Postgres想要从磁盘获取数据(page)时,先搜索shared_buffers,确认该page是否在shared_buffers中,如果存在,则直接命中,返回缓存的数据以避免I/O。如果不存在,再到OS缓存查找,最后才会通过I/O访问disk获取数据。

结构

PostgreSQL 缓存管理器分成三层结构:缓冲表(buffer table)、缓冲区描述符(buffer descriptors)和缓冲池(buffer pool)

PostgreSQL shared buffers_shared buffers

buffer table - 缓冲表

是一个哈希表,它存储着页面的buffer_tag与描述符的buffer_id之间的映射关系。

例如数据项Tag_A,id=2 表示,buffer_id=2对应的缓冲区描述符中,存储着页面Tag_A的元数据。

PostgreSQL中的每个数据文件页面都可以分配到唯一的标签,即缓冲区标签(buffer tag)。 当缓冲区管理器收到请求时,PostgreSQL会用到目标页面的缓冲区标签。

缓冲区标签(buffer_tag) 由三个值组成:关系文件节点(relfilenode)关系分支编号(fork number)页面块号(block number)

例如,缓冲区标签{(16821, 16384, 37721), 0, 7}表示,在oid=16821的表空间中的oid=16384的数据库中的oid=37721的表的0号分支(关系本体)的第七号页面。再比如缓冲区标签{(16821, 16384, 37721), 1, 3}表示该表空闲空间映射文件的三号页面。

buffer descriptors - 缓冲区描述符

是一个由缓冲区描述符组成的数组。

缓冲区描述符保存着页面的元数据,这些与缓冲区描述符相对应的页面保存在缓冲池槽中

buffer pool - 缓冲池

缓冲池只是一个用于存储关系数据文件(例如表或索引)页面的简单数组。缓冲池数组的序号索引也就是buffer_id

缓冲池槽的大小为8KB,等于页面大小,因而每个槽都能存储整个页面。

  • BufMappingLock:用于保护整个缓冲表的数据完整性。
    在缓冲表中查询条目时,后端进程会持有共享的BufMappingLock。插入或删除条目时,后端进程会持有独占的BufMappingLock
  • content_lock - 内容锁:是一种强制限制访问的锁
  • io_in_progress_lock - IO进行锁
    io_in_progress_lock用于等待缓冲区上的I/O完成。当PostgreSQL进程加载/写入页面数据时,该进程在访问页面期间,持有对应描述符上独占的io_in_progres_lock
  • spin lock - 自旋锁
    当检查或更改标记字段与其他字段时(例如refcountusage_count),会用到自旋锁。
  • refcount:保存当前访问相应页面的PostgreSQL进程数,也被称为钉数(pin count)
  • usage_count:保存着相应页面加载至相应缓冲池槽后的访问次数。(时钟扫描会用到)

页面替换算法

当所有缓冲池槽位都被占用,且其中未包含所请求的页面时,缓冲区管理器必须在缓冲池中选择一个页面逐出,用于放置被请求的页面。 在计算机科学领域中,选择页面的算法通常被称为页面置换算法(page replacement algorithms),而所选择的页面被称为受害者页面(victim page)

PostgreSQL使用**时钟扫描(clock-sweep)**算法

PostgreSQL shared buffers_缓冲池_02

  1. nextVictimBuffer指向第一个描述符(buffer_id = 1);但因为该描述符被钉住了,所以跳过。
  2. nextVictimBuffer指向第二个描述符(buffer_id = 2)。该描述符未被钉住,但其usage_count为2;因此该描述符的usage_count将减1,而nextVictimBuffer迭代至第三个候选描述符。
  3. nextVictimBuffer指向第三个描述符(buffer_id = 3)。该描述符未被钉住,但其usage_count = 0,因而成为本轮的受害者。

nextVictimBuffer扫过未固定的描述符时,其usage_count会减1。因此只要缓冲池中存在未固定的描述符,该算法总能在旋转若干次nextVictimBuffer后,找到一个usage_count为0的受害者。

环形缓冲区 - ring buffer

在读写大表时,PostgreSQL会使用环形缓冲区(ring buffer)。是一个临时缓冲区,在使用后被立即释放

PostgreSQL在共享内存中分配一个环形缓冲区的条件:

  • 批量读取
    当扫描关系读取数据的大小超过缓冲池的四分之一(shared_buffers/4)时,在这种情况下,环形缓冲区的大小为_256 KB_。
  • 批量写入
    当执行下列SQL命令时,这种情况下,环形缓冲区大小为_16 MB_。
  • 清理过程
    当自动清理守护进程执行清理过程时,这种情况环形缓冲区大小为256 KB。

详情参考 https://www.interdb.jp/pg/pgsql08.html

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  IE5LYMWlmdvL   2023年11月13日   28   0   0 postgresql
IE5LYMWlmdvL