PostgreSQL數據庫啟動時,會先啟動一個叫做Postmaster的主進程,還會fork一些輔助子進程,這些輔助子進程各自負責一部分功能,輔助子進程分類如下:
$ ps -ef | grep postgres postgres 2162 1 0 May23 ? 00:01:01 /usr/local/pgsql/bin/postmaster -D /usr/local/pgsql/data postgres 2346 2162 0 May23 ? 00:00:00 postgres: logger process postgres 2804 2162 0 May23 ? 00:00:10 postgres: checkpointer process postgres 2805 2162 0 May23 ? 00:00:14 postgres: writer process postgres 2806 2162 0 May23 ? 00:00:25 postgres: wal writer process postgres 2807 2162 0 May23 ? 00:00:43 postgres: autovacuum launcher process postgres 2808 2162 0 May23 ? 00:00:05 postgres: archiver process postgres 2809 2162 0 May23 ? 00:01:15 postgres: stats collector process
1. Postmaster進程
主進程Postmaster是整個數據庫實例的總控制進程,負責啟動和關閉數據庫實例,用戶可以運行postmaster,postgres命令加上合適的參數啟動數據庫,實際上,postmaster命令是一個指向postgres的鏈接.
$ ls -lh /usr/local/pgsql/bin/post* -rwxr-xr-x 1 postgres dba 6.4M Jun 24 2016 /usr/local/pgsql/bin/postgres lrwxrwxrwx 1 postgres dba 8 Jun 24 2016 /usr/local/pgsql/bin/postmaster -> postgres
更多時候我們使用pg_ctl啟動數據庫,pg_ctl也是通過運行postgres來啟動數據庫,它只是做了一些包裝,讓我們更容易啟動數據庫,所以,主進程Postmaster實際是第一個postgres進程,此進程會fork一些與數據庫實例相關的輔助子進程,並管理他們.
當用戶與PostgreSQL數據庫建立連接時,實際上是先與Postmaster進程建立連接,此時,客戶端程序會發出身份證驗證的消息給Postmaster進程,Postmaster主進程根據消息中的信息進行客戶端身份驗證,如果驗證通過,它會fork一個子進程postgres為這個連接服務,fork出來的進程被稱為服務進程,查詢pg_stat_activity表可以看到的pid,就是這些服務進程的pid.
postgres=# select pid from pg_stat_activity;
pid ------ 3279 4449 3411 (3 rows) $ ps -ef | egrep "3279|3363|3411|4352" postgres 3279 1366 0 09:55 ? 00:00:00 postgres: contentreader TnGeo-Here-Data 172.16.60.57(64716) idle postgres 3411 1366 0 09:58 ? 00:00:00 postgres: aceuser TnGeo-Here-Data 172.16.40.14(64017) idle
當某個服務出現錯誤的時候,Postmaster主進程會自動完成系統的修復,修復過程中會停掉所有的服務進程,然后進行數據庫數據的一致性恢復,等待恢復完成后,數據庫又可以接受新的連接了.
2. SysLogger進程
日志信息是數據庫管理員獲取數據庫系統運行狀態的有效手段。在數據庫出現故障時,日志信息是非常有用的。把數據庫日志信息集中輸出到一個位置將極大方便管理員維護數據庫系統。然而,日志輸出將產生大量數據(特別是在比較高的調試級別上),單文件保存時不利於日志文件的操作。因此,在SysLogger的配置選項中可以設置日志文件的大小,SysLogger會在日志文件達到指定的大小時關閉當前日志文件,產生新的日志文件。在postgresql.conf里可以配置日志操作的相關參數:
log_destination:配置日志輸出目標,根據不同的運行平台會設置不同的值,Linux下默認為stderr。
logging_collector:是否開啟日志收集器,當設置為on時啟動日志功能;否則,系統將不產生系統日志輔助進程。
log_directory:配置日志輸出文件夾。
log_filename:配置日志文件名稱命名規則。
log_rotation_size:配置日志文件大小,當前日志文件達到這個大小時會被關閉,然后創建一個新的文件來作為當前日志文件。
此外,postgresql.conf中還提供了其他配置參數,可以根據需要進行設置。
3. BgWriter進程
BgWriter是PostgreSQL中在后台將臟頁寫出到磁盤的輔助進程,引入該進程主要為達到如下兩個目的:首先,數據庫在進行查詢處理時若發現要讀取的數據不在緩沖區中時要先從磁盤中讀入要讀取的數據所在的頁面,此時如果緩沖區已滿,則需要先選擇部分緩沖區中的頁面替換出去。如果被替換的頁面沒有被修改過,那么可以直接丟棄;但如果要被替換的頁已被修改,則必需先將這頁寫出到磁盤中后才能替換,這樣數據庫的查詢處理就會被阻塞。通過使用BgWriter定期寫出緩沖區中的部分臟頁到磁盤中,為緩沖區騰出空間,就可以降低查詢處理被阻塞的可能性。其次,PostgreSQL在定期作檢查點時需要把所有臟頁寫出到磁盤,通過BgWriter預先寫出一些臟頁,可以減少設置檢查點(CheckPoint,數據庫恢復技術的一種)時要進行的IO操作,使系統的IO負載趨向平穩。通過BgWriter對共享緩沖區寫操作的統一管理,避免了其他服務進程在需要讀入新的頁面到共享緩沖區時,不得不將之前修改過的頁面寫出到磁盤的操作。不過,當BgWriter無法維護足夠的干凈共享緩沖區時,其他服務進程仍然可以自行完成將臟頁寫回磁盤的操作。BgWriter同時也負責處理所有的檢查點,它也會定期地發出一個檢查點請求,當然也可以由其他進程通過信號要求BgWriter執行一個檢查點。
BgWriter是PostgreSQL 8.0以后新加的特性,但在8.2以前版本中,使用BgWriter需要管理員進行很復雜的配置。在PostgreSQL 8.4中,數據庫配置文件postgresql.conf中與BgWriter相關的配置選項有3個:bgwriter_delay、bgwriter_lru_maxpages、bgwriter_lru_multiplier。系統每隔bgwriter_delay指定的時間啟動BgWriter。BgWriter從后向前掃描緩沖區的LRU鏈表,寫出至多bgwriter_lru_multiplier*N個臟頁,並且不超過bgwriter_lru_maxpages值的限制。其中N是最近一段時間在兩次BgWriter運行期間系統新申請的緩沖頁數。在BgWriter參數的配置中,如果BgWriter過於頻繁地將臟頁寫出,則經常被更新的數據頁很可能會被一次又一次地寫出到磁盤上,反而增加了數據庫的IO次數,進而導致系統性能下降。另一方面,若BgWriter寫周期過長,又不能起到優化數據庫寫IO操作的作用。因此確定BgWriter以什么速率將臟頁寫出才能達到最佳效果需要綜合考慮系統的實際運行狀態,默認將bgwriter_delay設置為200毫秒,bgwriter_lru_maxpages設置為100,bgwriter_lru_multiplier設置為2.0。
4. WalWriter進程
預寫式日志WAL(Write Ahead Log,也稱為Xlog)的中心思想是對數據文件的修改必須是只能發生在這些修改已經記錄到日志之后,也就是先寫日志后寫數據。如果遵循這個過程,那么就不需要在每次事務提交的時候都把數據塊刷回到磁盤,因為在出現崩潰的情況下可以用日志來恢復數據庫。使用WAL主要的好處就是顯著地減少了寫磁盤的次數,因為在日志提交的時候只需要把日志文件刷新到磁盤,而不是事務修改的所有數據文件。在多用戶環境里,許多事務的提交可以用日志文件的一次fsync來完成。而且日志文件是順序寫的,因此同步日志的開銷遠比同步數據塊的開銷要小。WalWriter是Postgres 8.3以后才新加入的新特性,它避免了其他服務進程在事務提交時需要同步地寫入預寫式日志到磁盤,也使得事務提交記錄不是在提交時同步地寫入磁盤,而是在一個已知的預先設置的時間異步地寫入。同BgWriter一樣,其他服務進程在WalWriter出錯時也允許直接進行預寫日志寫操作。
WAL日志文件存放在數據集簇中的pg_xlog目錄里。它是作為一個段文件的集合存儲的,每個段16MB,並分割成若干頁,每頁8KB。日志記錄頭格式在xlog.h里描述。日志內容取決於它記錄的事件的類型。一個段文件的名字由24個十六進制字符組成,分為三個部分,每個部分由8個十六進制字符組成。第一部分表示時間線,第二部分表示日志文件標號,第三部分表示日志文件的段標號。時間線由1開始,日志文件標號和日志文件的段標號由0開始,所以系統中的第一個事務日志文件是000000010000000000000000,第二個事務日志文件是000000010000000000000001。目前這些數字不能循環使用(不過要把所有可用的數字都用光也需要非常長的時間)。
WAL的緩沖區和控制結構在共享內存里,它們是用輕量的鎖保護的,對共享內存的需求由緩沖區數量決定,默認的WAL緩沖區大小是8個8KB的緩沖區(即64KB)。出於安全考慮,可以將日志文件和數據文件分別存儲在不同的磁盤上,可以通過把pg_xlog目錄移動到另外一個位置,然后在數據集簇里原來的位置創建一個指向新位置的符號鏈接來實現。
在PostgreSQL數據庫的系統配置文件postgresql.conf中有如下參數可以配置WAL的屬性:
fsync:該參數直接控制日志是否先寫入磁盤。默認值是ON(先寫入),表示更新數據寫入磁盤時系統必須等待WAL的寫入完成。可以配置該參數為OFF,表示更新數據寫入磁盤完全不用等待WAL的寫入完成。
synchronous_commit:參數配置是否等待WAL完成后才返回給用戶事務的狀態信息。默認值是ON,表明必須等待WAL完成后才返回事務狀態信息;配置成OFF能夠更快地反饋回事務狀態。
wal_sync_method:WAL寫入磁盤的控制方式,默認值是fsync,可選用值包括open_datasync、fdatasync、fsync_writethrough、fsync、open_sync。open_datasync和open_sync分別表示在打開WAL文件時使用O_DSYNC和O_SYNC標志;fdatasync和fsync分別表示在每次提交時調用fdatasync和fsync函數進行數據寫入,兩個函數都是把操作系統的磁盤緩存寫回磁盤,但前者只寫入文件的數據部分,而后者還會同步更新文件的屬性;fsync_writethrough表示在每次提交並寫回磁盤會保證操作系統磁盤緩存和內存中的內容一致。
full_page_writes:表明是否將整個page寫入WAL。
wal_buffers:用於存放WAL數據的內存空間大小,系統默認值是64K,該參數還受wal_writer_delay、commit_delay兩個參數的影響。
wal_writer_delay:WalWriter進程的寫間隔時間,默認值是200毫秒,如果時間過長可能造成WAL緩沖區的內存不足;時間過短將會引起WAL的不斷寫入,增加磁盤I/O負擔。
commit_delay:表示一個已經提交的數據在WAL緩沖區中存放的時間,默認值是0毫秒,表示不用延遲;設置為非0值時事務執行commit后不會立即寫入WAL中,而仍存放在WAL緩沖區中,等待WalWriter進程周期性地寫入磁盤。
commit_siblings:表示當一個事務發出提交請求時,如果數據庫中正在執行的事務數量大於commit_siblings值,則該事務將等待一段時間(commit_delay的值);否則該事務則直接寫入WAL。系統默認值是5,該參數還決定了commit_delay的有效性。
結合WAL日志和數據文件可以實現PostgreSQL數據庫的在線備份和恢復。使用這種備份恢復方法時,我們可能要經常性地把數據文件、WAL日志文件保存到另外一個存儲設備上。數據庫文件拷貝和日志歸檔文件可以用於災難恢復,每次做歸檔以后,過時的日志文件就可以刪除。PostgreSQL提供了一種dump方式備份數據庫文件,完成此工作的pg_dump工具存放在安裝目錄的子目錄bin下。
5. PgArch進程
ostgreSQL從8.x版本開始提出了PITR(Point-In-Time-Recovery)技術,支持將數據庫恢復到其運行歷史中任意一個有記錄的時間點。除2.5.3節中所述的WalWriter外,PITR的另一個重要的基礎就是對WAL文件的歸檔功能。PgArch輔助進程的目標就是對WAL日志在磁盤上的存儲形式(Xlog文件)進行歸檔備份。
PostgreSQL在數據集簇的pg_xlog子目錄中始終只使用一個WAL日志文件,這個日志文件記錄數據庫中數據文件的每個改變。從邏輯上來看,PostgreSQL數據庫會產生一個無限長的順序的WAL記錄序列。PostgreSQL在物理上把這個WAL記錄序列分割成多個WAL文件(每個WAL文件為一個WAL段),通常每個段的大小為16MB(在編譯PostgreSQL時可以通過編譯選項改變這個大小)。每個段文件的名字是一個數字,用來反映它們在WAL序列中的位置。即使不進行WAL歸檔,PostgreSQL也會創建一些WAL段文件。但是只會使用其中一個來記錄WAL日志,如果當前使用的WAL段文件超過了大小限制,則會關閉當前段文件,然后把另外一個可重復使用的段文件作為當前段文件來使用。能夠被重復使用的段文件必須保證其中的內容都在最后一次檢查點之前產生並保證其中的內容都寫入磁盤中。在這種情況下,被保存下來的將只有部分WAL日志,因此也不能實現任意歷史時間點的恢復。為實現PITR,需要在WAL段文件被重用時進行歸檔備份操作,把將被重用的WAL段中的日志記錄保存到其他位置。這樣歸檔日志加上當前日志就可以形成連續的WAL日志記錄。為了給數據庫管理員提供最大的靈活性,PostgreSQL不對如何歸檔做任何假設,而是讓管理員提供一個shell命令來拷貝一個完整的WAL段文件到備份存儲位置。該命令可以就是一個cp命令,或者是一個復雜的shell腳本,所有的操作都由管理員決定。
在postgresql.conf中與預寫式日志歸檔相關的屬性有:
archive_mode:表示是否進行歸檔操作,默認值為off(關閉)。
archive_command:由管理員設置的用於歸檔WAL日志的命令。
archive_time:表示歸檔周期,在超過該參數設定的時間時強制切換WAL段,默認值為0(表示禁用該功能)。
為允許歸檔,需要把postgresql.conf配置文件中的wal_level參數設置為“archive”或“hot_standby”,archive_mode參數設置為“on”,並為archive_command命令指定一個shell命令。在用於歸檔的命令中,預定義變量“%p”用來指代需要歸檔的WAL全路徑文件名,“%f”表示不帶路徑的文件名(這里的路徑都是相對於當前工作目錄的路徑)。每個WAL段文件歸檔時將調用archive_command所指定的命令。當歸檔命令返回0時,PostgreSQL就會認為文件被成功歸檔,然后就會刪除或循環使用該WAL段文件。否則,如果返回一個非零值,PostgreSQL會認為文件沒有被成功歸檔,便會周期性地重試直到成功。
為了標識各個段文件的狀態,PostgreSQL在數據集簇的pg_xlog/archiver_status目錄下記錄了每一個WAL段文件的狀態文件,狀態文件的前綴與段文件同名,以表示時間順序的整數形式命名。狀態文件后綴為.ready或者.done,代表段文件的歸檔狀態,分別代表“就緒”和“已完成”兩種模式。PgArch進程會找到所有狀態為“就緒”的段文件,找到狀態文件后,若用戶設置了歸檔命令,PgArch進程將歸檔命令解析后交由系統的shell函數system(3)執行。文件歸檔成功后會把pg_xlog/arcive_status目錄下相應的狀態文件后綴修改為.done。
對WAL日志的歸檔給管理員提供了一種新的數據庫備份策略,這種備份策略組合了文件系統備份與WAL文件的備份。在恢復時,首先恢復數據文件,然后重放WAL日志到指定的時間點。應用這種備份恢復策略,在開始的時候並不需要一個非常完美的一致性備份。任何備份內部的不一致都會被日志的重放動作修改正確。因此,我們不需要文件系統快照的功能,只需要tar或者類似的歸檔工具。另外,WAL文件的分段歸檔也把連續的備份簡化為了分段的備份。這個功能對大數據庫特別有用,因為大數據庫的完全備份可能並不方便。如果持續把WAL文件重放給其他裝載了同樣的基礎備份文件的機器,就有了一套“熱備份”系統:在任何點我們都可以啟動第二台機器,而它擁有近乎當前的數據庫拷貝。和簡單的文件系統備份技術一樣,這個方法只能支持整個數據集簇的恢復。
6. AutoVacuum進程
數據庫總是不斷地在執行刪除,更新等操作。良好的空間管理非常重要,能夠對性能帶來大幅提高。在postgresql中用於維護數據庫磁盤空間的工具是VACUUM,其重要的作用是刪除那些已經標示為刪除的數據並釋放空間。
VACUUM語法結構:
VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
postgresql中執行delete操作后,表中的記錄只是被標示為刪除狀態,並沒有釋放空間,在以后的update或insert操作中該部分的空間是不能夠被重用的。經過vacuum清理后,空間才能得到釋放。可惜的是vacuum工具不能夠對相應的索引進行清理,唯一的辦法就是手動去重建相應索引(令人非常不爽,而高興的是在9.0之后有所改進)。
Full Vacuum
full vacuum與單純的vacuum還是有很大的區別的。vacuum只是將刪除狀態的空間釋放掉,轉換到能夠重新使用的狀態,但是對於系統來說該數據塊的空閑空間並沒有反應到系統的元數據中。類似oracle中高水位標記並沒有下降。Full vacuum將會使空間釋放的信息表現在系統級別,其實質是將當前刪除記錄后面的數據進行移動,使得整體的記錄連貫起來,降低了“高水位標記”。
Vacuum analyze
analyze的功能是更新統計信息,使得優化器能夠選擇更好的方案執行sql。oracle中同樣也有analyze,作用也相同,目前更多的使用的是dbms_stats包。統計信息收集和更新對於系統性能來說非常重要,與oracle維護類似,通常可以通過采用手動或者定制任務的方式。也有不同,oracle在進行imp后自動的對相應數據對象進行統計信息的收集和更新,而postgresql的恢復過程還沒有集成到里面,需要手動去執行。
自動vacuum配置
自動vacuum的執行直接由autovacuum參數值決定,默認值是on。
log_autovacuum_min_duration:默認值為-1,關閉vacuum的日志記錄,配置為0表示記錄autovacuum的所有log。參數設置為正整數表示對於在此時間內完成的vacuum操作不進行log記錄,如果沒能完成,則記錄超出時間內的log。該參數對於了解對象執行vacuum操作的時間非常有用。
autovacuum_max_workers:最大的autovacuum進程的數量,默認值為3。參數大小的配置主要依據系統當前負載和資源。對於系統負載較重的情況,建議開啟少量的進程為好,反之,空閑時間可以采用較大值的方式。
autovacuum_naptime:檢查數據庫的時間間隔。默認為1分鍾。
autovacuum_vacuum_threshold:參數表示執行autovacuum操作之前,對單個表中記錄執行DML操作的最少行數。達到該行數時自動激活autovacuum操作。該參數針對數據庫中的所有表,還可以通過對單個表配置不同的值來改變相應表的autovacuum操作。默認值是50。
autovacuum_analyze_threshold:激活自動analyze操作的最小行數。默認值50。機制與上面相同。
autovacuum_vacuum_scale_factor:該參數采用百分比的方式設定閥值。默認值為20%,當DML涉及的數據量大於某個表的20%時,自動觸發autovacuum操作。同樣可以通過對單個表進行閥值設定。
autovacuum_analyze_scale_factor:機制與上面相同,到達閥值是自動激活analyze操作。同樣可以通過對單個表進行閥值設定。
autovacuum_freeze_max_age:為防止事務ID的重置,在啟用vacuum操作之前,表的pg_class .relfrozenxid字段的最大值,默認為200萬。
autovacuum_vacuum_cost_delay:autovacuum進程的時間延遲限制,默認值是20ms。對於單個表同樣適用。
autovacuum_vacuum_cost_limit:autovacuum進程的開銷延遲限制,默認值是-1,表示不進行開銷限制,系統將會直接依據vacuum_cost_limit參數管理vacuum的開銷。對於單個表同樣適用。
通過了解vacuum,能夠更清楚postgresql是如何進行系統維護的,其中最為重要的是索引的維護,因為8.3中還不能對索引同時進行維護,這在實際的使用中需要耗費較大的精力,還好在9.0版本中有所改進(具體情況沒有測試)。同時大致了解postgresql進行自動vacuum操作的機制與過程。
7. PgStat進程
PgStat輔助進程是PostgreSQL數據庫系統的統計信息收集器,它專門負責收集數據庫系統運行中的統計信息,如在一個表和索引上進行了多少次插入與更新操作、磁盤塊的數量和元組的數量、每個表上最近一次執行清理和分析操作的時間,以及統計每個用戶自定義函數調用執行的時間等。由於統計數據收集給查詢處理增加了一些負荷,所以可以把系統配置為收集信息,也可以配置為不收集信息。系統表pg_statistic中存儲了PgStat收集的各類統計信息,另外在數據庫集簇的目錄下有與統計信息收集器相關的文件:global子文件夾下的pgstat.stat文件用於保存當前全局的統計信息;pg_stat_tmp文件則是PgStat進程和各個后台進程進行交互的臨時文件所在地。
PgStat輔助進程收集的統計信息主要用於查詢優化時的代價估算。在PostgreSQL的查詢優化過程中,查詢請求的不同執行方案是通過建立不同的路徑(Path)來表達的。在生成了許多符合條件的路徑之后,從中選擇出代價最小的路徑轉化為一個計划,這個計划將被傳遞給執行器執行。因此優化器的核心工作就是建立許許多多的路徑,然后從中找出最優的路徑。造成同一個查詢請求有不同路徑的主要原因是:表不同的訪問方式(如順序訪問(Sequential Access)、索引訪問(Index Access),PostgreSQL中還有可能使用TID直接訪問元組);表間不同的連接方式(嵌套循環連接(Nest-loop join)、歸並連接(Merge Join)、Hash連接(Hash Join));表間不同的連接順序(左連接(Left-join)、右連接(Right-join)、布希連接(Bushy-join))。而評價路徑優劣的依據是用系統表pg_statistic中的系統統計信息估計出的不同路徑的代價。
在PostgreSQL數據庫系統配置文件postgresql.conf中與PgStat相關的配置選項有:
track_activities:表示是否對會話中當前執行的命令開啟統計信息收集功能,該參數只對超級用戶和會話所有者可見,默認值為on(開啟)。
track_counts:表示是否對數據庫活動開啟統計信息收集功能,由於在AutoVacuum自動清理進程中選擇清理的數據庫時,需要數據庫的統計信息,因此該參數默認值為on。
track_function:表示是否開啟函數的調用次數和調用耗時統計。
track_activity_query_size:設置用於跟蹤每一個活動會話的當前執行命令的字節數,默認值為1024,只能在數據庫啟動后設置。
對於PgStat收集的統計信息,系統提供了部分標准視圖以供管理員查看;同時,還提供了統計信息相關的操作函數,供管理員來定義視圖。需要注意的是,使用的統計信息並非實時的,每個活動的獨立數據庫服務僅僅在處理空閑時才發送信息到統計信息收集器,因此查詢或者事務仍然在處理中並未更新當前的統計信息。在設置了track_activities參數時,當前查詢信息在統計信息收集器中是實時的。
8. 共享內存
PostgreSQL啟動后,會生成一塊共享內存,共享內存主要做數據塊的緩沖區,以便提高讀寫新能,WAL日志緩沖區和CLOG緩沖區也存在於共享內存中,除此之外,一些全局信息也保存在共享內存中,如進程信息,鎖信息,全局統計信息,等.
9. 本地內存
后台服務進程除了訪問共享內存外,還會申請分配一些本地內存,以便暫存一些不需要全局存儲的數據,這些內存緩沖區主要有以下幾類:
- 臨時緩沖區:用於訪問臨時表的本地緩沖區
- work_mem:內存排序操作和Hash表在使用臨時磁盤文件之前使用的內存緩沖區.
- maintenance_work_mem:在維護性操作(如vacuum,create index,和alter table add foreign key等)中使用的內存緩沖區.