本文主要是研究PostgreSQL在普通SSD和可计算存储CSD上的空间、性能差异,以及PostgreSQL的FILLFACTOR对空间和性能的影响。PostgreSQL的 sysbench 测试数据(50亿)在CSD3000 上压缩比在 3.91 以上,PostgreSQL的 Fillfactor 设置从100 降低到 75 时,性能还能够进一步提升,而闪存使用空间不会增加多少。
PostgreSQL版本是14.4,测试工具是sysbench 1.1 for PG。SSD分别是Intel的GEN4的一款4TB、以及ScaleFlux的GEN4的CSD3000
ES版本。由于测试环境和方法问题,测试数据跟SSD生产环境的能力值可能会有一些差异。本文重点是关注同样的环境和方法下二者的差异,以加深对PostgreSQL、SSD/CSD 特点的理解。
SSD的稳态、GC、写放大、容量
可计算存储CSD本身也是SSD。除了最新的ZNS SSD这个种类外,普通的SSD在进入稳态后都有写放大问题。严格的稳态定义指SSD标称的闪存空间都被用尽,继续写入会用到SSD的超额配置的闪存空间(Over Provision,简称OP)。此时SSD内部一定会启用闪存垃圾空间回收(GC)机制。根据以前的分享知道,GC 会降低SSD读写性能(新盘的空盘状态性能最好)。一个有预判能力的企业SSD,通常也会根据用户数据分布特点,提前合理安排垃圾回收,避免到最后一刻才开始GC以及性能骤降。OP的比例在SSD行业里通常有两种:7%和22%。OP越大,SSD稳态时性能越好。不过,由于OP的闪存空间不在用户的可用容量空间内,提升OP,会导致TCO略微下降。还补充一点的是为了所有闪存块寿命尽可能均衡,SSD还会有后台磨损均衡(Wear Leveling)机制。GC和WL都会导致写放大。理论上稳态对CSD性能更友好,标准的稳态定义太过严格,这里做PostgreSQL测试就不严格去控制进入稳态的时机。稳态并不是要把SSD盘占满(或接近占满),而是SSD闪存空间标称的部分都写到过。理解这个需要先理解SSD的写都是追加写不是覆盖写(同一个数据可能有多个版本,只有最新的版本是业务需要的,所以SSD闪存写起来非常浪费)。这次测试PostgreSQL的数据大小到达1TiB以上,反复读写测试后相信已经到达稳态。实际通过观察SSD写放大值也可以确认这点。
PostgreSQL 多实例部署和初始化
PostgreSQL 安装
sudo yum
install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpmsudo yum
install -y postgresql14 postgresql14-contrib postgresql14-serversudo
/usr/pgsql-14/bin/postgresql-14-setup initdbsudo systemctl
enable postgresql-14sudo systemctl
start postgresql-14默认安装的PostgreSQL数据库目录在 var/lib/pgsql/14/ 下。可以将目录移到SSD盘上并通过软链接访问。或者直接修改服务文件里的PGATA 地址。安装第二个PostgreSQL实例,需要复制第一个实例的配置文件并修改PGDATA目录和数据库端口。cp usr/lib/systemd/system/postgresql-14.service
/usr/lib/systemd/system/postgresql-14-secondary.service/usr/pgsql-14/bin/postgresql-14-setup
initdb postgresql-14-secondarysystemctl
enable postgresql-14-secondarysystemctl
start postgresql-14-secondaryPostgreSQL 数据库测试准备
PostgreSQL 数据库测试准备包括参数配置以及用户和表空间创建。PostgreSQL数据库参数在数据目录下的 postgres.conf 文件里。主要需要调整内存和IO相关的参数。shared_buffers
= 64GB
maintenance_work_mem
= 4GB
fsync =
on
synchronous_commit
= on
full_page_writes
= on
port = 5432
max_connections
= 1000
max_connections
= 1000
maintenance_work_mem=1GB
bgwriter_delay
= 20ms
max_wal_size =
1GB
archive_mode =
off
create user mq
with password 'scaleflux' ;
create
database testdb owner mq;
grant all
privileges on database testdb to mq;
create
tablespace tbs_data owner mq location '/data/csd3000/pgdata/tbs_data';
alter user mq
default tablespace tbs_data ;
Sysbench for PostgreSQL
sysbench默认不支持PostgreSQL,需要重新编译安装一下。为了方便,这里同时支持 mysql和postgresql 两个数据库。sysbench 安装
yum install
automake
yum install
libtool.x86_64
yum -y install
postgresql-devel
unzip
sysbench-1.0.zip
mv
sysbench-1.0 opt/
cd
sysbench-1.0
./autogen.sh
./configure
--prefix=/usr/local/pg/sysbencd_1.0 --with-mysql --with-pgsql --with-pgsql-includes=/usr/pgsql-14/include
--with-pgsql-libs=/usr/pgsql-14/lib
make
make install
sysbench 数据初始化
sysbench 的建表语句在脚本 oltp_common.lua中。如果要调整表结构(如修改列长度)可以修改这个脚本。sysbench --db-driver=pgsql --pgsql-host=127.0.0.1 --pgsql-port=5432 --pgsql-user=mq
--pgsql-password='scaleflux' --pgsql-db=testdb
--table-size=50000000 --tables=200 --threads=100 --time=120 --events=0 --report-interval=60 --percentile=99 --create-table-options='WITH (FILLFACTOR=75) tablespace tbs_data ' --create_secondary=true ./lua/oltp_read_only.lua prepare
PostgreSQL 建表时的 FILLFACTOR 选项会影响后期表的大小,默认值是100 。在 CSD3000 盘上的PostgreSQL 实例初始化的时候,可以通过sysbench选项 –create-table-options 将这个参数传递进去。
测试结果
数据容量、性能跟填充因子关系
根据PostgreSQL 部署所在的SSD类型(CSD和普通SSD)以及建表时填充因子(FillFactor,简称FF,指定100和75 两种取值)类型不同,一共有四种场景。- 物理容量指的SSD闪存使用容量(有效数据部分)。对于普通的SSD,这个容量跟操作系统里看到的磁盘的已使用空间是一样的。对于CSD,在操作系统里看到的已使用空间跟普通SSD是一样的,只是CSD内部的闪存使用容量由于有透明压缩,会小很多。
- 这里读写性能和纯写性能分别是指oltp_read_write 、oltp_write_only 场景的128 并发下的sysbench返回的QPS 信息。
- FF是表FILLFACTOR设置。无论是CSD还是SSD,当FF从默认值100降到75的时候,物理容量都会有增加,只不过CSD的物理容量增长比例比普通SSD要小很多。除了物理容量会增加,读写和纯写场景的性能也会有相应的提升。这就是FillFactor空间换性能的作用。
- 对于CSD,FF降低带来的空间增长由于开始的时候都是填充数据(0x0),所以都会被CSD压缩掉,表现为CSD压缩比也相应增加了。
填充因子对写场景性能影响的分析
下图是以普通SSD上sysbench 对应场景相应并发下的QPS为基准,测试 CSD上sysbench的相应QPS的增量占基准值的比例。根据FillFactor的值分为两个(100和75)。从图中也可以看出当FillFactor从100降低到75时,oltp_insert,
oltp_update_non_index 收益最大,oltp_delete 收益不明显,oltp_update_index 场景性能还可能更差。oltp_update_non_index场景提升最大,这个表示更新非索引字段。在真实的OLTP业务里,插入和更新的比例非常高,用空间换性能很值。SSD 写放大分析
SSD的写放大因子可以通过单位时间的“NAND写入变化量”除以“主机写入变化量”得出。查看闪存的NAND写入量和主机写入量命令如下:nvme intel
smart-log-add dev/nvme1n1Additional
Smart Log for NVME device:nvme1n1 namespace-id:ffffffffprogram_fail_count : 100% 0erase_fail_count : 100% 0wear_leveling : 98% min: 258, max: 264, avg: 261end_to_end_error_detection_count:
100% 0timed_workload_media_wear : 100% 63.999%timed_workload_host_reads : 100% 65535%timed_workload_timer : 100% 65535 minthermal_throttle_status : 100% 0%, cnt: 0retry_buffer_overflow_count : 100% 0pll_lock_loss_count : 100% 0nand_bytes_written : 100% sectors: 35523407host_bytes_written : 100% sectors: 21257937
通过多次查询计算变化量可以算出一段时间(这里是一分钟) SSD的写放大。默认安装的PostgreSQL实例的数据文件和Redo日志文件是放在同一块SSD上。经测算PostgreSQL文件放在CSD和SSD上的写放大,前者约是后者的1/3 。通常来说,数据库的数据文件和REDO日志文件读写特点不一样,写放大也不一样。但是在PostgreSQL 里,随着并发的提升,两类文件的写放大基本一样。将PostgreSQL的REDO日志单独放到一块SSD上,再次测试得到下面写放大数据。高并发时PostgreSQL的REDO日志写放大刚跟数据文件比较接近,主要原因是PostgreSQL的REDO日志里记录了每个数据块完整的内容。这个是由参数log_full_writes 控制,生产环境都要设置为 on ,主要是为了防止SSD掉电时数据库的8KB 的IO写在SSD内部出现部分成功部分失败的现象。所以在PostgreSQL里,变化的数据块在数据文件和日志文件里都会记录,这个效果跟MySQL的双写类似。其弊端除了浪费SSD寿命,还影响PostgreSQL的写性能。在MySQL里,可以使用CSD3000的16KB IO原子写能力,关闭MySQL的双写缓冲设计,但在PostgreSQL里还不行,因为PostgreSQL的数据写是BUFFER IO,写到PageCache就返回了。CSD原子写需要应用是DIRECTIO。如果我们关闭 log_full_write 选项,再看PostgreSQL的数据文件和日志文件SSD写放大。此时REDO文件的写放大就相对要高,尤其是低并发的时候。写放大关系到SSD的寿命。写放大越低,理论使用寿命越高。此外通过观察SSD写放大和IO 写入吞吐量,可以推测SSD内部的垃圾回收(GC)和磨损均衡(WC)活动的强度。写放大越低,则业务读写SSD期间性能受到的负面影响就越低。SSD 读写延时数据分析
SSD的垃圾回收和磨损均衡对业务读写SSD的直接影响是读写延时增加且不稳定,这个可以通过操作系统的/proc/diskstat 文件获取。这里测试使用 tsar 命令实时读取SSD的读写延时。数据散点图如下。 - 黄色的点是普通SSD和上面的PG实例(FF=100)在不同场景不同并发测试下的写延时,蓝色的点是CSD和上面的PG实例(FF=75)对应的场景和并发下的写延时。
- CSD透明压缩抑制了写放大,降低了SSD的GC和WL活动对业务读写的影响,所以CSD观察下的写延时相比普通SSD更低且更稳定。
- CSD透明压缩节省了后端NAND读写时的带宽,带来一个额外的效果在高并发读写时CSD的前端读吞吐可以跑的更高(更接近GEN4的带宽标准)。