為什麼 Postgres 閒置 95%,沒有文件 I/O?
我有一個 TileMill/PostGIS 堆棧在 OpenStack 雲上的 8 核 Ubuntu 12.04 VM 上執行。這是一個非常相似的系統的重建,上週在非常相似的硬體(我相信相同的雲,但不同的物理硬體)上執行良好。我試圖重建與原來完全相同的堆棧(使用我建構的一些腳本)。
一切都在執行,但數據庫執行查詢的速度非常緩慢,這最終表現為非常緩慢的切片生成。一個範例查詢(計算澳大利亞每個城鎮半徑內的酒吧數量),以前需要大約 10-20 秒,現在需要 10 多分鐘:
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
(我將此查詢作為症狀包括在內,而不是直接解決要解決的問題。這個特定的查詢僅每週執行一次左右。)
伺服器有 32 GB 的 RAM,我已經按如下方式配置了 Postgres(遵循在網上找到的建議):
shared_buffers = 8GB autovacuum = on effective_cache_size = 8GB work_mem = 128MB maintenance_work_mem = 64MB wal_buffers = 1MB checkpoint_segments = 10
iostat
顯示沒有讀取任何內容,寫入了一些數據(不知道在哪里或為什麼),以及 95% 的空閒 CPU: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
範例輸出
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
緊抓著稻草,我將 Postgres 數據目錄從 vda 移動到 vdb,但當然這並沒有什麼不同。
所以我很茫然。為什麼 Postgres 在不等待任何 I/O 時只使用 5% 的可用 CPU?我歡迎任何關於進一步調查、其他工具、隨機嘗試的建議。
更新
我對伺服器進行了快照並在同一云的不同部分(不同的可用區)上啟動它。結果有點奇怪。
vmstat
在此伺服器上報告 12% 的 CPU 使用率(我現在將其理解為 8 核 VM 上單個 Postgres 查詢的預期值) - 儘管實際查詢執行時間幾乎相同(630 秒與 623 秒)。我現在意識到這個特定的查詢可能不是一個好的範例,因為這個原因:它只能使用一個核心,而且它是一個
update
(而圖塊渲染只是select
s)。我也沒有註意到
explain
顯然planet_osm_polygon
沒有使用索引。這很可能是原因,所以我接下來會追究。更新2
問題肯定似乎是planet_osm_polygon 索引(es)正在/沒有被使用。有兩個(一個由 osm2pgsql 創建,一個由我按照一些隨機指南創建):
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);
我認為planet_osm_polygon 和planet_osm_point 的統計數據非常具有啟發性:
行星osm_polygon:
Sequential Scans 194204 Sequential Tuples Read 60981018608 Index Scans 1574 Index Tuples Fetched 0
行星osm_point:
Sequential Scans 1142 Sequential Tuples Read 12960604 Index Scans 183454 Index Tuples Fetched 43427685
如果我沒看錯的話,Postgres 已經搜尋了 planet_osm_polygon 1574 次,但實際上從未找到任何東西,所以進行了大量的蠻力搜尋。
新問題:為什麼?
謎團已揭開
感謝Frederik Ramm 的回答,答案變得相當簡單:由於某種原因,沒有空間索引。再生它們是微不足道的:
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);
現在執行該查詢需要 4.6 秒。空間索引很重要!:)
通過 explain.depesz.com執行您的Explain Anlayze 輸出會突出顯示大部分緩慢來自此操作:
Seq Scan on planet_osm_polygon p
以前有索引嗎?你現在可以索引它嗎?
通過搜尋該問題區域,我還在 Open Street Map 網站上找到了相關問答:
對於任何給定的查詢,PostgreSQL 只能使用一個核心。它通過許多並發查詢實現了良好的並行性能,但對於僅幾個非常大的查詢的工作負載並沒有受益於大核心數。因此,如果您只執行一個查詢,那麼 5% 就不足為奇了,儘管我希望它在 8 核系統上為 12%。
缺少 iowait 表明它可能不會受到磁碟 I/O 的影響。
所以 - 它似乎沒有在 CPU 或 I/O 上出現瓶頸。
查詢是否有可能被鎖簡單地阻塞了一段時間?檢查
pg_stat_activity
查詢,並加入pg_locks
以查看是否有任何未授予的鎖。(有關於 Pg 鎖監控的罐頭查詢)。接下來要做的是執行一些較低級別的系統測試。執行
pg_test_fsync
,使用 sysbench 的 CPU 和 I/O 測試等。如果這些測試也表現不佳,請向您的託管服務提供商提出。您還應該收集
perf top -a
一些輸出,看看它實際上在做什麼。