Mengapa Postgres duduk diam 95%, tanpa file I / O?

8

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. vmstatpada 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 selects).

Saya juga tidak memperhatikan explainbahwa tampaknya planet_osm_polygontidak 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! :)

Steve Bennett
sumber
Saya menyadari bahwa entri ini cukup lama, namun saya mengalami masalah yang sama. Saya tidak dapat membuat planet_osm_polygon_point dua kali, karena indeks sudah ada. Namun tidak masalah apa yang disebut indeks, kan?
Sebastian Borggrewe
Nah jika indeksnya ada, mengapa Anda ingin membuat yang lain? Tetapi bagaimanapun juga, Anda bisa menjatuhkan yang lama atau mengganti nama yang baru.
Steve Bennett
Saya hanya bertanya karena kedua indeks: buat indeks planet_osm_polygon_point di planet_osm_polygon menggunakan inti (cara); buat indeks planet_osm_polygon_point di planet_osm_point menggunakan inti (cara); diberi nama planet_osm_polygon_point, yang tampaknya seperti kesalahan kecuali saya kehilangan sesuatu.
Sebastian Borggrewe
Oh! Saya tidak mengerti. Ya ada salah ketik dalam jawaban saya.
Steve Bennett
Terima kasih Steve, bisakah Anda juga memperbaiki kesalahan ketik dalam jawaban Anda untuk referensi di masa mendatang. Terima kasih.
Sebastian Borggrewe

Jawaban:

4

Menjalankan output Jelaskan Anlayze Anda melalui menjelaskan.depesz.com menyoroti bahwa sebagian besar kelambatan berasal dari tindakan ini:

Seq Scan on planet_osm_polygon p 

Apakah itu diindeks sebelumnya? Bisakah Anda mengindeksnya sekarang?

Dengan mencari area masalah itu, saya juga menemukan tanya jawab terkait di situs Open Street Map:

Mark Stosberg
sumber
Terima kasih telah menunjukkan ini - saya melewatkan itu. Sebenarnya ada dua indeks pada tabel ini. Memperbarui pertanyaan saya dengan info lebih lanjut.
Steve Bennett
Oh - tautan itu punya jawabannya. Ya, meskipun ada "indeks", itu hanya di bidang ID, bukan bidang geometri yang sebenarnya ("jalan") - jadi tidak berguna untuk pengindeksan spasial. Komentar Frederik berisi jawabannya.
Steve Bennett
4

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_activitykueri, dan gabung dengan pg_locksuntuk 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 -aoutput sebentar, lihat apa yang sebenarnya dilakukannya.

Craig Ringer
sumber