您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
Postgres数据库缓存的深度指南
 
来源:极客头条 作者: Madusudanan.B.N 发布于 2016-7-27
   次浏览      
 

缓存

缓存对于数据库的系统性能有着重要意义。

本文虽以Postgres为例,但也可对应到其他数据库系统。

一、高速缓冲存储器是什么以及为什么需要它

不同的计算机部件有着不同的运行速度。人类在理解数字的规模上面,与计算机有着极大的差距。

对此,通过下面这张表格(截取自《文字间的无限空间》The Infinite Space Between Words),会有一个更直观的认识。

表中数据是从人类角度加以估算。

在数据库系统中,技术人员最关注的往往是硬盘的I/O问题。

与新的固态硬盘(SSD)相比,磁盘在随机I/O方面的性能较差。

大多数OLTP的工作负载都属于随机I/O,因此获取硬盘中信息时,速度就会极其缓慢。

为了克服这一劣势,Postgres利用随机存取存储器(RAM)来缓存数据,而这极大地提高了性能。即使对比SSD,RAM速度上也要快上很多。

上面是缓存处理器(cache)的普适原则,几乎适用于所有的数据库系统。

二、理解术语

在进一步拓展知识之前,先了解一些特定术语。

首先,可借助一篇优秀的文章展开阅读。

每当你读完一篇的时候,就接着换一篇难度更深一点的文章继续。这个过程中,要特别留意有关堆内存元组的部分。

另外,还可以看相关的官方文档,但这类相对难理解些。

不管内容是什么,Postgres都有一个抽象化存储,即计算机编程语言脚本(page,8kb)。

下幅图给出了一个简要介绍。

这一抽象概念是下文里将要重点解决的问题。

三、缓存的对象

Postgre缓存的内容如下:

表格数据

指表格的具体内容。

索引

索引亦存储至8k大小的块,即和表格数据存储位置一致,接着看下面的存储区域。

查询执行计划

看一条查询执行计划时,有一个计划阶段,主要用来挑选最适用于查询的计划。Postgres还可以储存这个计划,而这基于的是每一次会话,而一旦会话结束,存储的计划就会被删除。这导致其优化、分析变得棘手了起来,但从总体上来看这一点不是那么重要,除非处于执行中的查询非常复杂,并且/包含大量重复查询。

文档从细节着手对这些内容做出了很好的解释。我们可以通过查询pg_prepared_statements来找出缓存了哪些东西。这里要注意的是,在结束的会话间无法获取缓存,有且仅对正在进行的会话可见。

下文将进一步研究表格数据和索引缓存的细节问题。

四、内存区

Postgres具有多个配置参数,则需要理解参数指代的含义。

对于缓存来说,最重要的配置当属shared_buffers。这在Postgres源代码内部,又称为NBuffers,用以存储共享数据至内存。

Shared_buffers也仅仅是由8kb大小的块所形成的数组。每个脚本内部都包含元数据,如前所言,在此处起到区分的作用。Progres在查看硬盘数据之前,会先查找shared_buffers内的脚本,若此处有hit参与,则其将在这一环节返回数据,从而避免硬盘的I/O问题。

五、LRU/Clock清理缓存算法

关于存储器内数据的缓存和清理的装置,受控制于Clock清理缓存算法。

因其被用以处理OLTP工作负载,故而几乎所有的信息传输都是在内存下进行的。
下面从细节处谈一谈每一项操作。

缓冲区分配

Postgres是一个基于过程的系统,换言之,每一次连接自身都含有一个本地操作系统进程,这源于Postgres的root进程(原称postmaster)。

若一个进程要求一个LRU高速缓冲存储器下的脚本(一旦该脚本经过一个经典的SQL查询而获得,则进程结束),它要求在缓冲区分配。若block已存于高速缓冲存储器,则其将被锁定并返回。而这个锁定过程也将提升下面将要讨论到的使用计数。而如果使用计数显示为0,则脚本将被解除锁定。

只有当所有缓冲区或slots都包含一个脚本之后,才会进行到缓存区清理环节。

缓存区清理

计算机学科学的一个经典问题就是确定哪些脚本应当从内存中删除,并写入硬盘。

由于对之前的运行没有记录,简单一个LRU(Least Recently Used,最近不常使用算法)在实际中很难很好地工作。

而Postgres保存了脚本使用计数的运行轨迹,因此如果一个脚本的使用计数是0,则其将从内存中被删除并写入硬盘。此外,在遇到脏页的情况下,也将被写入硬盘(详情见下文)。

暂且抛下具体细节不看的话,缓存算法本身几乎不需要调整,而且其智能程度远超于人的想象。

六、脏页和高速缓冲存储器失效

一直到这里我们都在讨论选择查询的问题,那DML查询呢?简单来说,二者写入相同的脚本。若为内存,则直接写入,否则先从内存中提取出来再写入。

这就是产生“脏页”这个概念的环节,也就是说,一个脚本已被修改还未写入硬盘的情况。
在我们继续之前,还有许多功课和研究要做,这里特别强调关于WAL日志和内部事件(checkpoints)。

WAL是一个重做日志,主要用以保存系统内部发生一切的轨迹。这是通过将所有的变化分别录入一个WAL日志来实现。Checkpointer就是一个在一个time setting的控制下,定时将所谓的脏页写入磁盘的进程。之所以如此操作,是因为考虑到数据库崩溃时从头开始重复所有操作的需要。

这是从内存中删除脚本最常见的方法,而在经典案例中LRU算法清理几乎没有出现过。

七、理解高速缓冲存储器(cache)

Explain是理解计算机内部正在进行写什么的好方法。这个方法甚至能够告诉你有多少数据块是来自磁盘的,又有多少是来自shared_buffers,即内存的。

例如下面这个查询计划:

共享读取指的是其取自磁盘且不被缓存。若该查询再次运行,且缓存配置正确的话(我们将在下面讨论),其将以共享hit的形式呈现。

通过这个方法,很容易从查询的角度来获知缓存的量,而无需通过OS/Postgres的Internals来完成。

八、全面扫描案例

全面扫描,在没有索引且Postgres必须从磁盘中提取所有数据的情况下,对于这类高速缓冲存储器来说归属问题区域。

由于单次扫描能清楚存储器内的所有数据,故而其操作方法有所不同。它选用一组共计256K.B大小的缓冲区,而非常规的LRU/Clock清理缓存算法。下面的查询展示了它的操作方法。

再次执行上述查询。

从中我们可以清楚地看到32个块清楚地转入了内存,即32*8= 256 KB。这在src、backend、storage、buffer和README中都有所说明/解释/体现。

九、内存流和OS缓存

Postgres是一个跨平台数据库,其缓存很大程度上依赖于操作系统。

实际上shared_buffers是在复制OS的操作。下面给出一张典型的数据在Postgres内部的流向图。

起初的确令人困惑,由于缓存是由OS和Postgres二者同时管理的,但这样操作也是有原因的。

谈及操作系统,高速缓冲存储器则需要一个独立的post,网上也有很多可供利用的资源。

要记住OS缓存数据是处于和上面提到的一样的原因,即为什么我们需要一个高速缓冲存储器那一部分内容。

我们可以把I/O分为两类,即读和写。简言之,数据从磁盘流入内存叫做读;数据由内存流入磁盘称为写。

参考上面的流程图,可以发现写指的是数据从磁盘到OS存储器再到shared_buffers的转移过程。

有时,OS存储器和shared_buffers可以控制相同的脚本,而这可能导致空间浪费,但这里要记住,OS存储器所用的是简单的LRU算法而非数据库优化的clock sweep。一旦脚本页的共享缓冲功能减弱,OS存储器内则无法读取,且若有备份,也很容易被删除。

在实际情况下,并不存在太多被同时储存于各内存区域的脚本页。这也是建议仔细规划shared_buffers大小的原因之一。过分硬性的规定将有损其性能,例如让其承载最大份额的内存或是给其分配的过少。

针对其优化问题,下文将详解。

写是由内存到磁盘的数据转移。这个环节正是脏页产生之处。一个脚本一旦被标记为脏页,则将被传输至OS存储器,随后则被写入磁盘。在这个环节,OS在输入通信量的基础上享有更大的调度输入输出的自由。

如上文所说,若OS存储器容量较小,则其不能对写入进行重新排序,也不能对输入输出进行优化。而这对于高工作负载的写来说是非常重要的。因此,OS存储器的大小也很重要。

十、初始配置

对于很多数据库系统来说,并不存在直接适用的万能配置。配有基础配置的PostgreSQL ships经过优化增强了其兼容性而非性能。

依据应用程序、工作负载来优化配置,是数据库管理员、开发者的责任。然而Postgres有一个很好的文档用以指示从何处开始。

一旦确立了默认、启动配置,即可通过负载、性能测试查看其操作情况。

要记住对初始配置的调整是为了更好的获取而不是性能的提高。通常情况下,最好能检测并选择更适宜其工作负载的配置。

十一、随时优化

对于不可检测的东西,自然也无法优化。

有了postgres,就有了两种可供检测的方法。

操作系统

对于在哪个平台上Postgres可以最好地工作这个问题的答案,并未得到普遍的共识,所以此处假设适用的是Linux家庭版操作系统。但这个想法类似。

首先,有一个叫做Io top的工具,可以用它来检测磁盘的输入输出。和top相似的是,它在检测磁盘输入输出时迟早会派上用场。这是只需要运行iotop指令来检测读取、写入。

上图清楚地展示了在负载下Postgres是如何运行的,即哪些是针对磁盘的,又有哪些是来自RAM的,这些数据可通过产生的负载来获取。

直接来自Postgres

通常情况下,最好监测直接来源于Postgres的数据,而不是经历了OS路径传输的数据。

此外,通常只有在确认Postgres本身存在错误的条件下,才会执行OS层面的监测,但这种情况一般不常见。

伴随Postgres,有一些可供支配的工具,可以用来检测内存的性能。

Explain

默认是SQL explain。它能给出比其它数据库系统要更多的信息,但在理解上的难度也要相对高一些。故而需要通过练习来加以熟悉。不要错过那几个有用的flags,因为如前所见,他们将被特别缓存。

进入下面的链接来深入了解explain的相关内容:

更多explain详情关注网站 postgresguide.com
Explain visualizer

查询日志

查询日志是用以了解系统内部所发生的事件的另一途径。

我们无需事无巨细地全部记录,只需要记录特定时间间隔间的查询,或者运用log_min_duration_statement参数以采用慢速查询日志。

自动explain

这也可以帮助你利用慢速查询自动记录执行计划。它能够让你在无需手动运行explain的情况下进行调试。

Pg统计报表

上面提到的方案都很好,但是缺乏巩固的理念。

这是Postgres内部建立的模块,但是在默认情况下会产生缺陷。

可以通过创造extension pg_stat_statements来使之工作。

一旦其开始运行,经过一定量的查询之后,即可以展开如下查询。

给出大量查询所消耗的时长及其平均值的细节信息。

这个方法的缺陷在于它消耗了部分性能,故而在生产系统中不常推荐这个方法。

PG Buffer存储器和PG fincore

如果想要获得更深入的了解,还有两个可以直接深入shared_buffers和OS 存储器内部的模块。

值得注意的是,explain(analyze,buffers)只显示出自shared_buffers的工具,不包括出自OS存储器的。

PG缓冲存储器

这帮助我们实时掌握共享缓冲区内的数据。收集来自shared_buffers的数据,并存至pg_buffercache内部方便查看。

下面给出一个查询样例,它列出了前一百的表格和存储的脚本的数量。

这是一个外部模块,负责提供OS如何存储脚本的信息。这一层级较低且影响力较强。
Pg预加载模块(数据缓存预加载模块)

这是一个内置模块,它确实能够负载数据到shared_buffers或OS存储器或为二者共有。如果觉得内存预热是个问题的话,便可以借此来进行很好的调试。

虽然还有其它可以用以了解Postgres存储器的方法,但我这里已经列出了最为普遍以及最为便于使用的几项了。有了这些工具,就不会再出现由于内存问题导致的数据库运行缓慢。

 

   
次浏览       
相关文章

基于EA的数据库建模
数据流建模(EA指南)
“数据湖”:概念、特征、架构与案例
在线商城数据库系统设计 思路+效果
 
相关文档

Greenplum数据库基础培训
MySQL5.1性能优化方案
某电商数据中台架构实践
MySQL高扩展架构设计
相关课程

数据治理、数据架构及数据标准
MongoDB实战课程
并发、大容量、高性能数据库设计与优化
PostgreSQL数据库实战培训
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

MySQL索引背后的数据结构
MySQL性能调优与架构设计
SQL Server数据库备份与恢复
让数据库飞起来 10大DB2优化
oracle的临时表空间写满磁盘
数据库的跨平台设计
更多...   

并发、大容量、高性能数据库
高级数据库架构设计师
Hadoop原理与实践
Oracle 数据仓库
数据仓库和数据挖掘
Oracle数据库开发与管理

GE 区块链技术与实现培训
航天科工某子公司 Nodejs高级应用开发
中盛益华 卓越管理者必须具备的五项能力
某信息技术公司 Python培训
某博彩IT系统厂商 易用性测试与评估
中国邮储银行 测试成熟度模型集成(TMMI)
中物院 产品经理与产品管理
更多...