1. 程式人生 > >PostgreSQL 硬件性能調優

PostgreSQL 硬件性能調優

arm 送去 con order 數據庫管理 困難 warn 文件io 提高效率

PostgreSQL 硬件性能調優

翻譯自文章《PostgreSQL Hardware Performance Tuning》

PostgreSQL是一個由世界範圍內開發人員在互聯網上開發的對象-關系型數據庫。她是商業數據庫如Oracle和Informix一個開源替代。

PostgreSQL最初由加大伯克利分校開發。在1996年,一個團隊開始在互聯網上開發這個數據庫。他們通過郵件來交流思想並且通過文件服務器來共享代碼。PostgresSQL現在在專業特性、性能、可靠性上比得上商業數據庫。她具有事務、視圖、存儲過程、引用一致性約束。她支持許多編程接口,包括ODBC、Java(JDBC)、TCL/TK、PHP、Perl和Python。得益於一大批有才幹的網絡開發者,PostgreSQL 繼續以驚人的速度提升 。

性能概念

有兩個方面的數據庫性能調優。一個是提高數據庫服務器使用的CPU、內存、磁盤驅動。第二個是優化發送到數據庫的查詢。這篇文章討論硬件方面的性能調優。查詢優化可以通過SQL命令如 CREATE INDEX、VACUUM 、VACUUM FULL、ANALYZE、CLUSTER 和 EXPLAIN 來完成。這些在《PostgreSQL:Introduction and Concepts》中討論在 http://momjian.us/main/writings/pgsql/aw_pgsql_book/。

為了理解硬件調優問題,理解計算機裏正在發生什麽是非常重要的。簡單來說,計算機可以想象成一個被存儲包圍著的CPU。在和CPU同一芯片上是幾個用來存儲中間結果和不同指針和計數的CPU寄存器。在這些周圍是用來保存最近訪問信息的CPU緩存。在CPU緩存外面是大量的用來保存正在執行程序和數據的隨機訪問主存(RAM)。在主存的外面是存儲更多信息的磁盤驅動。磁盤驅動是唯一的持久存儲區,所以任何要在關機後保持的信息都必須放在那裏。總之,在CPU的周圍有這些存儲:
技術分享圖片

存儲區域 度量單位
CPU 寄存器 bytes
CPU 緩存 kilobytes
RAM megabytes
磁盤驅動 gigabytes

你可以看到距離CPU越遠存儲越大。理論上,大量的持久存儲可以放在CPU旁邊,但是會特別慢且比較昂貴。在實踐中,經常被使用的信息存儲在CPU旁邊,不經常訪問的信息存儲遠離CPU,當使用時被帶到CPU。

保持信息靠近CPU

在不同存儲區之間移動信息是自動發生的。編譯器決定哪些信息保存在寄存器中。CPU芯片邏輯保證最近使用的信息保存在CPU緩存中。操作系統控制哪些信息存儲在RAM並在磁盤驅動器間來回穿梭。

CPU寄存器和CPU緩存不能被數據庫管理員有效的調優。有效的數據庫調優涉及在RAM中增加有用的信息,來盡可能的阻止磁盤訪問。

你可能認為這很容易,但是不是。計算機的RAM包含很多東西:

  • 正在執行的程序
  • 程序數據和棧
  • PostgreSQL shared buffer cache
  • 內核磁盤緩存
  • 內核

合適的調優包括在RAM中盡可能多的保存數據庫信息,同時不影響操作系統的其他區域

PostgreSQL Shared Buffer Cache

技術分享圖片

PostgreSQL 不直接更改磁盤上的信息。相反,它請求讀數據到PostgreSQL shared buffer cache。PostgreSQL後臺來讀和寫這些塊,並且最終刷到磁盤上。

需要訪問表的後臺先在緩存中查找需要的塊。如果它們已經存在,可以馬上繼續處理。如果沒有,一個操作系統請求被發送去加載這些塊。這些塊從內核磁盤緩存或者直接從磁盤加載。這可能是昂貴的操作。

多大算太大?

技術分享圖片

你可能想,“我把全部的RAM都給PostgreSQL shared buffer cache”。然而,如果你那樣做,會沒有其他的空間分配給內核和其他任何要運行的程序。合適的PostgreSQL shared buffer cache 是不產生其他不良活動的最大空間。

為了理解不良活動,你需要去理解UNIX 操作系統怎麽管理內存。如果有足夠的內存去裝進所有的程序和數據,只需要很少的內存管理。然而,如果所有東西不能裝進內存,內核開始強制內存刷出到叫swap磁盤區域。它把最近沒有使用的內存頁移出。這個操作叫做swap pageout。Pageouts 不是問題因為它們發生在非活動時間段。糟糕的是當這些頁必須從swap返回時,意為著移到swap的舊頁必須移入RAM。這種叫 swap pagin。這種情況糟糕因為當頁從swap移動時,程序必須暫停直到pagein完成。

Pagein 活動可以被系統分析工具如vmstat和sar展示,並且暗示沒有足夠的內存去有效運行。不要混淆swap pageins和ordinary pageins。它包含的頁是作為的正常的操作系統讀取文件系統的一部分。如果你不能發現swap pageins,許多pageouts 是一個好的暗示,你也正在進行swap pageins。

緩存大小的影響

你可能好奇為什麽緩存大小如此重要。首先,假設PostgreSQL shared buffer cache 足夠大去裝下整個表。這張表的重復順序掃描不需要訪問磁盤,因為所有的數據已經在緩存中了。現在假設緩存比表小一個塊大小。這個表的順序掃描需要加載所有的表數據塊進入緩存直到最後一個。當需要塊時,最老的塊被移出,這種情況就是表的第一個塊。當另外一個順序掃描發生時,第一個塊已經不在緩存中,需要把它重新裝入,這時最老的塊,也就是這個表的第二個塊被移出緩存。這又會把下一個需要的塊繼續推出去直到這個表的最後。這是一個極端的例子,但是你可以明白減少一個塊可以把緩存的效率從100%變為0%。它展示了找到正確的緩存大小可以極大的影響性能。

合適的Shared Buffer Cache大小

理想的,PostgreSQL shared buffer cache 應該是:

  • 足夠大能裝入經常訪問的表
  • 足夠小能避免swap pageins活動

記住postmaster分配所有的共享內存在它啟動的時候。這片區域保持相同的大小即使沒有一個人訪問數據庫。一些操作系統pageout不涉及共享內存,一些鎖定主存中的共享內存。鎖定共享內存是推薦的。PostgreSQL管理員指南有關於各種操作系統內核參數配置信息。

批量排序內存大小

另外一個調優的參數是批量排序使用的內存大小。當排序大表或者結果集,PostgresSQL會分成幾部分排序它們,把中間結果放到臨時文件中。這些文件合並並且重新排序直到所有的行完成排序。增加批量大小能減少臨時文件且經常能加快排序。然而,如果批量排序太大,它們會引起pageins,因為在排序時一部分批量排序pageout到swap區。這種情況下使用更小的批量排序和更多的臨時文件是更快的。所以再次,swap pageins 指示已經分配了太多的內存。記住每個後臺排序如ORDER BY,CREATE INDEX,或者merge join都使用這個參數。有幾個並行的排序會使用幾倍的這個內存大小。

緩存大小和排序大小

緩存大小和排序大小都影響內存使用,所以你不可能最大化一個而不影響另一個。記住緩存大小在postmaster啟動是分配,而排序大小由正在執行的排序操作的數量決定。通常,緩存大小比排序大小更重要。然而,可預見的使用ORDER BY ,CREATE INDEX或者merge joins的確定查詢可以被大的批量排序大小加速。

同時,很多操作系統限制了多少共享內存可以分配。增加這些限制需要操作系統相關的知識去重新編譯或者重新配置內核。更多的信息可以在PostgreSQL管理員指南中找到。

作為調優的起點,如果只有一些大的會話,用15%的主存作為緩存大小,2-4%作為排序大小。如果有很多小的會話可以調的更小。你可以嘗試增加他們去看是否有性能提升同時沒有swap發生。如果shared buffer cache太大,你會浪費維護太多緩存的管理開銷,並且占用其他進程和額外的內核磁盤緩存的RAM。

一個有價值的參數是effective_cache_size。調優者使用這個參數去估計內核磁盤緩存的大小。在不固定緩存大小的內核中,這個參數可以設置成未使用RAM的平均大小,因為這些內核使用未使用的RAM去緩存最近訪問的磁盤頁。在其他固定大小磁盤緩存的內核中,通常應該把你的內核緩存設置成10%RAM大小。

磁盤局限性

技術分享圖片

磁盤驅動的物理特性導致了不同於文章中提到的其他存儲區域的性能特點。其他的存儲區域可以以相同速度訪問任何字節。磁盤驅動有它自己的自旋盤和移動頭,訪問在磁頭附近的數據比距離遠的數據快的多。

移動磁頭去盤面的另外磁柱需要花費一些時間。Unix開發者知道這個特性。當排序磁盤上的大文件,他們嘗試把文件的各個條放在一起。例如,假設一個文件需要10個磁盤塊。操作系統可能把1-5塊放在一個磁柱上,6-10塊放在另外磁柱上。如果這個文件需要從頭讀到未,只需要磁頭移動兩次。--一次獲取1-5塊的磁柱,一次獲取6-10塊。然而,如果文件不是順序讀,如塊1,6,2,7,3,8,4,9,5,10;需要10次磁頭移動。你可以看到,在磁盤上,順序讀比隨機讀快很多。這是為什麽如果一個表的大部分內容需要被讀,PostgreSQL偏向於順序掃描而不是索引掃描。這也凸顯了緩存的價值。

多磁盤Spindles

磁頭在數據庫活動期間移動相當多。如果產生太多的讀寫請求,驅動會變得飽和,導致性能不佳。(vmstat和sar可以提供每個磁盤活動量的信息)

一個磁盤飽和的解決方法是移動一些PostgreSQL的數據文件到其他磁盤。記著,移動文件到同一磁盤的其他文件系統沒有幫助。所有在同一磁盤的文件系統使用同一個磁頭。

通過磁盤驅動的數據庫訪問可以通過以下幾個方法加速:
移動數據庫、表、索引
表空間允許你在不同的驅動上創建對象。
移動WAL
initdb -X 和符號連接可以用來移動pg_xlog目錄到不同的磁盤驅動。不像其他的寫操作,PostgreSQL 寫日誌必須在事務完成前刷到磁盤。緩存不能用來推遲這些寫操作。為寫日誌使用單獨的磁盤可以允許磁頭停留在當前日誌的磁柱而沒有移動延遲。(你可以使用postgres -F 參數來阻止日誌刷到磁盤,但是一個操作系統災難需要從備份中恢復)

其他的選項包括使用磁盤陣列,通過多個磁盤驅動加速一個文件系統。鏡像會降低數據庫寫速度,但是會加速數據庫讀,因為數據可以從每個驅動中獲得。許多站點使用RAID1+0或RAID0+1,因為它同時提供了性能和可靠的優勢。RAID5對於6個或者更多驅動來說是更快的。理論上,RAID 5將有一個由電池支持的高速緩存,因此寫入可以以一種有效的方式刷新到磁盤,而不是在編寫文件的時候減慢應用程序的速度。

磁盤驅動緩存

現代磁盤驅動都有讀和寫緩存。讀緩存保證最近請求的磁盤塊在磁盤內存中可用。寫緩存保存寫請求直到它們可以有效的存儲到盤面上。你可能意識到這可能產生問題--如果磁盤斷電了,當它持有的寫數據還沒寫到磁盤上怎麽辦?一些磁盤驅動和RAID控制器有後備電池寫緩存來保證數據安全,且當電源完全恢復時把數據寫到盤面。然而,大部分驅動沒有這種特性,因此它們是不可靠的。

幸運的是,在大多數驅動你可以關閉寫緩存。SCSI驅動默認關閉寫緩存。IDE設備寫緩存通常是打開的,但是可以從操作系統命令關閉如hdparm -W0,sysctl hw.ata.wc=0或者scsimd。但是,一些IDE驅動雖然報告寫緩存關閉了,但是仍在使用它,這是不可靠的。沒有精確的測試很難判斷哪個驅動在撒謊。

因為PostgreSQL每個事務提交時使用fsync()寫WAL日誌到磁盤,並且等待寫完成。當使用寫緩存時用戶能看到巨大的性能提升。因此,為了性能和可靠性,如果PostgreSQL能使用有後備電池的寫緩存是一個理想的方案。

SCSI vs IDE

SCSI驅動通常比IDE驅動貴很多。SCSI驅動有一個協議用來在操作系統和控制器間通信,然而IDE驅動簡單的多且同一時刻只能接受一個請求。有標記隊列的SCSI驅動可以接受多個請求並且重新排列它們提高效率。這是為什麽當單用戶或者單文件IO時SCSI和IDE驅動有相似的性能特性,但是當多個用戶或者進程請求時SCSI比IDE性能更好。因此,SCSI更適合重負載數據庫服務器。

實際上,SCSI或IDE是唯一的方法區分兩種主要的驅動:企業驅動,為高性能和高可靠設計。個人電腦驅動,為最小耗費設計。這篇文章http://www.seagate.com/content/docs/pdf/whitepaper/D2c_More_than_Interface_ATA_vs_SCSI_042003.pdf,做了優秀的工作來描述在生產基於性能可靠性或者減小耗費的驅動。它是一個優秀的指導在選擇基於這些特性的驅動。

文件系統

一些操作系統支持多磁盤文件系統。在這種情況,可能很難知道哪個文件系統表現最好。PostgreSQL通常在傳統的Unix文件系統表現最好,像很多操作系統支持的BSD UFS/FFS等。UFS默認的8K塊大小和PostgreSQL的頁大小一樣。你可以運行在日誌和基於日誌的文件系統,但是這些會在WAL的fsync執行期間引起額外的開銷。老的基於SvR3的文件系統變的太碎片難以有好的性能。

因為有許多文件系統可以選擇並且沒有一個是最優的,Linux上的文件系統選擇是特別困難的:ext2不是完全的災難安全的,ext3,XFS和JFS是基於日誌的且Reiser是對小文件優化且記錄日誌。雖然ext2比日誌文件系統塊很多,但是當要求災難恢復時ext2是不可選的。如果必須使用ext2,使用sync enabled掛載。一些人推薦使用ext3時用data=writeback掛載。

不推薦PostgreSQL使用NFS和其他遠程文件系統。NFS和本地文件系統沒有一樣的文件系統特性,這些不一致可能引起數據可靠和災難恢復問題。

多CPU

PostgreSQL使用多進程模型,意為著每個數據庫連接擁有它自己的unix進程。因此,所有多CPU操作系統可以通過可用的CPU來加速多數據庫連接。然而,如果只有一個數據庫連接是活動的,它只能使用一個CPU。PostgreSQL沒有使用多線程模型從而允許一個進程使用多個CPU。

檢查點

當WAL文件充滿時,一個檢查點被執行來強制所有的臟緩存刷到磁盤,從而使日誌文件可以循環。檢查點也會在固定的時間間隔被執行,通常是5分鐘。如果有很多的數據庫寫活動,WAL段會很塊被充滿,導致所有磁盤緩存被刷到磁盤引起系統過度的緩慢。

檢查點

檢查點應該每幾分鐘發生一次。如果在一分鐘發生幾次,性能會變差。在服務日誌中查找"checkpoint_warning"消息來決定你的檢查點是否執行太頻繁。如果30秒內檢查點執行超過一次,會出現這個消息。

減小檢查點的頻率包括增加在data/pg_xlog中WAL文件的數量。每個文件是16 megabyte,所以它影響磁盤使用率。默認的配置使用了最小數量的日誌文件。為了減小檢查點頻率,你需要增加這個參數:

checkpoint_segments=3

默認值是3。增加它直到檢查點幾分鐘出現一次。另外一個可能出現的消息是:
LOG:XLogWrite:new log file created - consider increasing WAL_FILES
這個消息暗示postgresql.conf中的wal_files參數需要增加。

結論

幸運的是,PostgreSQL 不需要太多調優。大部分參數自動調整到最佳性能。緩存大小和排序大小是兩個參數管理員能夠控制去更好的利用可用內存。磁盤訪問可以通過多個驅動加速。其他參數可能設置在share/postgresql.conf.sample。你可以copy到data/postgresql.conf去實驗其他PostgreSQL更奇異的參數。

PostgreSQL 硬件性能調優