Saya memiliki tumpukan TileMill / PostGIS yang berjalan pada 8 inti Ubuntu 12,04 VM pada cloud OpenStack. Ini adalah pembangunan kembali sistem yang sangat mirip yang berjalan dengan baik pada perangkat keras yang sangat mirip (cloud yang sama, tetapi perangkat keras fisik yang berbeda, saya percaya) minggu lalu. Saya telah mencoba membangun kembali tumpukan persis sama seperti sebelumnya (menggunakan beberapa skrip yang saya buat).
Semuanya berjalan, tetapi database melakukan query dengan sangat lambat, yang memanifestasikan dirinya pada akhirnya dengan generasi ubin yang sangat lambat. Contoh kueri (hitung jumlah pub dalam radius setiap kota di Australia), yang sebelumnya membutuhkan waktu sekitar 10-20 detik sekarang membutuhkan waktu lebih dari 10 menit:
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
(Saya memasukkan kueri ini sebagai gejala, bukan secara langsung masalah yang harus dipecahkan. Kueri khusus ini hanya berjalan seminggu sekali atau lebih.)
Server memiliki 32 GB RAM, dan saya telah mengonfigurasi Postgres sebagai berikut (saran berikut ditemukan di web):
shared_buffers = 8GB
autovacuum = on
effective_cache_size = 8GB
work_mem = 128MB
maintenance_work_mem = 64MB
wal_buffers = 1MB
checkpoint_segments = 10
iostat
menunjukkan tidak ada yang sedang dibaca, sedikit data sedang ditulis (tidak tahu di mana atau mengapa), dan 95% CPU idle:
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
Output sampel dari 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
Sambil memegang erat-erat, saya memindahkan direktori data Postgres dari vda ke vdb tetapi tentu saja itu tidak membuat perbedaan.
Jadi saya bingung. Mengapa Postgres hanya menggunakan 5% CPU yang tersedia saat tidak menunggu I / O? Saya akan menyambut setiap saran untuk penyelidikan lebih lanjut, alat-alat lain, hal-hal acak untuk dicoba.
Memperbarui
Saya snapshotted server dan meluncurkannya di bagian berbeda dari cloud yang sama (zona ketersediaan berbeda). Hasilnya agak aneh. vmstat
pada server ini melaporkan penggunaan CPU 12% (yang sekarang saya pahami sebagai nilai yang diharapkan untuk satu query Postgres pada 8 core VM) - walaupun waktu eksekusi query sebenarnya hampir sama (630 detik vs 623).
Saya sekarang menyadari bahwa permintaan khusus ini mungkin bukan sampel yang bagus untuk alasan ini: hanya dapat menggunakan satu inti, dan ini merupakan update
(sedangkan rendering ubin hanya select
s).
Saya juga tidak memperhatikan explain
bahwa tampaknya planet_osm_polygon
tidak menggunakan indeks. Itu bisa jadi penyebabnya, jadi saya akan mengejar itu selanjutnya.
Pembaruan2
Masalahnya tampaknya adalah bahwa indeks planet_osm_polygon (es) sedang / tidak digunakan. Ada dua (satu dibuat oleh osm2pgsql, satu dibuat oleh saya mengikuti beberapa panduan acak):
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);
Statistik di planet_osm_polygon dan planet_osm_point cukup terbuka, saya pikir:
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
Jika saya membacanya dengan benar, Postgres telah mencari planet_osm_polygon sebanyak 1574 kali, tetapi tidak pernah benar-benar menemukan sesuatu, sehingga telah melakukan banyak sekali pencarian brute force.
Pertanyaan baru: mengapa?
Misteri terpecahkan
Berkat jawaban Frederik Ramm , jawabannya ternyata cukup sederhana: tidak ada indeks spasial, untuk beberapa alasan. Itu sepele untuk regenerasi mereka:
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);
Menjalankan kueri itu sekarang membutuhkan 4,6 detik. Indeks spasial penting! :)
sumber
Jawaban:
Menjalankan output Jelaskan Anlayze Anda melalui menjelaskan.depesz.com menyoroti bahwa sebagian besar kelambatan berasal dari tindakan ini:
Apakah itu diindeks sebelumnya? Bisakah Anda mengindeksnya sekarang?
Dengan mencari area masalah itu, saya juga menemukan tanya jawab terkait di situs Open Street Map:
sumber
PostgreSQL hanya dapat menggunakan satu inti untuk setiap kueri yang diberikan. Ini mencapai kinerja paralel yang baik dengan banyak permintaan bersamaan, tetapi tidak mendapat manfaat dari jumlah inti yang besar untuk beban kerja hanya beberapa permintaan yang sangat besar. Jadi, jika Anda hanya menjalankan kueri tunggal yang 5% tidak terlalu mengejutkan, meskipun saya harapkan 12% pada sistem 8-core.
Kurangnya iowait menunjukkan bahwa itu mungkin tidak menderita untuk disk I / O.
Jadi - tampaknya tidak mengalami hambatan pada CPU atau pada I / O.
Apakah mungkin kueri hanya diblokir untuk sementara waktu oleh kunci? Periksa
pg_stat_activity
kueri, dan gabung denganpg_locks
untuk melihat apakah ada kunci yang tidak diberikan. (Ada pertanyaan kalengan tentang pemantauan kunci Pg).Hal selanjutnya yang harus dilakukan adalah menjalankan beberapa tes sistem tingkat bawah. Jalankan
pg_test_fsync
, gunakan tes sysbench CPU dan I / O, dll. Jika kinerjanya buruk, naikkan ke penyedia hosting Anda.Anda juga harus mengumpulkan
perf top -a
output sebentar, lihat apa yang sebenarnya dilakukannya.sumber