2015-04-07 14 views
11

Ho un server che esegue Postgres 9.1.15. Il server ha 2 GB di RAM e non lo scambio. Intermittently Postgres inizierà a ricevere errori di "memoria insufficiente" su alcuni SELECT e continuerà a farlo finché non riavvio Postgres o alcuni dei client che sono connessi ad esso. La cosa strana è che quando ciò accade, free riporta ancora oltre 500 MB di memoria libera.Postgres perde gli errori di memoria nonostante abbia un sacco di memoria libera

select version();:

PostgreSQL 9.1.15 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit 

uname -a:

Linux db 3.2.0-23-virtual #36-Ubuntu SMP Tue Apr 10 22:29:03 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux 

postgresql.conf (tutto il resto è commentata/default):

max_connections = 100 
shared_buffers = 500MB 
work_mem = 2000kB 
maintenance_work_mem = 128MB 
wal_buffers = 16MB 
checkpoint_segments = 32 
checkpoint_completion_target = 0.9 
random_page_cost = 2.0 
effective_cache_size = 1000MB 
default_statistics_target = 100 
log_temp_files = 0 

ho ottenuto questi valori da pgtune (I ha scelto "tipi di applicazioni misti") e ha continuato a giocherellare li basati su ciò che ho letto, senza fare molti progressi reali. Al momento ci sono 68 connessioni, che è un numero tipico (non sto ancora utilizzando pgbouncer o qualsiasi altro gestore di connessione).

/etc/sysctl.conf:

kernel.shmmax=1050451968 
kernel.shmall=256458 

vm.overcommit_ratio=100 
vm.overcommit_memory=2 

prima ho cambiato overcommit_memory-2 una quindicina di giorni fa, dopo il killer OOM ha ucciso il server Postgres. In precedenza il server funzionava bene da molto tempo. Gli errori che ottengo ora sono meno catastrofici ma molto più fastidiosi perché sono molto più frequenti.

Non ho avuto molta fortuna nell'individuare il primo evento che causa il postgres "fuori dalla memoria" - sembra essere diverso ogni volta. Il momento più recente si è schiantato, le prime tre righe registrati sono stati:

2015-04-07 05:32:39 UTC ERROR: out of memory 
2015-04-07 05:32:39 UTC DETAIL: Failed on request of size 125. 
2015-04-07 05:32:39 UTC CONTEXT: automatic analyze of table "xxx.public.delayed_jobs" 
TopMemoryContext: 68688 total in 10 blocks; 4560 free (4 chunks); 64128 used 
[... snipped heaps of lines which I can provide if they are useful ...] 

--- 

2015-04-07 05:33:58 UTC ERROR: out of memory 
2015-04-07 05:33:58 UTC DETAIL: Failed on request of size 16. 
2015-04-07 05:33:58 UTC STATEMENT: SELECT oid, typname, typelem, typdelim, typinput FROM pg_type 
2015-04-07 05:33:59 UTC LOG: could not fork new process for connection: Cannot allocate memory 
2015-04-07 05:33:59 UTC LOG: could not fork new process for connection: Cannot allocate memory 
2015-04-07 05:33:59 UTC LOG: could not fork new process for connection: Cannot allocate memory 
TopMemoryContext: 396368 total in 50 blocks; 10160 free (28 chunks); 386208 used 
[... snipped heaps of lines which I can provide if they are useful ...] 

--- 

2015-04-07 05:33:59 UTC ERROR: out of memory 
2015-04-07 05:33:59 UTC DETAIL: Failed on request of size 1840. 
2015-04-07 05:33:59 UTC STATEMENT: SELECT... [nested select with 4 joins, 19 ands, and 2 order bys] 
TopMemoryContext: 388176 total in 49 blocks; 17264 free (55 chunks); 370912 used 

L'incidente, prima che, poche ore prima, aveva solo tre istanze di tale ultima query come le prime tre righe del disastro. Quella query viene eseguita molto spesso, quindi non sono sicuro se i problemi sono perché di questa query, o se compare appena nel log degli errori perché è un SELECT ragionevolmente complesso che viene eseguito sempre. Detto questo, ecco un EXPLAIN ANALYZE di esso: http://explain.depesz.com/s/r00

Questo è ciò che ulimit -a per l'utente postgres assomiglia:

core file size   (blocks, -c) 0 
data seg size   (kbytes, -d) unlimited 
scheduling priority    (-e) 0 
file size    (blocks, -f) unlimited 
pending signals     (-i) 15956 
max locked memory  (kbytes, -l) 64 
max memory size   (kbytes, -m) unlimited 
open files      (-n) 1024 
pipe size   (512 bytes, -p) 8 
POSIX message queues  (bytes, -q) 819200 
real-time priority    (-r) 0 
stack size    (kbytes, -s) 8192 
cpu time    (seconds, -t) unlimited 
max user processes    (-u) 15956 
virtual memory   (kbytes, -v) unlimited 
file locks      (-x) unlimited 

Cercherò di ottenere il numero esatto dalla free la prossima volta che c'è un incidente, nel frattempo questo è un braindump di tutte le informazioni che ho.

Qualche idea su dove andare da qui?

+0

per quanto ne so il kernel deve promettere di memoria per i processi se è allocata, anche se sono mai intenzione di usarlo. Ciò include le regioni di memoria copy-on-write 'fork()' ed del postmaster. Quindi, anche se la memoria è libera nel senso di non essere attualmente mappata nello spazio degli indirizzi di un processo, viene commessa. Credo. Potrei essere totalmente sventolante qui. È anche possibile che alcune delle stranezze del kernel riguardo alla contabilità della memoria condivisa siano in discussione. –

+1

'maintenance_work_mem = 128 MB 'sembra abbastanza grande se si considerano i limiti di memoria. Il fatto che il problema si verifichi quando viene eseguita un'analisi automatica, indica anche che questo parametro è troppo grande. –

+0

@a_horse_with_no_name Ho provato a impostarlo su '16MB'. Riferirà i risultati. Qualcos'altro da cercare nel frattempo? –

risposta

2

È possibile verificare se è disponibile memoria di scambio quando si verifica un errore?

Ho rimosso completamente la memoria di scambio nel mio desktop Linux (solo per testare altre cose ...) e ho ottenuto esattamente lo stesso errore! Sono abbastanza sicuro che questo è ciò che sta succedendo anche a te.

+0

Ho ricevuto questo messaggio e anch'io ho scambiato .. Potrebbe essere il motivo di questo errore ... – alfonx

3

Mi sono imbattuto in questo stesso problema con un file SQL di solo testo da 2,5 GB che stavo cercando di ripristinare. Ho ridimensionato il mio server Digital Ocean fino a 64 GB di RAM, creato un file di scambio da 10 GB e riprovato. Ho ricevuto un errore di memoria esaurita con 50 GB gratuiti e nessuno swap in uso.

Ho ridimensionato il mio server alla piccola istanza da 1 GB che stavo usando (richiedendo un riavvio) e ho pensato di dargli un altro scatto per nessun'altra ragione di quanto non fossi frustrato. Ho iniziato l'importazione e mi sono reso conto di aver dimenticato di creare nuovamente il mio file di scambio temporaneo.

L'ho creato nel bel mezzo dell'importazione. psql lo ha reso un lotto ulteriormente prima di bloccarsi. Ha superato 5 tavoli aggiuntivi.

Penso che ci sia un bug che alloca memoria in psql.

1

È un po 'diffidente segnalare la stessa dimensione di memoria disponibile della dimensione shared_buffers. Sei sicuro di avere i valori giusti?

uscita di free comando al momento della caduta sarebbe utile così come il contenuto di/proc/meminfo

Attenzione che l'impostazione overcommit_memory-2 non è così efficace se si vede la overcommit_ratio a 100. Sarà fondamentalmente limita l'allocazione della memoria allo scambio di dimensioni (0 in questo caso) + 100% della RAM fisica, che non tiene conto di alcuno spazio per la memoria condivisa e le cache del disco.

probabilmente si dovrebbe impostare overcommit_ratio a 50.

+0

Penso che sia solo una coincidenza nel modo in cui ho scritto la domanda. Era più di 500mb gratis (come in "cumuli di memoria!") Piuttosto che un valore difficile. Detto questo, penso che sia un buon punto sul 'overcommit_ratio' - ci penserò. –

Problemi correlati