Warum sitzt Postgres zu 95% im Leerlauf ohne Datei-E / A.

8

Ich habe einen TileMill / PostGIS-Stack, der auf einer 8-Kern-Ubuntu 12.04-VM in einer OpenStack-Cloud ausgeführt wird. Es ist ein Umbau eines sehr ähnlichen Systems, das letzte Woche auf sehr ähnlicher Hardware (gleiche Cloud, aber unterschiedliche physische Hardware, glaube ich) gut lief. Ich habe versucht, den Stapel genau so neu zu erstellen, wie er war (mithilfe einiger von mir erstellter Skripte).

Alles läuft, aber die Datenbank führt Abfragen unerträglich langsam aus, was sich letztendlich in einer sehr langsamen Kachelgenerierung äußert. Eine Beispielabfrage (zählen Sie die Anzahl der Pubs in einem Umkreis jeder Stadt in Australien), die zuvor etwa 10 bis 20 Sekunden dauerte, dauert jetzt mehr als 10 Minuten:

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

(Ich füge diese Abfrage als Symptom hinzu und nicht direkt als das zu lösende Problem. Diese spezielle Abfrage wird nur etwa einmal pro Woche ausgeführt.)

Der Server verfügt über 32 GB RAM und ich habe Postgres wie folgt konfiguriert (folgende Hinweise im Internet):

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

iostat zeigt an, dass nichts gelesen wird, ein bisschen Daten geschrieben werden (keine Ahnung, wo oder warum) und 95% CPU im Leerlauf:

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

Beispielausgabe von 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

Ich klammerte mich an Strohhalme und verschob das Postgres-Datenverzeichnis von vda nach vdb, aber das machte natürlich keinen Unterschied.

Ich bin also ratlos. Warum verwendet Postgres nur 5% der verfügbaren CPU, wenn es nicht auf E / A wartet? Ich würde mich über Vorschläge für weitere Untersuchungen, andere Tools und zufällige Versuche freuen.

Aktualisieren

Ich habe einen Snapshot des Servers erstellt und ihn in einem anderen Teil derselben Cloud (einer anderen Verfügbarkeitszone) gestartet. Die Ergebnisse waren etwas seltsam. vmstatAuf diesem Server wird eine CPU-Auslastung von 12% gemeldet (was ich jetzt als den erwarteten Wert für eine einzelne Postgres-Abfrage auf einer 8-Kern-VM verstehe) - obwohl die tatsächliche Ausführungszeit der Abfrage praktisch identisch ist (630 Sekunden gegenüber 623).

Mir ist jetzt klar, dass diese spezielle Abfrage aus diesem Grund wahrscheinlich kein gutes Beispiel ist: Sie kann nur einen Kern verwenden und es ist ein update(während das Rendern von Kacheln nur selects ist).

Ich habe auch nicht bemerkt, explaindass anscheinend planet_osm_polygonkein Index verwendet wird. Das könnte die Ursache sein, also werde ich das als nächstes verfolgen.

Update2

Das Problem scheint definitiv zu sein, dass die planet_osm_polygon-Indizes verwendet werden / nicht. Es gibt zwei (eine von osm2pgsql, eine von mir nach einer zufälligen Anleitung):

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);

Die Statistiken auf planet_osm_polygon und planet_osm_point sind ziemlich aufschlussreich, denke ich:

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

Wenn ich das richtig lese, hat Postgres 1574 Mal das planet_osm_polygon durchsucht, aber nie etwas gefunden, also eine lächerlich große Anzahl von Brute-Force-Suchen durchgeführt.

Die neue Frage: warum?

Geheimnis gelüftet

Dank der Antwort von Frederik Ramm ist die Antwort ziemlich einfach: Aus irgendeinem Grund gab es keinen räumlichen Index. Es war trivial, sie zu regenerieren:

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);

Das Ausführen dieser Abfrage dauert jetzt 4,6 Sekunden. Raumindizes sind wichtig! :) :)

Steve Bennett
quelle
Mir ist klar, dass dieser Eintrag ziemlich alt ist, aber ich habe ein ähnliches Problem. Ich kann planet_osm_polygon_point nicht zweimal erstellen, da der Index bereits vorhanden ist. Es spielt jedoch keine Rolle, wie der Index heißt, oder?
Sebastian Borggrewe
Nun, wenn der Index existiert, warum möchten Sie einen anderen erstellen? In jedem Fall können Sie die alte löschen oder die neue umbenennen.
Steve Bennett
Ich frage nur seit beiden Indizes: Erstelle den Index planet_osm_polygon_point auf planet_osm_polygon mit gist (way); Erstellen Sie den Index planet_osm_polygon_point auf planet_osm_point mit gist (way). heißen planet_osm_polygon_point, was wie ein Fehler erscheint, es sei denn, mir fehlt etwas.
Sebastian Borggrewe
Oh! Ich habe es nicht verstanden Ja, meine Antwort enthält einen Tippfehler.
Steve Bennett
Vielen Dank, Steve. Könnten Sie auch den Tippfehler in Ihrer Antwort korrigieren, um später darauf zurückgreifen zu können? Vielen Dank.
Sebastian Borggrewe

Antworten:

4

Wenn Sie Ihre Explain Anlayze-Ausgabe über EXPLAIN.depesz.com ausführen, wird hervorgehoben, dass der größte Teil der Langsamkeit auf diese Aktion zurückzuführen ist:

Seq Scan on planet_osm_polygon p 

Wurde das schon einmal indiziert? Können Sie es jetzt indizieren?

Bei der Suche nach diesem Problembereich habe ich auch auf einer Open Street Map-Website entsprechende Fragen und Antworten gefunden:

Mark Stosberg
quelle
Vielen Dank für den Hinweis - das habe ich verpasst. Es gibt tatsächlich zwei Indizes in dieser Tabelle. Aktualisierung meiner Frage mit weiteren Informationen.
Steve Bennett
Oh - dieser Link hatte die Antwort. Ja, obwohl es "einen Index" gab, befand er sich nur im ID-Feld, nicht im tatsächlichen Geometriefeld ("Weg") - also nutzlos für die räumliche Indizierung. Frederiks Kommentare enthielten die Antwort.
Steve Bennett
4

PostgreSQL kann nur einen Kern für eine bestimmte Abfrage verwenden. Es erzielt eine gute parallele Leistung bei vielen gleichzeitigen Abfragen, profitiert jedoch nicht von großen Kernzahlen für Workloads mit nur wenigen sehr großen Abfragen. Wenn Sie also nur eine einzige Abfrage ausführen, sind 5% nicht allzu überraschend, obwohl ich erwarten würde, dass sie auf einem 8-Kern-System 12% betragen.

Das Fehlen von iowait deutet darauf hin, dass es wahrscheinlich nicht unter Festplatten-E / A leidet.

Also - es scheint kein Engpass auf der CPU oder auf der E / A zu sein.

Ist es möglich, dass die Abfrage einfach zeitweise durch eine Sperre blockiert wird? Suchen Sie pg_stat_activitynach der Abfrage und verbinden Sie sich mit, pg_locksum festzustellen, ob nicht gewährte Sperren vorhanden sind. (Es gibt vordefinierte Abfragen zur Überwachung der Pg-Sperre).

Als Nächstes müssen Sie einige Systemtests auf niedrigerer Ebene ausführen. Führen pg_test_fsyncSie die CPU- und E / A-Tests von sysbench aus, verwenden Sie sie usw. Wenn diese ebenfalls schlecht funktionieren, wenden Sie sich an Ihren Hosting-Anbieter.

Sie sollten auch die perf top -aAusgabe für eine Weile sammeln , um zu sehen, was sie tatsächlich tut.

Craig Ringer
quelle