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. vmstat
Auf 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 select
s ist).
Ich habe auch nicht bemerkt, explain
dass anscheinend planet_osm_polygon
kein 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! :) :)