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


    2.3 理解一致性和数据丢失

    挖掘PostgreSQL事务日志而不考虑一致性是不可能的。在本章的第一部分,我们已经大体上解释了事务日志的基本思想。您已经知道,无需事先的日志改变的能力,使数据处于一种好的形状是很难甚至是不可能的。

    到现在为止,我们大多都在讨论崩溃的问题。因为数据文件中的条目的损坏而丢失文件是绝对不好的。但是,崩溃不是您要关心的唯一问题。另外两个重要的主题是:

    • 性能

    • 数据丢失

    虽然这可能是一个重要的主题的明显的选择,我们有这样的感觉,这两个主题都不好理解,是受尊敬的,并因此需要考虑。

    在我们的日常业务为PostgreSQL咨询专家和培训师,我们通常会看到那些只专注于性能的人。

    Performance is everything, we want to be fast; tell us how to be fast…

    潜在的数据丢失,或者甚至是一个来处理它的概念的意识。对许多人来说,这看起来是新东西。我们这样看:如果数据丢失甚至更快有什么好处呢?这样做的关键不是性能不重要;性能是非常重要的。然而,我们只是想指出性能不是全局中唯一的组成部分。

    2.3.1 到磁盘的路径

    要了解关于数据丢失和一致性的问题,我们要看看一个数据块是如何被送到磁盘的。下图说明了这是如何工作的:

    当PostgreSQL要读取或者写入一个块是,它通常要经过几个层次。当一个块被写入,它将被发送到操作系统。操作系统将缓存数据并对数据执行写操作。在有些时候,操作系统将决定把数据传到一些低层次。这可能是磁盘控制器。磁盘控制器将缓存,重新排序,在数据最终到真实的物理存储设备之前,可能还有一个缓存层。

    在我们的例子中,我们使用了四层。在许多企业级系统中,甚至可能有更多的层次。试想一个虚拟机,存储通过网络挂载,例如,SAN,NAS,NFS,ATA-over_Ethernet,iSCSI,等等。许多抽象层都会有数据通过,并且每层都将尝试做自己那部分的优化。

    从内存到内存

    当PostgreSQL给操作系统传递一个8K的块时,发生了什么?这个问题唯一正确的答案可能是:“有事情”。当一个到文件的写被执行时,绝对不能保证数据被实际送到磁盘。

    在现实中,写入文件无非就是从PostgreSQL内存的复制操作到一些系统内存。这两个内存区域都在内存中,因此,在崩溃的情况下,东西可能丢失。从实践上来说,如果整个内存由于故障而不能工作,谁丢失了数据没有什么区别。

    下面的代码片段说明了我们所面临的基本问题:

    test=# d t_test

    Table "public.t_test"

    Column | Type | Modifiers

    --------+---------+-----------

    id | integer |

    test=# BEGIN;

    BEGIN

    test=# INSERT INTO t_test VALUES (1);

    INSERT 0 1

    test=# COMMIT;

    COMMIT

    就像在前面章节中,我们使用只有一列的表。目标是运行一个插入一行的事务。

    如果在提交不久之后,发生了崩溃,没有数据会处于危险之中,因为什么都没有发生。如果崩溃在一个INSERT语句之后,但在COMMIT之前,没有什么会发生。用户还没有发出COMMIT,因此该事务是众所周知的要运行,但没有完成。如果发生崩溃,应用程序将注意到事情是不成功的,并(希望)做出相应的反应。

    然而,情况是完全不同的,如果用户已经发出了COMMIT语句,它已经成功返回。无论发生什么,用户将期望提交的数据是可用的。

    [用户期望成功的写入在意外重新启动后是可用的。所谓的ACID标准也要求持久性。在计算机科学中,ACID(原子性,一致性,隔离性,耐久性)是一组属性,这些属性保证数据库事务可靠地处理。]

    从内存到磁盘

    要确保内核将数据从内存传递到磁盘,PostgreSQL必须采取一些预防措施。在 COMMIT,系统调用将被发起,它强制数据到事务日志中。

    [在这一点上,PostgreSQL没有必要强制数据到数据文件,因为我们总能从XLOG修复坏的数据文件。如果数据被安全地存储在XLOG中,事务可以被认为是安全。]

    必要的强制数据到磁盘的系统调用是fsync()。一些列表是从BSD手册页复制过来的。在我们看来,这是所写过的处理这个主题的最好的手册页之一:

    FSYNC(2) BSD System Calls Manual FSYNC(2)

    NAME

    fsync -- synchronize a file's in-core state with

    that on disk

    SYNOPSIS

    #include <unistd.h>

    int fsync(intfildes);

    DESCRIPTION

    Fsync() causes all modified data and attributes of fildes to be moved to a permanent storage device.This normally results in all in-core modified

    copies of buffers for the associated file to be written to a disk.

    Note that while fsync() will flush all data from the host to the drive (i.e. the "permanent storage device"), the drive itself may not physically

    write the data to the platters for quite some time and it may be written in an out-of-order sequence.Specifically, if the drive loses power or the OS

    crashes, the application may find that only some or none of their data was written. The disk drive may also re-order the data so that later writes

    may be present, while earlier writes are not.This is not a theoretical edge case. This scenario is easily reproduced with real world workloads

    and drive power failures.

    它本质上说,内核试图使它在内存中文件的映像与磁盘上的文件映像一致。它通过所有的改变到存储设备来实现。它也清楚地指出,我们在这里不是在谈论一个理论场景,刷回磁盘是一个非常重要的话题。

    在COMMIT没有磁盘刷新,您根本无法确保您的数据安全,这意味着,在非常麻烦的情况下,您实际上会丢失数据。

    而且,本质上重要的是速度和一致性;它们实际上是相对立的工作。刷回改变到磁盘尤其昂贵,因为这涉及到真实的硬件。我们的开销并不是5%,而是多了很多。随着SSD的引进,开销已经大幅下降,但是它仍然是可观的。

    关于电池的一句话

    大多数生产服务器将使用RAID控制器来管理磁盘。这里重要的一点是,磁盘刷新和性能通常和RAID控制器关系较紧密。如果RAID控制器没有电池,这是通常的情况,那么它需要长时间疯狂地刷新。RAID控制器必须等待最慢的磁盘的返回。然而,如果电池是可用的话,RAID控制器可以假定一个功率损耗,不会阻止一旦电被恢复的话一个公认的磁盘写完成。这样控制器可以缓存写和简单地伪装刷新。因此,一个简单的电池可以很容易地将性能提高十倍。

    [请记住,我们在本节所阐述的是一般的问题。但是,每个硬件都是不同的。我们强烈推荐您检查和了解您的硬件以及RAID配置,看看刷新是如何处理的。]

    超越 fsync()

    fsync()不是唯一把数据刷新到磁盘的系统调用。根据您正在使用的操作系统,不同的刷新调用都是可用的。在PostgreSQL中您可以通过改变wal_sync_method来决定您首选的刷新系统。同样,这个改变可以通过调整postgresql.conf来进行。

    可用的方法是 open_datasync, fdatasync, fsync, fsync_writethrough, 以及 open_sync。

    [如果您要改变这些值,我们强烈建议您查看您正在使用的操作系统的手册页,以确保您已经做了正确的选择。]

    2.3.2 PostgreSQL的一致性级别

    确保一致性和防止数据丢失是昂贵的;每个磁盘刷新都是昂贵的,在刷新到磁盘之前,我们应该三思而后行。为了给用户选择,PostgreSQL提供了多种级别的数据保护。这些不同的选择由两个重要的参数代表,这可以在postgresql.conf中找到:

    1. fsync

    2. synchronous_commit
    如果fsync被使用的话,fsync参数将控制数据丢失。在缺省配置中,PostgreSQL将始终刷新提交到磁盘。如果fsync处于关闭状态,然而,不能保证COMMIT会幸免于崩溃。数据会丢失,甚至可能会有数据损坏。要保护您的数据,保持fsync处于打开的状态是必须的。如果您能承受失去一部分或者全部数据,您可以放松刷新标准。

    synchronous_commit 和XLOG-writing 相关。通常情况下, PostgreSQL 将等待,直到数据已完全被写入到XLOG。尤其是短事务可以承受的相当多,因此,提供了各种不同的选择:

    • on: PostgreSQL将一直等到 XLOG 已经完全成功地写入。 如果您要存储信用卡数据,您要确保金融事务部丢失。在这种情况下,刷新到磁盘是必不可少的。

    • off: 在给客户报告成功和安全地写入磁盘之间有一个时间差。在这样的情况下,可以有损坏。让我们假设一个存储在一个网站上当前谁在线的数据库。假设您的系统崩溃了,20分钟后又恢复了。您真的在乎您的数据吗?20分钟后,每个人都有可能再次来回登录。这不值得牺牲性能来保护在几分钟后就过时的数据。

    • local:在复制数据库实例的情况下,我们将只等待本地实例刷新到磁盘。这里的好处是,您有一个高级别的保护,因为您刷新到一个磁盘;然而,我们可以放心地假设不会有两台服务器同时崩溃,因此我们可以就可以放松一点slave 上的标准。

    • remote_write: PostgreSQL 将一直等到同步备用服务器为给定的事务报告成功。

    在协议中设置fsync 为 off,改变 synchronous_commit 为 off 将不会导致崩溃。然而,在崩溃的情况下,我们可能会丢失一些事务,它们已经被成功提交了。 潜在的数据丢失的数量由一个额外的 postgresql.conf 中叫 wal_writer_delay管理。在把synchronous_commit 设置为off的情况下, 我们失去的永远都不会比在wal_writer_delayconfig变量中定义的多。

    [更改synchronous_commit 可能看起来像一个小的性能调整;然而,在现实中,当运行次小的写事务时,更改 sync 行为是主导因素之一,增益可能不只有几个百分点,但是,如果您幸运的话,它可能是十倍或者甚至更多(取决于硬件,工作负载,I/O子系统,等等)。]

    请记住,配置数据库不只是速度。一致性至少和速度同样重要,因此,您应该仔细考虑您是否要用潜在的数据丢失来和速度交换。

    因此,完全理解本章中所述的这些一致性相关的主题是非常重要的。当涉及到您的集群架构,数据安全将是一个重要的组成部分,能够判断是否特定架构对您数据有意义是非常可取的。毕竟,数据库的工作就是保护数据。您的耐久性要求的意识绝对是一个大的好处。

  • 相关阅读:
    内网穿透教程
    深入浅出 TCP/IP 协议栈
    STM32CUBEMX配置RTC闹钟
    RT-Thread STM32 系列 BSP 制作教程
    RT-Thread 在stm小内存系列产品的nano+msh完整移植教程
    C语言字符串与数字相互转换
    SD卡 TF卡 接口引脚定义
    定位数据格式
    安信可ESP-12F连接阿里云教程
    电脑使用网络调试助手连接阿里云步骤
  • 原文地址:https://www.cnblogs.com/songyuejie/p/4743332.html
Copyright © 2020-2023  润新知