Postgres 流复制滞后,使用大量 CPU 和少量 I/O

har*_*aut 5 postgresql replication

我们有 2 个专用的数据库服务器。一个是主,另一个是它的流从。
Postgres 版本9.0.17

我们在两台服务器上都有类似的硬件,并在 Raid 10 中使用 15krpm SAS 驱动器用于数据库集群。唯一的区别是在服务器上我们有 128 GB 内存,而在从服务器上我们有 64 GB 内存。

我们面临的问题是我们的流媒体奴隶落后了。

在流式从属设备上,我们有

postgres=# select pg_last_xlog_receive_location();
 pg_last_xlog_receive_location
-------------------------------
 1F7D/DD3BA000


postgres=# select pg_last_xlog_replay_location();
 pg_last_xlog_replay_location
------------------------------
 1F75/5BE08980
Run Code Online (Sandbox Code Playgroud)

wal received 和 replay 之间的这种差异在不断增加。

请让我知道如何解决此问题。

的输出perf top -u postgres

98.30%  postgres          (.) DropRelFileNodeBuffers
0.20%  postgres          (.) 0x000000000008b05b
0.14%  (kernel)          (k) copy_user_generic_string
0.13%  postgres          (.) hash_seq_search
0.07%  postgres          (.) hash_search_with_hash_value
0.05%  (kernel)          (k) _spin_lock
0.05%  (kernel)          (k) apic_timer_interrupt
0.03%  (kernel)          (k) do_timer
0.03%  postgres          (.) RememberFsyncRequest
0.03%  (kernel)          (k) __sb_start_write
0.02%  (jbd2)            (k) do_get_write_access
0.02%  (kernel)          (k) unroll_tree_refs
0.02%  (cciss)           (k) do_cciss_request
0.02%  (ext4)            (k) ext4_check_dir_entry
0.02%  (kernel)          (k) path_walk
0.02%  (kernel)          (k) scheduler_tick
0.02%  postgres          (.) LWLockAcquire
0.02%  (kernel)          (k) dyntick_save_progress_counter
0.02%  (kernel)          (k) _spin_lock_irqsave
0.02%  (kernel)          (k) audit_syscall_entry
0.02%  (ext4)            (k) ext4_journal_start_sb
0.02%  (kernel)          (k) radix_tree_range_tag_if_tagged
0.01%  (kernel)          (k) sys_getppid
0.01%  (kernel)          (k) native_read_tsc
0.01%  libc-2.12.so      (.) _IO_str_init_static_internal
0.01%  (kernel)          (k) __getblk
0.01%  (kernel)          (k) run_timer_softirq
0.01%  (kernel)          (k) system_call
0.01%  postgres          (.) __errno_location@plt
0.01%  libc-2.12.so      (.) __GI___libc_lseek64
0.01%  postgres          (.) XLogReadBufferExtended
0.01%  (kernel)          (k) memcpy
0.01%  (kernel)          (k) irq_work_run
0.01%  postgres          (.) fsm_set_avail
0.01%  (kernel)          (k) kmem_cache_free
0.01%  (kernel)          (k) do_unlinkat
0.01%  libc-2.12.so      (.) vfprintf
0.01%  postgres          (.) hash_any
0.01%  (kernel)          (k) sysret_check
0.01%  (kernel)          (k) mutex_lock
0.01%  (kernel)          (k) printk_tick
0.01%  postgres          (.) elog_start
0.01%  (kernel)          (k) __percpu_counter_add
0.01%  (kernel)          (k) file_update_time
0.01%  (kernel)          (k) enqueue_task_fair
0.01%  (kernel)          (k) blk_recount_segments
0.01%  (kernel)          (k) rcu_check_callbacks
0.01%  (kernel)          (k) put_pid
0.01%  postgres          (.) mdunlink
0.01%  postgres          (.) LWLockRelease
0.01%  (kernel)          (k) current_kernel_time
0.01%  (kernel)          (k) perf_event_task_tick
0.01%  (kernel)          (k) native_apic_mem_write
Run Code Online (Sandbox Code Playgroud)

用于 postgres 启动过程的 gdb 输出

(gdb) thread apply all backtrace Thread 1 (Thread 0x7fd06d28f7c0 (LWP 26949)):
#0  0x00000000005ec320 in DropRelFileNodeBuffers ()
#1  0x0000000000603115 in smgrdounlink ()
#2  0x000000000047d992 in ?? ()
#3  0x000000000048eca9 in StartupXLOG ()
#4  0x0000000000490c58 in StartupProcessMain ()
#5  0x00000000004a6faf in AuxiliaryProcessMain ()
#6  0x00000000005d31c3 in ?? ()
#7  0x00000000005d7372 in PostmasterMain ()
#8  0x000000000057e320 in main ()
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 7

当前(至少在 PostgreSQL 9.4 及更早版本中如此)PostgreSQL 版本具有单线程 WAL 恢复。

这意味着预写日志的重放仅发生在一个恢复工作者中,因此与正常运行的 master 相比,从 I/O 并发中获益更少。在副本和主服务器具有相似硬件的情况下,这可能导致 WAL 重放滞后,即使您希望主服务器(通常也承受更多负载)是较慢的服务器。

(改进这一点会很棒,但希望它足以完成这项工作,目前似乎没有人愿意为其提供资金)。

也就是说,您的 CPU 使用率非常高的情况似乎不适合低 I/O 并发性的问题。在你的情况下,我会附加gdb并查看重放过程正在做什么,或者perf top用来检查整个系统在做什么,然后perf一旦我有一些线索就深入挖掘。我还会仔细查看iotopvmstatiostat、 PostgreSQL 日志dmesg等。

经调查

配置文件显示,大部分时间都花在了DropRelFileNodeBuffers.

这确实通过线性扫描shared_buffers每当relfilenode被删除-引起的truncatedrop tableclusterdrop index等,这必须WAL重放期间完成,以及在主节点上。

所以这表明:

  • shared_buffers的可能很大;和
  • 您可能正在执行大量删除 relfilenodes 的操作

减少shared_buffers副本可能会有所帮助。