postgresql 維護與優化

原文:http://ruimemo.wordpress.com/2010/03/31/postgresql-performance-and-maintenance-%EF%BC%88postgres-%E4%BC%98%E5%8C%96%E4%B8%8E%E7%BB%B4%E6%8A%A4/


每次看postgresql的設定,好像每次都忘記。過一段時間又要看。今天終於決定,開始blog吧。

postgresql 優化與維護
1. 硬件

數據庫最重要的就是 I/O了。所以一切從I/O開始。
RAID: 這個基本不用說,數據庫放RAID10上面,只讀的備份數據庫可以放RAID0,反正掛了沒關係。謹記:數據庫是Random Read

RAID卡的選擇:
RAID卡一定要帶電池的纔可以(BBU)有電源的才能做到東西寫進 CACHE,RAID就返回硬盤寫成功(不用等)
1. Areca
2. LSI (真正的LSI,re-brand不要)
3. HP P400 以上系列

硬盤選擇:

首選是SAS: 15K RPM 每個SAS大約能提供25MB/s的Random Write。也就是說在RAID10的設定下,如果需要50MB/s的Random Write就需要4個硬盤

節儉選擇是: SATA 可以多用幾個硬盤(SAS一倍數量)達到在RAID10中接近SAS的速度。就算SATA買SAS一倍的數量,價格仍然比SAS便宜。
也可以買 產品: 例如 Compaq的 MSA 70 (P800 Battery backed RAID control)

CPU:64位
Cache:越大越好 (現在個人電腦都3M的cache了)
CORE:越多 越好 (postgresql畢竟是跑cpu的)建議最少4個core
RAM: 最少4G。通常根據具體需求,用16-64G的RAM
2. OS (系統)

可用系統:
1. Debian Stable
2. CentOS
3. Ubuntu LTS
4. Red Hat
5. SUSE Enterprise

如果準備付費(服務),那麼就是 Canonical, Novell 跟 Redhat這三家選擇而已

如果準備不買任何服務,可以用Debian, CentOS, Ubuntu LTS

這裏還是覺得系統用Red Hat (不付費就CentOS)畢竟人家是企業級的老大哥,錯不了。
* 現在CentOS也可以買到服務了。

不可用系統: 例如 fedora (redhat QA) ubuntu (non-LTS)
Scheduler:

Grub 增加: elevator=deadline

redhat 的圖標可以看出,deadline是數據庫的最佳選擇
文件系統 (Filesystem)

這裏的選擇是:ext2,ext3 跟 ext4。 爲什麼只考慮這幾個呢?因爲數據庫還是穩定第一,內核開發人員所做的文件系統,理論上說出問題的情況會少點。

WAL: 放ext2 因爲WAL本身自己有Journal了,不需要用ext3 (ext2快很多)
data: ext3

Block Size: postgres自己是8k的block size。所以文件系統也用8k的 block size。這樣才能最佳的提高系統的效能。

ext4:出來時間還 不夠長,不考慮。
分區 (Partitioning)

Postgres 跟系統 OS 應該在不同分區

系統(OS):系統應該放獨立的RAID1

數據庫 (Postgres Data):數據庫應該放獨立的RAID10上。 如果RAID是帶電池的,mount 的時候給 data=writeback的選項
獨立的數據庫分區,就不許要記錄文件時間了(都是放數據的)所以mount的時候要給noatime的 選項,這樣可以節約更新時間(timestamp)的I/O了。

WAL日誌(xlogs): 獨立的RAID1上 (EXT2 系統)日誌是 Sequential write,所以普通的硬盤(SATA)速度就足夠了,沒有必要浪費SAS在log上

Postgresql 日誌(logs):直接丟給syslog就可以。最好在syslog.conf中設定單獨的文件名. 這裏 例如用local2來做postgresql
local2.* -/var/log/postgres/postgres.log
記得log要給Async,這樣纔不會等卡在log的I/O上, 同時記得設定logrotate以及創建路徑(path)

ext2 VS ext3 性能測試:
HP DL585
4 Dual Core 8222 processors
64GB RAM
(2) MSA70 direct attached storage arrays.
25 spindles in each array (RAID 10)
HP P800 Controller
6 Disk in RAID 10 on embedded controller

xlog with ext3: avg = 87418.44 KB/sec
xlog with ext2: avg = 115375.34 KB/sec
3. Postgres 內存 (Memory Usage)

Shared Buffer Cache
Working Memory
Maintenance Memory
Shared Buffers

Postgres 啓動時要到的固定內存。每個allocation是8k。 Postgres不直接做硬盤讀寫,而是把硬盤中的東西放入Shared Buffers,然後更改Shared Buffers,在flush 到硬盤去。
通常 Shared Buffers設定爲內存(available memory)的25%-40%左右。
在系統(OS)中,記得設置 kernel.shmmax的值(/etc/sysctl.conf)
kernel.shmmax決定了進程可調用的最大共享內存數量。簡單的計 算方法是
kernel.shmmax=postgres shared_buffers + 32 MB
要保留足夠的空間(不然會out of memory)postgresql除了shared buffer還會用到一些其他的內存,例如max_connections, max_locks_pre_transaction
Working Memory

這個是postgres運行作業中 (task)需要的內存,例如內存內的hashed (aggregates, hash joins)sort (order by, distinct 等等)合理的設定,可以保證postgres在做這些東西的時候可以完全在內存內完成,而不需要把數據吐回到硬盤上去作swap。但是設定太大的話,會造 成postgres使用的內存大於實際機器的內存,這個時候就會去硬盤swap了。(效能下降)

working memory是per connection and per sort的設定。所以設定一定要非常小心。舉例來說,如果設定working memory爲32MB,那麼以下例子:
select * from lines, lineitems
where lines.lineid = lineitems.lineid
and lineid=6
order by baz;
這裏就可 能用到64MB的內存。
hashjoin between lines and lineitems (32MB)
order by baz (32MB)
要注意自己有多少query是用到了order by或者join
如果同時有100個鏈接,那麼就是 100 connection X 64MB = 6400MB (6G) 內存
通常來說,working mem不要給太大,2-4MB足夠

在postgres 8.3之後的版本,working mem可以在query中設定
Query:
begin;
set work_mem to ‘128MB’;
select * from foo order by bar;
insert into foo values (‘bar’);
reset work_mem;
commit;
Function:
create function return_foo() returns setof text as
$ select * from foo order by bar; $
SET work_mem to ‘128MB’
LANGUAGE ’sql’

postgres官方不建議(但是支持)在 postgresql.conf文件中更改work_mem然後HUP (數據庫應該沒有任何中斷)

利用 explain analyze可以檢查是否有足夠的work_mem
sort (cost=0.02..0.03 rows=1 width=0) (actual time=2270.744..22588.341 rows=1000000 loops=1)
Sort Key: (generate_series(1, 1000000))
Sort Method: external merge Disk:13696kb
-> Result (cost=0.00..0.01 rows=1 width=0) (actual time=0.006..144.720 rows=1000000 loops=1)
Total runtime: 3009.218 ms
(5 rows)
以上的 query分析顯示,這裏需要從硬盤走13MB的東西。所以這個query應給set work_mem到16MB才能確保性能。
Maintenance Memory (維護內存)

maintenance_work_mem 決定系統作維護時可以調用的內存大小。
這個也是同樣可以在query中隨時設定。
這個內存只有在VACUUM, CREATE INDEX 以及 REINDEX 等等系統維護指令的時候纔會用到。系統維護是,調用硬盤swap會大大降低系統效能。通常maintenance_work_mem超過1G的時候並沒有 什麼實際的效能增加(如果內存夠, 設定在1G足以)
Background Writer (bgwriter)

功能:
負責定時寫 shared buffer cache 中的 dirty shared buffers
好處:
a. 減少系統flush shared buffers到硬盤(已經被bgwriter做了)
b. 在checkpoint中,不會看到I/O的突然性暴增,因爲dirty buffers在背景中已經被flush進硬盤
壞處:
因爲一直定時在背後flush disk,會看到平均硬盤I/O怎加(好過checkpoint時I/O暴增)

設定:

bgwriter_delay:
sleep between rounds。 default 200(根據機器,數據而調整)

bgwriter_lru_maxpages:
決 定每次bgwriter寫多少數據。如果實際數據大於這裏的設定,那麼剩餘數據將會被postgres的進程(server process)來完成。server porcess自己寫的數據會造成一定的性能下降。如果想確定所有的數據都由bgwriter來寫,可以設定這裏的值爲-1

bgwriter_lru_multiplier:
採 用計算的方式來決定多少數據應該被bgwriter來寫。這裏保持內置的2.0就可以。

計算bgwriter的I/O:
1000 / bgwriter_delay * bgwriter_lru_maxpages * 8192 = 實際I/O
(8192是 postgres的8k block)
例如:
1000/200 * 100 * 8192 = 4096000 = 4000 kb

bgwrater 可以用 pg_stat_bgwriter 來監測。如果想要觀察bgwrater 的運行狀況,記得首先清理舊的stat信息。

bgwriter如果設定的太大(做太多事情)那麼就會影響到前臺的效能 (server)但是如果由系統(server)來做buffer flush同樣會影響效能。所以這裏的最好設定就是通過觀察 pg_stat_bgwriter 來找到一個最佳的平衡點。
WAL (write ahead log)

postgres中的所有寫動作都是首先寫入WAL,然後才執行的。這樣可以確保數據的準確跟 完整。當中途數據庫崩潰的時候,postgres可以通過WAL恢復到崩潰前的狀況而不會出現數據錯誤等等問題。
WAL 會在兩種情況下被回寫硬盤。
1. commit。 當commit數據的時候,WAL會被強制寫回硬盤(flush)並且所有這個commit之前的東西如果在WAL中,也會一同被flush。
2. WAL writer進程自己會定時回寫。

FSYNC vs ASYNC
postgres 的 default 是做 fsync,也就是說postgres會等待數據被寫入硬盤,纔會給query返回成功的信號。如果設定sync=no關閉fsync的話,postgres不會等待WAL會寫硬盤,就直接返回query成功。通常這個會帶來15-25%的性能提升。
但是缺點就是,如果系統崩潰 (斷電,postgres掛掉)的時候,你將有可能丟失最後那個transcation. 不過這個並不會造成你係統的數據結構問題。(no data corrupt)如果說在系統出問 題的時候丟失1-2筆數據是可以接受的,那麼25%的性能提升是很可觀的。

WAL設定:
fsync 可以選擇on或者off
wal_sync_method:
linux中是使用fdatasync。其他的。。。不知道,應該是看系統的文 件參數了
full_page_writes:
開啓的時候,在checkpoint之後的第一次對page的更改,postgres會將每 個disk page寫入WAL。這樣可以防止系統當機(斷電)的時候,page剛好只有被寫一半。打開這個選項可以保證page image的完整性。
關 閉的時候會有一定的性能增加。尤其使用帶電池的 RAID卡的時候,危險更低。這個選項屬於底風險換取性能的選項,可以關閉

wal_buffers:
WAL 的儲存大小。default 是 64 kb。 實驗證明, 設定這個值在 256 kb 到 1 MB 之間會提升效能。

wal_writer_delay
WAL 檢查WAL數據(回寫)的間隔時間。值是毫秒(milliseconds)
Checkpoints

確保數據回寫硬盤。dirty data page會被 flushed回硬盤。
checkpoint 由以下3中條件激發 (bgwriter如果設定,會幫忙在後臺寫入,所以就不會有checkpoint時候的短期高I/O出現)
1. 到達設定的WAL segments
2. 到達設定的timeout
3. 用戶下達checkpoint指令
如果 checkpoint運行頻率高於checkpint_warning值。postgres會在日誌(log)中記錄出來,通過觀察log,可以來決定 checkpoint_segments的設定。
增加cehckpoint_segments或者checkpoint_timeout可以有一 定的效能提升。而唯一的壞處就是如果系統掛了,在重啓的時需要多一點時間來回復(系統啓動回覆期間數據庫是不能用的)鑑於postgres很少掛掉,這個 其實可以設定的很長(1天都可以)

設定:
checkpoint_segments 最多的wal log數量,到達後會激發checkpoint,通常設定在30就好
checkpoint_timeout 一般設置15-20分鐘,常的可以設定1天也沒關係
checkpoint_completion_target 這個保持不動就好。內建是0.5,意思就是每個checkpoint預計在下個checkpoint完成前的一半時間內完成(聽起來有點繞嘴,呵呵)
checkpoint_warning 如果checkpint速度快於這個時間,在log中記錄。內建是30秒

理論中的完美設定,就是你的backend從來不用回寫硬盤。 東西都是由background來寫入的。這個就要靠調整bgwriter, checkpoints跟wal到一個最佳平衡狀態。當然這個是理想中的完美,想真的做到。。。繼續想吧。呵呵
4. 維護 – 保持postgres的笑容

維護數據庫是必 須的。基本維護
vacuum

delete數據的 時候,數據庫只是記錄這筆數據是‘不要的‘並不是真的刪除數據。所以這個時候就要vacuum了,vacuum會把標記爲‘不要‘的數據清除掉。這裏要注 意的是,vacuum不會清理index。當數據更改超過75%的時候,需要重新建立index。postgres 8.4 index可以用cluster重建速度快很多。在postgres 9.x中,vacuum=cluster,沒有任何區別了(保留cluster只是爲了兼容舊版指令)

Full Vacuum
這個會做exclusive lock。vacuum跟full vacuum的區別是vacuum會把標誌爲‘不要‘的空間標誌成可以再次使用(回收)而 full vacuum則會把這個空間刪除(返還給系統OS)所以vacuum之後你的postgres在硬盤上看到的佔用空間不會減少,但是full vacuum會減小硬盤佔用空間。不建議使用full vacuum,第一沒必要,第二exclusive lock不好玩。
ANALYZE

Analyze 會更新統計信息(statistics)所有的query的最佳方案,以及sql prepared statement都是靠這統計信息而決定的。所以當數據庫中的一定量數據變動後(例如超過10%),要作analyze,嚴格的說,這個是應該常做的東 西,屬於數據庫正常維護的一部分。另外一個很重要的就是,如果是 upload數據(restore那種)做完之後要記得作analyze(restore自動不給你作的)
當 建立新的table的時候,或者給table增加index,或者對table作reindex,或者restore數據進數據庫,需要手動跑 analyze纔可以。analyze直接影響default_statistics_target數據。
Autovacuum

根 據postgres的官方資料,autovacuum在8.3之後才變得比較真的實用(8.1推出的)因爲在8.3之前,autovacuum一次只能同 時做一個數據庫中的一個table。 8.3之後的版本,可以作多數據庫多table。

設定

log_autovacuum_min_duration:
-1 爲關閉。0是log全部。>0就是說超過這個時間的就log下來。例如設定爲30,那麼所有超過30ms的都會被日誌記錄。
autovacuum_max_workers:
同 時啓用的autovacuum進程。通常不要設定太高,3個就可以。
autovacuum_naptime:
檢查數據庫的時 間,default是1分鐘,不用改動
autovacuum_vacuum_threshold:
最低n行記錄纔會引發 autovacuum。也就是數據改變說低於這個值,autovacuum不會運行。default是50
autovacuum_analyze_threshold:
運 行analyze的最低值,跟上面的一樣
autovacuum_vacuum_scale_factor:
table中的百分比的計算方 式(超過一定百分比作vacuum)內建是20% (0.2)
autovacuum_analyze_scale_factor:
同上, 不過是analyze的設定
autovacuum_freeze_max_age:
最大XID出發autovacuum
autovacuum_vacuum_cost_delay:
延 遲。。如果系統負荷其他東西,可以讓vacuum慢點,保證其他東西的運行.這裏是通過延遲來限制
autovacuum_vacuum_cost_limit:
同 上,也是作限制的,這裏是通過cost限制limit
Cluster

Cluster 類似於vacuum full。建議使用cluster而不是vacuum full。cluster跟vacuum full一樣會重寫table,移除所有的dead row。同樣也是要做exclusive lock。
Truncate

Turncat 會刪除一個table中的所有數據, 並且不會造成任何的dead row(delete則會造成dead row)同樣的,turncate也可以用來重建table

begin;
lock foo in access exclusive mode;
create table bar as select * from foo;
turncate foo;
insert into foo (select * from bar);
commit;

這樣就重新清理了 foo這個table了。

REINDEX

重 新建立index
5. 其他
planner:

statistics直接決定planner的結 果。使用planner,那麼要記得確保statistics的準確(analyze)
default_statistics_target:

設定analyze分析的值。這個可以在 query中隨時設定更改
set default_statistics_target to 100;
analyze verbose mytable;
INFO: analyzing “aweber_shoggoth.mytable”
INFO: “mytable”: scanned 30000 of 1448084 pages, containing 1355449 live rows and 0 dead rows; 30000 rows in sample, 65426800 estimated total rows
ANALYZE

set default_statistics_target to 300;
analyze verbose mytable;
INFO: analyzing “aweber_shoggoth.mytable”
INFO: “mytable”: scanned 90000 of 1448084 pages, containing 4066431 live rows and 137 dead rows; 90000 rows in sample, 65428152 estimated total rows
ANALYZE
Set statistics per column 給不同的column設定不同的 statistics

alter table foo alter column bar set statistics 120
查找何時需要增加statistics

跑 個query作expain analyze
這個就會看到例如:
-> Seq Scan on bar (cost=0.00-52.00 rows=52 width=2 (actual time=0.007..1.894 rows=3600 loops=1)
這裏的rows應該跟真正的rows數量差不多才 是正確的。
seq_page_cost

planner 作sequential scan時候的cost。default是1,如果內存,cache,shared buffer設定正確。那麼這個default的值太低了,可以增加
random_page_cost

planner 作random page fetch的值。default是4.0 如果內存,cache,shared buffer設定正確,那麼這個值太高了,可以降低

seq_page_cost跟random_page_cost的值可以設定成一樣 的。然後測試效能,可以適當降低random_page_cost的值
cpu_operator_cost

default 是0.0025,測試爲,通常設定在0.5比較好
set cpu_operator_cost to 0.5;
explain analyze select ….
cpu_tuple_cost

default 是0.01 測試爲,通常設定在0.5比較好
set cpu_tuple_cost to 0.5;
explain analyze select …
effective_cache

應 該跟儘可能的給到系統free能接受的大小(越大越好)
total used free shared buffer cached
mem: xxxx yyyyy zzz aaaa bbbb cccc
設定的計算方法爲:
effective_cache=cached X 50% + shared
這裏的50%可以根據服務器的繁忙程度 在40%-70%之間調整。
監測方法:
explain analyze ;
set effective_cache_size=新的值;
explain analyze ;
reset effective_cache_size;
嘗試出一個最適合的值,就可以改postgresql.conf文件設定成固定了。
Natural vs Primary Key

Primary Key 基本因爲要做join,跟Natural相比多消耗20%左右的效能。所以盡力primary做在Natural key上。
Btree vs hash

btree 比 hash 快,不管什麼情況,所以不要用hash
gin vs gist

full text的時候,用gin不要用 gist
發佈了35 篇原創文章 · 獲贊 4 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章