Postmaster 使用过多的 CPU 和磁盘写入

wol*_*tle 9 postgresql linux performance

使用 PostgreSQL 9.1.2

我看到过多的 CPU 使用率和大量的 postmaster 任务写入磁盘。即使我的应用程序几乎什么都不做(每分钟插入 10 次),也会发生这种情况。但是,有合理数量的连接打开。

我一直在尝试确定我的应用程序中是什么导致了这种情况。我对 postgresql 很陌生,到目前为止还没有到任何地方。我在我的配置文件中打开了一些日志选项,并查看了 pg_stat_activity 表中的连接,但它们都处于空闲状态。然而,每个连接消耗约 50% 的 CPU,并且正在向磁盘写入约 15M/s(不读取任何内容)。

我基本上是使用股票 postgresql.conf 进行很少的调整。我很感激任何关于我可以做些什么来追踪这个问题的建议或指示。

这是 top/iotop 向我展示的示例:

Cpu(s): 18.9%us, 14.4%sy,  0.0%ni, 53.4%id, 11.8%wa,  0.0%hi,  1.5%si,  0.0%st
Mem:  32865916k total,  7263720k used, 25602196k free,   575608k buffers
Swap: 16777208k total,        0k used, 16777208k free,  4464212k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                          
17057 postgres  20   0  236m  33m  13m R 45.0  0.1  73:48.78 postmaster                                                                                                                       
17188 postgres  20   0  219m  15m  11m R 42.3  0.0  61:45.57 postmaster                                                                                                                       
17963 postgres  20   0  219m  16m  11m R 42.3  0.1  27:15.01 postmaster                                                                                                                       
17084 postgres  20   0  219m  15m  11m S 41.7  0.0  63:13.64 postmaster                                                                                                                       
17964 postgres  20   0  219m  17m  12m R 41.7  0.1  27:23.28 postmaster                                                                                                                       
18688 postgres  20   0  219m  15m  11m R 41.3  0.0  63:46.81 postmaster                                                                                                                       
17088 postgres  20   0  226m  24m  12m R 41.0  0.1  64:39.63 postmaster                                                                                                                       
24767 postgres  20   0  219m  17m  12m R 41.0  0.1  24:39.24 postmaster                                                                                                                       
18660 postgres  20   0  219m  14m 9.9m S 40.7  0.0  60:51.52 postmaster                                                                                                                       
18664 postgres  20   0  218m  15m  11m S 40.7  0.0  61:39.61 postmaster                                                                                                                       
17962 postgres  20   0  222m  19m  11m S 40.3  0.1  11:48.79 postmaster                                                                                                                       
18671 postgres  20   0  219m  14m   9m S 39.4  0.0  60:53.21 postmaster                                                                                                                       
26168 postgres  20   0  219m  15m  10m S 38.4  0.0  59:04.55 postmaster  


Total DISK READ: 0.00 B/s | Total DISK WRITE: 195.97 M/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND                                                                                                                        
17962 be/4 postgres    0.00 B/s   14.83 M/s  0.00 %  0.25 % postgres: aggw aggw [local] idle
17084 be/4 postgres    0.00 B/s   15.53 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
17963 be/4 postgres    0.00 B/s   15.00 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
17188 be/4 postgres    0.00 B/s   14.80 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
17964 be/4 postgres    0.00 B/s   15.50 M/s  0.00 %  0.24 % postgres: aggw aggw [local] idle
18664 be/4 postgres    0.00 B/s   15.13 M/s  0.00 %  0.23 % postgres: aggw aggw [local] idle
17088 be/4 postgres    0.00 B/s   14.71 M/s  0.00 %  0.13 % postgres: aggw aggw [local] idle
18688 be/4 postgres    0.00 B/s   14.72 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
24767 be/4 postgres    0.00 B/s   14.93 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
18671 be/4 postgres    0.00 B/s   16.14 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
17057 be/4 postgres    0.00 B/s   13.58 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
26168 be/4 postgres    0.00 B/s   15.50 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
18660 be/4 postgres    0.00 B/s   15.85 M/s  0.00 %  0.00 % postgres: aggw aggw [local] idle
Run Code Online (Sandbox Code Playgroud)

更新:很多文件写入似乎是针对 $PG_DATA/base/ 目录中的一些临时 (?) 文件。我对这里的文件结构的理解是,每个表基本上都存储为一个文件,文件名就是表的OID。然而,有大量名为 的文件tnn_nnnnnnn,而且这些文件似乎不断被写入(可能被覆盖)。这些文件有什么用?大约有 4700 个文件,大小均为 8K:

-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t12_1430975
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t16_1432736
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t28_1439066
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t24_1436243
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t24_1436210
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t19_1393372
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t28_1439051
-rw-------. 1 postgres postgres     8192 Jul  3 23:08 t8_1430334
Run Code Online (Sandbox Code Playgroud)

更新:在 postmaster 进程上运行 strace 基本上显示了很多文件 I/O 的东西:

open("base/16388/t24_1435947_fsm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435947_vm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435947", O_RDWR)  = 9
lseek(9, 0, SEEK_END)                   = 8192
ftruncate(9, 0)                         = 0
lseek(9, 0, SEEK_END)                   = 0
open("base/16388/t24_1435941", O_RDWR)  = 18
lseek(18, 0, SEEK_END)                  = 0
write(9, "\0\0\0\0\0\0\0\0\1\0\0\0000\0\360\37\360\37\4 \0\0\0\0b1\5\0\2\0\0\0"..., 8192) = 8192
lseek(18, 0, SEEK_END)                  = 0
close(9)                                = 0
open("base/16388/t24_1435947", O_RDWR)  = 9
lseek(9, 0, SEEK_END)                   = 8192
close(18)                               = 0
close(9)                                = 0
open("base/16388/t24_1435944_fsm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435944_vm", O_RDWR) = -1 ENOENT (No such file or directory)
open("base/16388/t24_1435944", O_RDWR)  = 9
lseek(9, 0, SEEK_END)                   = 0
close(9)                                = 0
Run Code Online (Sandbox Code Playgroud)

更新:所以这个问题似乎与临时表有关。我们更改了设置,因此临时表是“常规”表,所有磁盘活动都消失了,性能又回到了我预期的水平。现在,此更改只是一个快速而肮脏的测试:如果我们真的要更改为使用常规表,我们会遇到并发和清理问题。临时表真的那么邪恶,还是我们在滥用它们?

更新:一些更多的背景。我正在使用内部开发的基于语句的复制中间件。它已经相当成熟,并且已经在许多项目中使用了多年,但使用的是 MySQL。在过去的一两年中,我们一直在使用 PostgreSQL。我们基本上使用临时表作为复制机制的一部分。每当建立新连接时,我们都会为数据库中的每个表创建一个临时表。有 10-20 个(长寿命)连接和约 50 个表,这可能相当于很多临时表。所有临时表都是使用以下内容创建的:

CREATE TEMPORARY TABLE... ON COMMIT DELETE ROWS;
Run Code Online (Sandbox Code Playgroud)

临时表的语义非常适合我们的复制方案,并简化了我们必须用于 MySQL 的许多代码,但看起来实现也不太公平。根据我所做的一些研究,我认为临时表并不是真正适用于我们使用它们的功能。

我不是这个主题的内部专家(甚至不接近),只是它的用户,所以我的解释可能不是 100% 准确,但我认为它非常接近。

Læt*_*æti 0

如果您的服务器没有做好准备,那么使用临时表并拥有长期连接(可能涉及连接池)可能会成为一种负担。您可以尝试使用的一个 PostgreSQL 参数是temp_buffers控制分配给临时表的 RAM。这些临时缓冲区是按连接分配的,默认值 (8MB) 对于您的站点来说可能太低。

也许您还需要更改客户端应用程序的一些行为,具体取决于您使用临时表的方式。Stack Overflow 上有一个类似的问题,并且有一个很好的答案。