PostgreSQL VACUUM/CLUSTER/UPDATE 磁盘处于 100% 但只有 5MB/秒

PostgreSQL VACUUM/CLUSTER/UPDATE disk at 100% but only 5MB/sec

我遇到了一个非常奇怪的 PostgreSQL 9.4 行为。当它在大型 table 上运行 UPDATE,或在大型 table 上执行 VACUUMCLUSTER 时,它似乎会挂起很长时间。事实上,我只是在第二天结束了这个过程。奇怪的是 CPU 处于空闲状态,同时磁盘 activity 处于 100% BUT 它只报告 4-5 MB/sec 读取和写入(参见 nmap & atop 的屏幕截图)。

我的服务器是 24CPU、32GB RAM 和 RAID1 (2 SAS 15K x 2)。通常,当磁盘处于 100% 利用率时,它会给我 120-160 MB/s 组合 reads/writes,这几乎可以无限期地保持在 >100MB/sec 的持续 IO。

系统甚至终端命令行都变得非常缓慢。我猜这与共享内存和虚拟内存有关。发生这种情况时,PostgreSQL 会消耗最大配置的共享内存。

我已禁用交换 vm.swappiness=0。我没有玩 vm.dirty_ratiovm.dirty_background_ratio 之类的东西。系统大页面已禁用 vm.nr_hugepages=0.

以下是我的postgresql.conf设置:

shared_buffers = 8200MB
temp_buffers = 12MB
work_mem = 32MB
maintenance_work_mem = 128MB
#-----------------------------------------------------
synchronous_commit = off
wal_sync_method = fdatasync
checkpoint_segments = 32
checkpoint_completion_target = 0.9
#-----------------------------------------------------
random_page_cost = 3.2      # RAIDed disk
effective_cache_size = 20000MB  # 32GB RAM
geqo_effort = 10
#-----------------------------------------------------
autovacuum_max_workers = 4
autovacuum_naptime = 45s
autovacuum_vacuum_scale_factor = 0.16
autovacuum_analyze_scale_factor = 0.08

磁盘只做5MB/sec怎么能100%呢?即使是最累人的随机 read/write 例程也应该快一个数量级。它一定与 PostgreSQL 处理 mapped/shared 内存的方式有关。这也没有发生在 postgres 9.1 中。

我正在努力自学 disk/memory 行为,但此时我需要 PRO 的帮助。

经过长时间的调查,我发现低 read/write 速度的磁盘饱和度与 IOPS 数量之间存在相关性。 IOPS的数量越大,IO饱和带宽越低。我的问题中的其中一张截图有 "Transfers/sec"。当数字变高时,t运行sfer 率下降。

遗憾的是,在数据库配置方面无能为力。 PostgreSQL 严重依赖共享内存映射文件到内存页。当需要将 some/all 内存页面同步回磁盘时,对于具有大 tables 的数据库,可能有 tens/hundreds 的数千个脏页面要同步。它会导致大量 运行dom 磁盘访问和无数的小原子 IOs.

因为安装 SSD 和启用 writeback 都不是我的选择,所以我不得不从不同的角度来解决问题。我分别处理了每个案例。

我的 UPDATE 语句每次 运行 都会影响一半以上或 table 条记录。我没有进行更新,而是每次都重新创建 table。这几乎翻了一番性能。

CLUSTER-ing a table 会导致重建所有 table 索引,但执行聚类的索引除外。对于具有许多索引的大型 table,这是执行集群时要记住的重要考虑因素。

我还将 VACUUM 替换为 ANALYSE,这似乎对 table 性能影响不大,但运行速度明显快于 VACUUM