Postmaster utiliza CPU excesiva y escrituras en disco

9

usando PostgreSQL 9.1.2

Veo un uso excesivo de la CPU y grandes cantidades de escrituras en el disco desde las tareas de postmaster. Esto sucede incluso mientras mi aplicación no está haciendo casi nada (10s de inserciones por MINUTO). Sin embargo, hay un número razonable de conexiones abiertas.

He estado tratando de determinar qué está causando esto en mi aplicación. Soy bastante nuevo con postgresql, y hasta ahora no he llegado a ningún lado. Encendí algunas opciones de registro en mi archivo de configuración y miré las conexiones en la tabla pg_stat_activity, pero todas están inactivas. Sin embargo, cada conexión consume ~ 50% de CPU y escribe ~ 15M / s en el disco (sin leer nada).

Básicamente estoy usando el stock postgresql.conf con muy pocos ajustes. Agradecería cualquier consejo o sugerencia sobre lo que puedo hacer para rastrear esto.

Aquí hay una muestra de lo que me muestra 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

Actualización : Gran parte de la escritura del archivo parece estar en algunos archivos temporales (?) En el directorio $ PG_DATA / base /. Comprendo la estructura del archivo aquí es que cada tabla se almacena básicamente como un archivo cuyo nombre es el OID de la tabla. Sin embargo, hay toneladas de archivos nombrados tnn_nnnnnnn, y son estos archivos los que parecen estar escritos (quizás reescritos) constantemente. ¿Para qué son estos archivos? Hay ~ 4700 de los archivos, y todos tienen un tamaño de 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

Actualización : ejecutar strace en los procesos de postmaster básicamente muestra muchas cosas de E / S de archivos:

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

Actualización : por lo tanto, este problema parece tener que ver con tablas temporales. Cambiamos nuestra configuración para que las tablas temporales sean tablas 'regulares', y toda la actividad del disco desapareció, y el rendimiento volvió a donde esperaba que estuviera. Ahora, este cambio fue solo una prueba rápida y sucia: si realmente vamos a cambiar para usar tablas regulares, tenemos problemas con la concurrencia y la limpieza. ¿Las tablas temporales son realmente tan malvadas o las estamos abusando?

Actualización : un poco más de fondo. Estoy utilizando un middleware de replicación basado en sentencias desarrollado internamente . Es bastante maduro y ha estado en uso en varios proyectos durante varios años, pero usando MySQL. Solo hemos estado trabajando con PostgreSQL durante el último año o dos. Esencialmente estábamos usando las tablas temporales como parte del mecanismo de replicación. Cada vez que se establece una nueva conexión, creamos una tabla temporal para cada tabla en la base de datos. Con 10-20 conexiones (de larga duración) y ~ 50 tablas, esto puede equivaler a muchas tablas temporales. Todas las tablas temporales se crearon con:

CREATE TEMPORARY TABLE... ON COMMIT DELETE ROWS;

La semántica de las tablas temporales encaja muy bien con nuestro esquema de replicación, y simplificó mucho el código que tuvimos que usar para MySQL, pero parece que la implementación no fue tan buena. Por el poco de investigación que he hecho, no creo que las tablas temporales estén realmente destinadas a la función para la que las estábamos usando.

No soy el experto interno (ni siquiera cercano) en este tema, solo un usuario del mismo, por lo que mi explicación puede no ser 100% precisa, pero creo que está bastante cerca.

Wolfcastle
fuente
3
Su comprensión está un poco desactualizada, si mira la documentación oficial , encontrará que "... para relaciones temporales, el nombre del archivo tiene el formato tBBB_FFF, donde BBB es el ID del backend del backend que creó el archivo , y FFF es el número de filenode. ... "
Milen A. Radev
Wow, ese es un subsistema de E / S de disco con buen rendimiento. ¿Qué dice strace sobre lo que los trabajadores están haciendo realmente?
womble
@ MilenA.Radev, por lo que parece que podría estar haciendo algo extraño / excesivo con tablas temporales. Esto es interesante. Tengo muchos desencadenantes que hacen uso de tablas temporales. Voy a mirar más de cerca a estos.
wolfcastle
@womble, he actualizado la pregunta con salida de strace.
wolfcastle
¿Realmente estás experimentando un problema de rendimiento?
voretaq7

Respuestas:

1

Su configuración de PostgreSQL está muy lejos. Esto fue sospechoso por tu publicación inicial,

 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

De 32 GB en su servidor, ~ 25 GB son gratuitos, excluyendo ~ 575 MB de búfer.

Desde su archivo postgresql.conf,

 shared_buffers = 32MB                   # min 128kB                               
 #temp_buffers = 8MB                     # min 800kB
 #max_prepared_transactions = 0          # zero disables the feature
 ...
 #work_mem = 1MB                         # min 64kB
 #maintenance_work_mem = 16MB            # min 1MB
 #max_stack_depth = 2MB   

Supongo que esta es una base de datos dedicada. Si es así, cámbielo a los siguientes parámetros y vuelva a cargar / reiniciar,

 shared_buffers = 16GB                   # min 128kB                               
 temp_buffers = 128MB                     # min 800kB
 #max_prepared_transactions = 0          # zero disables the feature
 ...
 work_mem = 8MB                         # min 64kB
 maintenance_work_mem = 64MB            # min 1MB
 max_stack_depth = 4MB   

Hágame saber cómo esto cambia su rendimiento y puede ajustarlo aún más según sea necesario.

Con respecto a las tablas no registradas, si sus tablas temporales contienen datos temporales que son efímeros y, como mencionó, se crean en la sesión, es mejor usar tablas no registradas.

Puede truncar sus tablas después de la sesión si eso es aceptable.

Más información aquí: http://michael.otacoo.com/postgresql-2/unlogged-table-performance-in-postgresql-9-1/

No estoy seguro de por qué necesita tablas temporales para la replicación. ¿No puedes usar la replicación de transmisión PostgreSQL?

Chida
fuente
0

Usar tablas temporales y tener conexiones de larga data (probablemente la agrupación de conexiones está involucrada) puede ser una carga si su servidor no está preparado para ello. Un parámetro de PostgreSQL con el que puede intentar jugar es el temp_buffersque controla la RAM asignada a las tablas temporales. Esos búferes temporales se asignan por conexión y el valor predeterminado (8 MB) es probablemente demasiado bajo para su sitio.

Tal vez también necesite cambiar un poco el comportamiento de su aplicación cliente, dependiendo de cómo use sus tablas temporales. Hay una pregunta similar con una buena respuesta en Stack Overflow .

Tonin
fuente
Tendré que preguntarle a mi experto interno si intentamos ajustar el valor temp_buffers o no (probamos muchas cosas diferentes). La pregunta a la que apunta no se aplica realmente ya que no estamos usando tablas temporales de esa manera. He actualizado la pregunta con más detalles.
Wolfcastle
Gracias por la actualización de la pregunta y por el archivo postgresql.conf, eso es lo que debemos tratar de mejorar en esta situación. Estoy de acuerdo con la respuesta de @Chida que está en línea con lo que sugerí wrt temp_buffers. ¿También puede decirnos cuál es el tamaño de la base de datos que está tratando de replicar? ¿Cuántas tablas, tamaño medio por tabla y tamaño total de la base de datos?
Tonin
0

¿Podría publicar su archivo postgresql.conf? Su postgresql parece estar significativamente menos optimizado.

¿Podrías también publicar:

  • Si está utilizando tablas no registradas para sus tablas temporales?

  • ¿Cuántos discos y en qué configuración RAID?

Chida
fuente
He puesto el archivo postgresql.conf aquí . Yo creo que no se puede crear una tabla que es a la vez temporal y no talado. Hay 6 discos de 1 TB en un RAID 1 + 0 (almacenamiento total de 3 TB)
wolfcastle