Perché Postgres è inattivo al 95%, senza I / O di file?


8

Ho uno stack TileMill / PostGIS in esecuzione su una VM Ubuntu 12.04 a 8 core su un cloud OpenStack. È la ricostruzione di un sistema molto simile che funzionava bene su hardware molto simile (stesso cloud, ma credo che hardware fisico diverso) la scorsa settimana. Ho provato a ricostruire lo stack esattamente come era (usando alcuni script che avevo creato).

Tutto funziona, ma il database sta eseguendo query in modo lancinante lentamente, che alla fine si manifesta con una generazione di piastrelle molto lenta. Una query di esempio (contare il numero di pub nel raggio di ogni città in Australia), che in precedenza richiedeva qualcosa come 10-20 secondi, ora impiega più di 10 minuti:

explain (analyze, buffers) update places set pubs = 
(select count(*) from planet_osm_point p where p.amenity = 'pub' and st_dwithin(p.way,places.way,scope)) +
(select count(*) from planet_osm_polygon p where p.amenity = 'pub' and st_dwithin(p.way,places.way,scope)) ;
 Update on places  (cost=0.00..948254806.93 rows=9037 width=160) (actual time=623321.558..623321.558 rows=0 loops=1)
   Buffers: shared hit=132126300
   ->  Seq Scan on places  (cost=0.00..948254806.93 rows=9037 width=160) (actual time=68.130..622931.130 rows=9037 loops=1)
         Buffers: shared hit=132107781
         SubPlan 1
           ->  Aggregate  (cost=12.95..12.96 rows=1 width=0) (actual time=0.187..0.188 rows=1 loops=9037)
                 Buffers: shared hit=158171
                 ->  Index Scan using planet_osm_point_index on planet_osm_point p  (cost=0.00..12.94 rows=1 width=0) (actual time=0.163..0.179 rows=0 loops=9037)
                       Index Cond: (way && st_expand(places.way, (places.scope)::double precision))
                       Filter: ((amenity = 'pub'::text) AND (places.way && st_expand(way, (places.scope)::double precision)) AND _st_dwithin(way, places.way, (places.scope)::double precision))
                       Buffers: shared hit=158171
         SubPlan 2
           ->  Aggregate  (cost=104917.24..104917.25 rows=1 width=0) (actual time=68.727..68.728 rows=1 loops=9037)
                 Buffers: shared hit=131949237
                 ->  Seq Scan on planet_osm_polygon p  (cost=0.00..104917.24 rows=1 width=0) (actual time=68.138..68.716 rows=0 loops=9037)
                       Filter: ((amenity = 'pub'::text) AND (way && st_expand(places.way, (places.scope)::double precision)) AND (places.way && st_expand(way, (places.scope)::double precision)) AND _st_dwithin(way, places.way, (places.scope)::double precision))
                       Buffers: shared hit=131949237
 Total runtime: 623321.801 ms

(Includo questa query come sintomo, non direttamente il problema da risolvere. Questa query specifica viene eseguita solo una volta alla settimana).

Il server ha 32 GB di RAM e ho configurato Postgres come segue (seguendo i consigli trovati sul web):

shared_buffers = 8GB
autovacuum = on
effective_cache_size = 8GB
work_mem = 128MB
maintenance_work_mem = 64MB
wal_buffers = 1MB
checkpoint_segments = 10

iostat non mostra nulla da leggere, un po 'di dati vengono scritti (non ho idea di dove o perché) e CPU inattiva al 95%:

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5.40    0.00    0.00    0.11    0.00   94.49

Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
vda               0.20         0.00         0.80          0          8
vdb               2.30         0.00        17.58          0        176

Esempio di output da vmstat:

  procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
...
 1  0      0 18329748 126108 12600436    0    0     0    18  148  140  5  0 95  0
 2  0      0 18329400 126124 12600436    0    0     0     9  173  228  5  0 95  0

Stringendo a botte, ho spostato la directory dei dati di Postgres da vda a vdb, ma ovviamente non ha fatto differenza.

Quindi sono in perdita. Perché Postgres utilizza solo il 5% della CPU disponibile quando non è in attesa di alcun I / O? Gradirei qualsiasi suggerimento per ulteriori indagini, altri strumenti, cose casuali da provare.

Aggiornare

Ho eseguito l'istantanea del server e l'ho avviato su una parte diversa dello stesso cloud (una zona di disponibilità diversa). I risultati sono stati un po 'strani. vmstatsu questo server riporta un utilizzo della CPU del 12% (che ora intendo come il valore atteso per una singola query Postgres su una VM a 8 core), sebbene il tempo di esecuzione della query effettivo sia praticamente identico (630 secondi contro 623).

Ora mi rendo conto che questa particolare query non è probabilmente un buon esempio per questo motivo: può usare solo un core ed è un update(mentre il rendering delle piastrelle è solo selects).

Inoltre non ho notato explainche apparentemente planet_osm_polygonnon sta usando un indice. Potrebbe essere la causa, quindi lo inseguirò dopo.

Update2

Il problema sembra sicuramente essere che gli indici planet_osm_polygon siano / non vengano utilizzati. Ce ne sono due (uno creato da osm2pgsql, uno creato da me seguendo una guida casuale):

CREATE INDEX idx_planet_osm_polygon_tags
  ON planet_osm_polygon
  USING gist
  (tags);


CREATE INDEX planet_osm_polygon_pkey
  ON planet_osm_polygon
  USING btree
  (osm_id);

Le statistiche su planet_osm_polygon e planet_osm_point sono piuttosto rivelatrici, penso:

planet_osm_polygon:

Sequential Scans    194204  
Sequential Tuples Read  60981018608 
Index Scans 1574    
Index Tuples Fetched    0

planet_osm_point:

Sequential Scans    1142    
Sequential Tuples Read  12960604    
Index Scans 183454  
Index Tuples Fetched    43427685

Se ho letto bene, Postgres ha cercato il pianeta_osm_polygon 1574 volte, ma in realtà non ha mai trovato nulla, quindi ha fatto un numero ridicolmente elevato di ricerche di forza bruta.

La nuova domanda: perché?

Mistero risolto

Grazie alla risposta di Frederik Ramm , la risposta risulta abbastanza semplice: per qualche motivo non esisteva un indice spaziale. È stato banale rigenerarli:

create index planet_osm_polygon_polygon on planet_osm_polygon using gist(way);
create index planet_osm_polygon_point on planet_osm_point using gist(way);

L'esecuzione di quella query ora richiede 4,6 secondi. Gli indici spaziali contano! :)


Mi rendo conto che questa voce è piuttosto vecchia, tuttavia sto riscontrando un problema simile. Non riesco a creare planet_osm_polygon_point due volte, poiché l'indice esiste già. Tuttavia, non importa come si chiama l'indice, giusto?
Sebastian Borggrewe,

Bene, se l'indice esiste, perché vuoi crearne un altro? Ma in ogni caso, potresti abbandonare quello vecchio o rinominare quello nuovo.
Steve Bennett,

Lo sto chiedendo da entrambi gli indici: crea indice planet_osm_polygon_point su planet_osm_polygon usando gist (way); creare un indice planet_osm_polygon_point su planet_osm_point usando gist (way); sono chiamati planet_osm_polygon_point, che sembra un errore se non mi manca qualcosa.
Sebastian Borggrewe,

Oh! Non ho capito Sì, c'è un refuso nella mia risposta.
Steve Bennett,

Grazie Steve, potresti anche correggere l'errore nella tua risposta per riferimento futuro. Grazie.
Sebastian Borggrewe,

Risposte:


4

L'esecuzione dell'output di Explain Anlayze tramite spiegato.depesz.com evidenzia che la maggior parte della lentezza deriva da questa azione:

Seq Scan on planet_osm_polygon p 

È stato indicizzato prima? Puoi indicizzarlo adesso?

Cercando quell'area problematica, ho anche trovato una relativa domanda e risposta in un sito di Open Street Map:


Grazie per averlo sottolineato - mi è mancato. Ci sono infatti due indici su questa tabella. Aggiornamento della mia domanda con maggiori informazioni.
Steve Bennett,

Oh - quel link ha avuto la risposta. Sì, sebbene esistesse "un indice", era solo sul campo ID, non sul campo della geometria reale ("way"), quindi inutile per l'indicizzazione spaziale. I commenti di Frederik contenevano la risposta.
Steve Bennett,

4

PostgreSQL può utilizzare un solo core per una determinata query. Raggiunge buone prestazioni in parallelo con molte query simultanee, ma non beneficia di grandi conteggi di core per carichi di lavoro di solo un paio di query molto grandi. Quindi, se stai eseguendo una sola query, il 5% non è poi così sorprendente, anche se mi aspetto che sia il 12% su un sistema a 8 core.

La mancanza di iowait suggerisce che probabilmente non soffre di I / O su disco.

Quindi - non sembra essere strozzato su CPU o I / O.

È possibile che la query venga semplicemente bloccata per un certo periodo da un lucchetto? Controlla pg_stat_activityla query e unisciti a pg_locksper vedere se ci sono blocchi non concessi. (Esistono query fisse per il monitoraggio del blocco Pg).

La prossima cosa da fare è eseguire alcuni test di sistema di livello inferiore. Esegui pg_test_fsync, usa i test I / O e CPU di sysbench, ecc. Se anche questi funzionano miseramente, alzalo con il tuo provider di hosting.

Dovresti anche raccogliere l' perf top -aoutput per un po ', vedere cosa sta realmente facendo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.