ZFS上的Postgres(2017)

2020-09-12 02:49:35

ZFS是由Sun Microsystems最初创建的文件系统,已经为BSD提供了十多年的时间。虽然Postgres可以在BSD上运行得很好,但大多数Postgres安装在历史上都是基于Linux的系统。由于察觉到许可证不兼容,Linux上的ZFS在集成方面经历了更多的坎坷。

因此,管理员不愿意或直接拒绝在他们的Linux集群上运行ZFS。直到2013年OpenZFS被引入,这种情况才慢慢开始改变。这些天,ZFS和Linux开始变得更加集成,Ubuntu名气的Canonical甚至在其16.04LTS版本中宣布直接支持ZFS。

那么,由一家现已倒闭的硬件和软件公司设计的相对默默无闻的文件系统如何帮助Postgres呢?让我们来看看吧!

如今,旧的服务器硬件非常便宜,是测试可疑配置的完美实验室。这是我们将用于这些测试的服务器,供在家进行这些测试的人使用,或者需要一些参考点:

H200特别重要,因为ZFS充当自己的RAID系统。它也有自己的校验和和其他算法,不喜欢RAID卡挡路。因此,我们将卡本身置于一种便于此用例的模式。

因此,我们失去了RAID卡可能提供的任何电池后备写高速缓存。为了弥补这一点,使用SSD或其他永久性快速存储同时充当写缓存和读缓存是相当常见的。这也会自动将我们的硬盘转换为混合存储,这在预算上是一个巨大的性能提升。

首先要做的是:我们需要一个文件系统。该硬件有四个1TB硬盘和一个250 GB固态硬盘。为了避免本文太长,我们已经在所有HDD上放置了GPT分区表,并将SSD拆分为50 GB(操作系统)、32 GB(写缓存)和150 GB(读缓存)。更健壮的设置可能会使用单独的SSD或镜像对,但实验室是公平的选择。

我们首先创建ZFS池本身并显示状态,这样我们就知道它起作用了:

$>;zpool创建坦克-o ashift=12\ 镜像sdb1 sdd1\ 镜像sdc1 sde1\ 日志sda4\ 缓存SDA5 $>;zpool状态水箱 游泳池:水箱 状态:联机 扫描:擦除已在0h0m修复0B,但在Sun Dec 10 00:24:02 2017年12月10日修复0个错误 配置: 名称状态读写CKSUM 油箱联机%0%0 镜像-0联机0 0 0 Sdb1联机%0%0 %sdd1联机%0%0 镜像-1联机%0%0 SDC1联机%0%0 SDE1联机%0%0 原木 SDA4联机%0%0 快取 SDA5联机%0%0 错误:没有已知数据错误。

第一个zpool命令创建了相当于具有独立读写缓存的4磁盘RAID-10。除了简单得令人不安之外,它还自动挂载文件系统。我们确实可以立即开始在上面存储数据,但是让我们先花一些时间来调整它。

默认情况下并不总是启用压缩,通常会禁用atime,这样每次读取都不会有对应的磁盘写入。我们可能还应该为数据库存储创建一个单独的区域,以保持整洁。

ZFS设置压缩=lz4油箱 ZFS设置TIME=关闭油箱 ZFS设置Relatime=开坦克 ZFS创建水箱/db。

此测试也在Debian系统上进行,因此我们可以访问几个集群创建和配置实用程序。让我们创建一个专用的ZFS实例,并设置一些常用的配置参数:

Pg_createcluster 10 ZFS-D/油箱/数据库 Systemctl后台进程-重新加载 Pg_conftool 10 ZFS设置SHARED_BUFFERS 4 GB Pg_conftool 10 ZFS设置work_mem 12MB Pg_conftool 10 ZFS集maintenance_work_mem 1 GB Pg_conftool 10 ZFS SET RANDOM_PAGE_COST 2.0 Pg_conftool 10 ZFS设置Efficient_Cache_size 40 GB Systemctl启动[电子邮件受保护] Createdb pgbench Pgbench-i-s 100 pgbench。

最后,我们还创建了一个pgbench数据库,并使用10M条记录对其进行初始化,以用于测试目的。我们开始吧!。

让我们从获取硬件的性能基准开始。我们可能期望在12或24个线程时达到性能峰值,因为服务器有12个实际CPU和24个线程,但是查询吞吐量实际上最高达到并发32个进程的峰值。我们可以稍后再考虑这一点,现在,我们可以认为这是这种硬件的最大能力。

$>;pgbench-S-j 32-c 32-M准备-T 20 pgbench ..。 Tps=264661.135288(包括建立连接) Tps=264849.345595(不包括建立的连接)。

到目前为止,这是相当标准的行为。每秒26万个准备好的查询是很好的读取性能,但这应该是一个文件系统演示。让我们让ZFS参与进来。

让我们在启用写入的情况下重复相同的测试。一旦发生这种情况,文件系统同步、脏页、WAL开销和其他事情应该会极大地降低总体吞吐量。这是意料之中的结果,但我们现在看到的是多少呢?

$>;pgbench-j 32-c 32-M准备-T 10 pgbench ..。 Tps=6153.877658(包括建立连接) Tps=6162.392166(不包括建立的连接)。

不管有没有固态硬盘缓存,存储开销都是令人痛苦的现实。但是,在启用写入的情况下,6000 TPS对于此硬件来说是一个很好的结果。或者说是?我们真的能做得更好吗?

考虑Postgres FULL_PAGE_WRITS参数。托马斯·冯德拉(Tomas Vondra)过去曾写过这一点,认为这是防止由于部分写入而导致的沃尔腐败的必要之举。WAL既是流复制又是崩溃恢复,因此其完整性至关重要。因此,这是一个几乎每个人都应该忽略的参数。

ZFS是写入时拷贝(COW)。因此,不可能有撕裂的页面,因为页面不能在不恢复到前一个副本的情况下被部分写入。这意味着我们实际上可以在Postgres配置中关闭FULL_PAGE_WRITES。结果是一些相当惊人的性能提升:

$>;pgbench-j 32-c 32-M准备-T 10 pgbench ..。 Tps=10325.200812(包括建立连接) Tps=10336.807218(不包括建立的连接)

这几乎提高了70%。由于整页写入导致写入放大,Postgres在1分钟的pgbench测试中生成了1.2 GB的WAL文件,但在禁用整页写入的情况下只生成了160MB的WAL文件。

公平地说,32线程pgbench写测试非常滥用,当然不是典型的使用场景。然而,ZFS只是通过更改一个参数来确保我们的存储具有低得多的写负载。这意味着硬件的功能也已扩展到更高的写入工作负载,因为WAL流量没有消耗IO带宽。

精明的读者可能已经注意到,我们没有将缺省ZFS块大小从128k更改为与Postgres缺省值8KB保持一致。这就是当我们这样做时会发生的事情:

事实证明,128KB的块允许ZFS更好地组合8KB Postgres页面中的一些,以节省空间。这将使我们微不足道的2TB比其他情况下走得更远。

请注意,这不是重复数据消除,而是简单的lz4压缩,就CPU开销而言,这几乎是实时的。ZFS上的重复数据删除目前是一个不确定的怪诞世界,充满了沿着破碎的地貌爬行的畸形恐怖。对于重复数据消除表来说,这是一个极端的内存开销世界,而且由于与COW基础的固有冲突,可能会丢失数据。请不要使用它,让任何人使用它,甚至永远不要想使用它。

我们还没说完呢。ZFS作为COW文件系统的一个重要方面是它集成了快照。

考虑这样一种场景:开发人员连接到错误的系统,并丢弃了他们认为是QA环境中的表。原来他们走错了航站楼,刚刚抹去了一个关键的生产表,现在大家都抓狂了。

我们可以通过自己扔掉桌子来模拟这一点。出于本演示的目的,我们将在执行此操作之前拍摄快照:

啊!幸运的是,ZFS具有充分利用其奶牛天性的克隆能力。虽然ZFS快照始终以只读方式可用,但克隆是该快照的完全可写分支。这意味着我们可以进行一些细微的更改,并使用与拍摄快照时相同的数据使克隆联机。

也就是说,我们可能需要复制和修改配置文件,并删除可能与正在运行的实例冲突的任何延迟的postmaster.*文件。然后我们可以在不同的端口上启动克隆。此时,有两个postgres实例,我们可以从克隆中转储丢失的pgbench_Accounts表,并将其导入回主数据库,而不会跳过任何节拍。

ZFS克隆坦克/[电子邮件受保护]坦克/恢复 CD/坦克/恢复 RM邮政署署长* CP/usr/share/postgresql/10/postgresql.conf.sample Postgresql.conf Cp/etc/postgresql/10/zfs/pg_hba.conf pg_hba.conf Pg_ctl-D/TANK/RECOVER-O";-p5433";START Pg_dump-p 5433-t pgbench_account pgbench|psql pgbench。

表恢复后,每个人都很高兴,基础设施团队加入了新的防火墙规则,阻止开发系统连接到PROD。所有人都学到了宝贵的一课,开始了新的生活。

之后,我们只需停止克隆postgres实例并清除关联的挂载即可进行清理:

许多ZFS系统在大部分时间都自动运行快照创建和清理维护作业。这意味着我们可能已经有了每小时、每天或每周的快照,可用于恢复或调查。

虽然Linux Volume Manager(LVM)系统具有类似的功能,但LVM快照仅限于卷组中未分配的空间,必须手动挂载。ZFS快照来自同一个存储池,因此我们不需要猜测将来可能需要多大的快照。我们不会从我们的卷中失去潜在的分配空间。克隆也会以显示其与源的关系的方式自动装载。

ZFS使利用快照变得极其容易。事实上,开发系统甚至可以将单个Postgres实例指定为快照源,并为数十名开发人员提供他们自己的数据库在线副本。毕竟,这与在ZFS上运行的VM使用的方法相同。

ZFS还有一个命令可以将快照发送到远程ZFS文件系统。如果那里已经存在以前的快照,则它只发送差异。这种内置差异实际上比rsync快得多,因为它已经确切地知道哪些块是不同的。考虑一下这对几TB大小的VLDB Postgres系统意味着什么。

很难将立即可见的写入开销减少打折扣。快照也有大量公认的和潜在的使用情形。除了在线低开销压缩和混合缓存层之外,ZFS还拥有大量我们没有探索过的功能。

具有集成自我修复功能的内置校验和表明,启用校验和并不完全需要重新初始化现有的Postgres实例。文件系统本身确保校验和有效且正确,特别是当我们的池中有多个驱动器资源时。它甚至会走得更远,并在遇到不一致时主动纠正不一致。

早在2012年,我就立即对ZFS打折,因为当时我工作的公司是一家纯Linux商店。ZFS当时只能使用FUSE驱动程序使用,这意味着ZFS只能通过用户空间工作,没有真正的内核集成。修补它很有趣,但是没有一个理智的人会在任何类型的生产服务器上使用它。

从那时起,情况发生了很大的变化。我已经不再等待btrfs变得可行,而ZFS可能已经取代XFS成为我选择的文件系统。Postgres High Availability Cookbook的未来版本也将反映这一点。

Postgres MVCC和ZFS COW似乎是天生的一对。我很想看看未来几年会发生什么,因为ZFS已经在至少一个主要的Linux发行版中获得了主流的接受。