PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(4)

2.4 调整检查点和XLOG

目前为止,这一章已经提供深入洞察PostgreSQL如何写入数据,一般来说,XLOG是用来干什么的。考虑到这方面的知识,我们现在可以继续并学习我们能做些什么来使我们的数据库在复制和单台服务器运行的两种情况更加有效的工作。

2.4.1 理解检查点

在本章中,我们已经看到在数据可能到其它地方之前,它已经被写入到了XLOG。问题是,如果XLOG从未被删除,显然,在没有填满磁盘的同一时间,我们不会永远写到XLOG中。

要解决这个问题,XLOG必须在某一时刻被删除。这个过程就是所谓的检查点。

从这个问题所带来的主要问题是:什么时候XLOG可以被截断到某一特定的点?答案是:PostgreSQL把XLOG中所有的东西都放到存储文件中。如果XLOG中的所有更改也被放到数据文件中,XLOG才可以被截断。

[请记住,只写数据是没有价值的,我们还必须把数据刷新到数据表中。]

在某种程度上,XLOG可以被看作在有情况发生时,数据文件修理工。如果一切都被完全修复,修理指令就可以被放心地删除了。这就是在一个检查点期间所发生的。

2.4.2 配置检查点

对一致性来说,检查点是非常好重要的,但是它们对性能来说也是非常重要的。如果检查点配置不当,您可能会面临严重的性能下降。

当谈到配置检查点,下面是一些相关参数。请注意,所有这些参数可以在postgresql.conf 中进行更改:

checkpoint_segments = 3

checkpoint_timeout = 5min

checkpoint_completion_target = 0.5

checkpoint_warning = 30s

在下面的章节中,我们将看看这些变量:

关于段和超时

checkpoint_segments 和 checkpoint_timeout 将定义两个检查点之间的距离。检查点发生或者当我们用完段或者实际到了。

请记住,一个段通常是16MB,所以三个段意味着我们将每48MB做一个检查点。在现代硬件上,16MB是远远不够的。在一个典型的生产系统中,一个检查点256个间隔或者更高是完全可行的。

但是,当设置checkpoint_segments的时候,有一件事必须记在您的脑后:在崩溃的情况,PostgreSQL必须重放自从最后一个检查点的所有的更改。如果两个检查点之间的距离非常大,您可能会注意到,您的故障数据库实例需要很长的时间才能再次启动。为了可用性,这种情况应该避免。

[在崩溃之后,总会有性能与恢复时间之间的权衡;您必须平衡您相应的配置。]

checkpoint_timeout 也非常重要。它是两个检查点之间所允许的时间上线。不更改时间而无限制地增加checkpoint_segments是没有意义的。在大型系统中,对许多人来说,增加checkpoint_timeout已被证明是有意义的。

[在PostgreSQL中,您会发现,有一个事务日志的常数。不同于在其它数据库系统中,XLOG文件的数目和事务的最大尺寸没有关系;一个事务的大小可以很容易地超过两个检查点之间的距离。]

写或不写?

我们在本章已经知道,在COMMIT时,我们不能确定数据是否已经在数据文件。

因此,如果数据文件不必是一致的,为什么不改变数据写入的时间点?这正是我们使用checkpoint_completion_target可以做到的。这个思想是有一个指定检查点完成的目标,作为两个检查点之间的总时间的一部分。

现在让 我们讨论三个场景来说明checkpoint_completion_target的目的:

场景1-存储股市数据

在这个场景中,我们将存储道琼斯工业(DJIA)所有股票的最近行情。我们不想存储所有股票价格的历史,而是最近的,当前的价格。

考虑到我们正在处理的数据的类型,我们可以假设我们有一个由UPDATE语句决定的工作负载。

会发生什么?PostgreSQL必须一遍又一遍地更新相同的数据。鉴于一个事实,DJIA由30个不同的股票组成,数据量是非常有限的,并且我们的表也非常小。除此之外,价格可能每秒更新一次,或者更频繁。

在内部,情况是这样的:当第一个UPDATE到来时,PostgreSQL将获得一个块,放入内存并修改它。每一个后续的UPDATE将最有可能改变相同的块。从逻辑上讲,所有的写操作必须写到事务日志,但是在共享缓冲区中的缓存块发生了什么?一般的规则是:如果有许多UPDATE(分别对相同的块做更改),尽可能地把块保存在内存中是明智的;这将通过一个写多个变化更改来极大地增加避免I/O的可能性。

[如果你要增加在一个磁盘I/O有许多更改的肯能性,考虑降低checkpoint_complection_target。块将在内存中停留更长的时间,因此在写发生之前,很多变化可能进入相同的块。.]

该方案只是介绍,checkpoint_completion_target 为 0.05(或者5%)可能是合理的。

场景2-批量装载

在我们的第二个场景中,我们将加载1TB的数据到一个空表。如果你正在一次加载这么多的数据,再次命中你十分钟之前命中的数据块的可能性是多少?这个可能性基本上是0,在这种情况下,缓冲区没有一点写入,因为我们会很容易通过空闲以及等待I/O的发生而错过磁盘的容量。

在批量加载期间,我们要使用我们一直都有的所有的I/O能力。为了确保PostgreSQL立即把数据写出来,我们必须把checkpoint_completion_target的值增加到接近1。

场景3-I/O峰值和吞吐量方面的考虑

尖锐的剑锋可以杀死你,至少它们可以造成应该避免的严重的伤害。在你周围的真实世界中真实的东西在数据库世界中也是真实。

在这个场景中,我们要假设一个应用程序存储一个电话公司所谓的呼叫详细记录(CDRs)。你可以想象,很多写将会发生,并且人们一整天都在打电话。当然,会有人们在打电话时,立即有另外一个电话跟在后面,但我们也将见证好多人在一周之内只打一次电话。

从技术上将,这意味着有一个好机会,在共享内存中的块,它最近已经被更改了,将面临第二次或者第三次的更改,但是,我们也将对那些不再被访问的块做出巨大的更改。

这种情况我们该如何处理呢?晚点写出数据,以便尽可能多的更改将在之前已经修改过的页面上进行更改。但是,在检查点期间会发生什么呢?如果更改(在这种情况下,脏页)囤积了太长时间,检查点本身将会很激烈,很多块必须在很短的时间内被写入。这会导致所谓的I/O剑锋。在一个I/O剑锋,你会看到你的系统是繁忙的。这可能显示缺少响应时间,缺少响应时间可以被你的终端用户感受到。

这给问题增加了一个维度:可预测的响应时间。

让我们这样说吧:让我们假设你已经成功地使用了一段时间的网上银行。你很高兴。现在,一些人在你的网上银行找到了一个调整方法,这使得网上银行背后的数据库快了50%,但是,这增加了一个缺点:每天有两个小时,该系统不可达。显然,从性能的角度来说,吞吐量会比较好:

24 hours * 1 X < 22 hours * 1.5 X

但是,你的客户会开心吗?很显然,你不会。这是一个典型的用户案例,优化最大吞吐量并没有好处。如果你可以满足你性能需求,有均匀的响应时间而有一点小小的性能损失作为代价可能是明智的。在我们的银行的例子中,这将意味着你的系统是24×7运行而不是每天只运行22小时。

[如果你的互联网带宽比以前快10倍,你会频繁地支付你负担吗?显然,你不会。有时,它不是关于每秒多少事务的优化,而是你以最合理的方式处理一个预先定义的负载量的优化方法。]

同样的概念也适用于我们的电话应用程序。我们在检查点期间写所有的更改,因为这可能导致检查点期间的延迟问题。这对立即更改数据文件也没有好处(意思是:高的checkpoint_completion_target),因为我们会写得太多,太频繁。

这是一个你必须妥协的典型的例子,checkpoint_completion_target为0.5 可能在这种情况下是最好的注意。

结论

从三个例子中得出的结论是,没有适合所有用途的配置。为了得出一个好的可行的配置,你真的需要考虑一下你在处理的数据类型。对于许多应用,0.5的值已经证明刚刚好。

2.4.3 调整WAL缓冲区

在本章中,我们已经调整了一些重要的参数,例如,shared_buffers, fsync,等等。还有一个参数,但是,这可能会对性能产生重大的影响。参数 wal_buffers 被设计用来告诉PostgreSQL,用多少内存来记录目前还没有被写入磁盘的XLOG。所以,如果有人在注入大事务时,在COMMIT之前,PostgreSQL将不会把任何变化较小的表写到XLOG。请记住,在崩溃期间,如果一个未提交的事务丢失了,我们不需要在意它,因为COMMIT是在日常生活中唯一重要的事情。在COMMIT发生之前,这对使用较大的块写XLOG很有意义。这正是wal_buffers做的:除非在postgresql.conf中手动更改,它是一个自动调整的参数(用-1表示),在XLOG写回磁盘之前,它使得PostgreSQL花费3%的shared_buffers,但不超过16MB来保持XLOG。

[在老版本的PostgreSQL中,这个参数是64KB。对现代的机器来说 这么低的值是不合理的。如果你在运行一个老版本的PostgreSQL,可以考虑把wal_buffers增加到16MB。对合理大小的数据库实例来说,这通常是一个合理的值。]

时间: 2024-10-04 10:45:06

PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(4)的相关文章

PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(1)

在前面的章节中,我们已经理解了各种复制概念.这不仅仅是一个为了接下来将要介绍的东西而增强您的意识的理论概述,还将为您介绍大体的主题. 在本章,我们将更加接近实际的解决方案,并了解PostgreSQL内部是如何工作的,复制意味着什么.我们将看到所谓的事务日志(XLOG)做什么,以及它是如何运作的.XLOG在PostgreSQL复制机制中起着主要作用.理解这部分是如何工作的是必要的. 2.1 PostgreSQL如何写入数据 PostgreSQL的复制完全是关于写入数据的.因此,PostgreSQL

PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(3)

2.3 理解一致性和数据丢失 挖掘PostgreSQL事务日志而不考虑一致性是不可能的.在本章的第一部分,我们已经大体上解释了事务日志的基本思想.您已经知道,无需事先的日志改变的能力,使数据处于一种好的形状是很难甚至是不可能的. 到现在为止,我们大多都在讨论崩溃的问题.因为数据文件中的条目的损坏而丢失文件是绝对不好的.但是,崩溃不是您要关心的唯一问题.另外两个重要的主题是: • 性能 • 数据丢失 虽然这可能是一个重要的主题的明显的选择,我们有这样的感觉,这两个主题都不好理解,是受尊敬的,并因此

PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(5)

2.5 XLOG的内部结构 我们将使用事务贯穿本书,并让您在技术层面上更深地洞察事情是如果工作的,我们已经增加了这部分专门处理XLOG的内部工作机制.我们会尽量避免前往下降到C级,因为这将超出本书的范围,但我们会为您提供希望足够深的见解. 2.5.1 理解XLOG记录 对XLOG所做的更改是基于记录的.这意味着什么?让我们假设您在给一个表添加一行数据: test=# INSERT INTO t_test VALUES (1, 'hans'); INSERT 0 1 在这个例子中,我们正在插入一个

PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(2)

2.2 XLOG和复制 在本章中,您已经了解到PostgreSQL的事务日志已经对数据库做了所有的更改.事务日志本身被打包为易用的16MB段. 使用这种更改集来复制数据的想法是不牵强的.事实上,这是在每个关系(或者甚至非关系)数据库系统的发展的一个逻辑步骤.本书的其它部分,您将在许多方面看到PostgreSQL事务日志可以如何以许多不同的方法被使用,获取,存储,复制,和分析. 在大多数的复制系统中,PostgreSQL事务日志是整个体系结构(用于同步复制和异步复制)的的骨干.

PostgreSQL Replication之第一章 理解复制概念(1)

PostgreSQL Replication系列翻译自PostgreSQL Replication一书 在本章中,将会介绍不同的复制概念,您会了解哪些类型的复制对哪一种实用场景是最合适的. 在本章的最后,您将能够判断某个概念在各种情况下是否是可行的. 我们在本章将介绍以下主题: • CAP理论 •复制的物理限制 •为什么延迟有影响 •同步和异步复制 •拆分和复制 在我们使用PostgreSQL实际工作之前,我们将引导您完成一些非常基本的与复制相关想法和事实. 1.1 CAP理论和物理限制 您可能

PostgreSQL Replication之第一章 理解复制概念(3)

1.3 使用分片和数据分配 本节您将了解基本可扩展性技术,例如数据库分片.分片被广泛应用于高端系统并提供一个简单而且可靠的扩展设置方式来向外扩展.近年来,分片已经成为一种扩大专业系统规模的标准方式. 1.3.1 理解分片的目的 如果您的数据量增长超过一台机器的处理能力将会发生什么事情?如果您要运行这么多的事务,一台服务器根本跟不上怎么办?我们假设您有百万级的用户,上万用户想在同一时间执行特定的任务. 显然,某些时候,您再也不能通过购买能够处理无限大的负载的足够大的服务器来解决问题.显然在单个服务

PostgreSQL Replication之第一章 理解复制概念(2)

1.2不同类型的复制 现在,您已经完全地理解了物理和理论的局限性,可以开始学习不同类型的复制了. 1.2.1 同步和异步复制 我们可以做的第一个区分是同步复制和异步复制的区别. 这是什么意思呢?假设我们有两台服务器,希望从一台服务器(the master)复制数据到第二台服务器(the slave).下图说明了同步和异步复制的概念: 我们可以使用一个简单的事务如下所示: BEGIN: INSERT INTO foo VALUES ('bar'); COMMIT; 在异步复制的情况下,事务被提交到

疯狂JAVA——第二章 理解面向对象

面向对象的三大特征:继承.封装和多态 面向对象的方式实际上由OOA(面向对象分析).OOD(面向对象设计)和OOP(面相对象编程)三个部分组成,其中OOA和OOD的结构需要用一个描述方式来描述并记录,目前业界统一采用UML(统一建模语言)来描述并记录OOA和OOD的结果. 面向对象和基于对象的区别:基于对象也是用了对象,但无法利用现有的对象模板产生新的对象类型,也就是说,基于对象没有继承和多态.JavaScript就是基于对象的. java语言中,除了8个基本数据类型以外,一切都是对象. 一般-

第二章.理解面向对象

面向对象语言的三个基本特征:封装(Encapsulation).继承(Inheritance).多态(Polymorphism) 封装:将对象的实现细节隐藏起来,然后通过一些公用方法来暴露该对象的功能 继承:实现软件复用的手段,当子类继承父类后,子类作为一种特殊的父类,将直接获得父类的属性和方法 多态:子类对象可以直接赋给父类变量,但运行时依然表现出子类的行为特征,意味着同一个类型的对象在执行同一个方法时,可能表现出多种行为特征. 抽象:忽略一个主题中与当前目标无关的那些方面,抽象并不打算了解全