1. 程式人生 > 資料庫 >PostgreSQL體系架構

PostgreSQL體系架構

PostgreSQL 使用客戶機/伺服器(C/S)的模式提供服務,一個PostgreSQL會話由下列相關的程序(程式)組成:

(1)一個伺服器端程序。該程序管理資料庫檔案,接受客戶端與資料庫的連線,且代表客戶端對資料庫進行操作。該程序的程式名叫做 postgres。

(2)前端應用,即需要進行資料庫操作的客戶端應用。客戶端應用可能本身就是多種多樣的:它們可以是一個字元界  面的工具, 也可以是一個圖形介面的應用,或者是一個通過訪問資料庫來顯示網頁的 web 伺服器,或者是一個特殊的資料庫管理工具。 一些客戶端應用是和 PostgreSQL 釋出一起提供的,但絕大部分是使用者開發的。

和典型的客戶端/伺服器應用(C/S應用)一樣,客戶端和伺服器可以在不同的主機上。此時,它們通過TCP/IP進行網路連線,你應該記住這一點,因為在客戶機上可以訪問的檔案未必能夠在資料庫伺服器機器上訪問(或者只能用不同的檔名進行訪問)。

PostgreSQL 伺服器可以處理來自客戶端的多個併發請求。為了能這樣處理,它會為每個請求啟動(“forks”)一個新的程序,然後,客戶端和新伺服器端程序就不再經過最初的postgres 程序而直接通訊。 因此, 伺服器端的主程序一直執行,等待著來自客戶端的連線;而客戶端和相關聯的伺服器端程序則在需要的時候才會執行。(當然,這些對使用者來說是透明的,在這裡談這些主要是為了說明的完整性。)

PostgreSQL資料庫是一種極好可以執行在各種平臺上的免費的開放原始碼的物件關係資料庫,它是一種以關係資料庫和SQL為基礎,擴充套件了抽象資料型別,從而具備面向物件特性的資料庫。

                        

                                      PostgreSQL體系結構圖(組成結構和關係)

PostgreSQL由連線管理系統(系統控制器),編譯執行系統,儲存管理系統,事務系統,系統表五大部分組成。

連線管理系統接受外部操作對系統的請求,對操作請求進行預處理和分發,起系統邏輯控制作用;

編譯執行系統由查詢編譯器,查詢執行器組成,完成操作請求在資料庫中的分析處理和轉化工作,最終實現物理儲存介質中資料的操作;

儲存管理系統由索引管理器,記憶體管理器,外存管理器組成,負責儲存和管理物理資料,提供對編譯查詢系統的支援;

事務系統由事務管理器,日誌管理器,併發控制,鎖管理器組成,日誌管理器和事務管理器完成對操作請求的事務一致性支援,鎖管理器和併發控制提供對併發訪問資料的一致性支援;

系統表是PostgreSQL資料庫的元資訊管理中心,包括資料庫物件資訊和資料庫管理控制資訊。系統表管理元資料資訊,將PostgreSQL資料庫的各個模組有機地連線在一起,形成一個高效的資料管理系統。

系統表

在關係資料庫中,為了實現資料庫系統的控制,必須提供資料字典的功能。資料字典不僅儲存各種物件的描述資訊,而且儲存系統管理所需的各種物件的細節資訊。資料字典包含資料庫系統中所有物件及其屬性的描述資訊,物件之間關係的描述資訊,物件屬性的自然語言含義以及資料字典變化的歷史,資料字典是關係資料庫系統管理控制資訊的核心,在PostgreSQL資料庫系統中系統表扮演著資料字典的角色。

系統表是PostgreSQL資料庫存放結構元資料的地方,他在PostgreSQL中表現為存放有系統資訊的普通表或者檢視(使用者可以刪除,重建)。

系統表儲存了資料庫的所有元資料,所以系統執行時對系統表的訪問是非常頻繁的。為了提高系統性能,在記憶體中建立了共享的系統表,使用Hash表提高查詢效率。

主要系統表功能

1 pg_namespace 儲存名稱空間

2 pg_tablespace 儲存空間資訊

3 pg_database 儲存當前資料集簇中資料庫的資訊。

4 pg_class 儲存表及與表類似結構的資料庫物件資訊,包含,索引,序列,檢視,複合資料型別,TOAST表等。

5 pg_type 儲存資料型別資訊。

6 pg_attribute 儲存表的屬性資訊。

7 pg_index 儲存索引的具體資訊。

 

PostgreSQL資料庫系統的主要功能都集中於Postgres程式,其入口是Main模組中的main函式,在初始化資料集簇,啟動資料庫伺服器是,都將從這裡開始執行。Main模組主要的工作時確定當前的作業系統平臺,並據此做一些平臺相關的環境變數設定和初始化,然後通過對命令列引數的判斷,將控制轉到相應的模組中去。下圖是main函式的呼叫流程。

                    

                        PostgreSQL系統主函式main的流程

PostgreSQL守護程序Postmaster為使用者連線請求分配後臺Postgres服務程序,還將啟動相關的後臺服務程序:SysLogger(系統日誌程序),PgStat(統計資料收集程序),

AutoVacuum(系統自動清理程序).在Postmaster進入到迴圈監聽中時啟動如下進行:BgWriter(後臺寫程序),WalWriter(預寫式日誌寫程序),PgArch(預寫式日誌歸檔程序)。這些程序將在後續文章中介紹。

下圖是PostgreSQL的後臺流程圖:

                        

 

 

   1.1.1.1 Potgres(常駐程序)

管理後端的常駐程序,也稱為’postmaster’。其預設監聽UNIXDomain Socket和TCP/IP(Windows等,一部分的平臺只監聽tcp/ip)的5432埠,等待來自前端的的連線處理。監聽的埠號可以在PostgreSQL的設定檔案postgresql.conf裡面可以改。

一旦有前端連線過來,postgres會通過fork(2)生成子程序。沒有Fork(2)的windows平臺的話,則利用createProcess()生成新的程序。這種情形的話,和fork(2)不同的是,父程序的資料不會被繼承過來,所以需要利用共享記憶體把父程序的資料繼承過來。

   1.1.1.2 Postgres(子程序)

子程序根據pg_hba.conf定義的安全策略來判斷是否允許進行連線,根據策略,會拒絕某些特定的IP及網路,或者也可以只允許某些特定的使用者或者對某些資料庫進行連線。

Postgres會接受前端過來的查詢,然後對資料庫進行檢索,最好把結果返回,有時也會對資料庫進行更新。更新的資料同時還會記錄在事務日誌裡面(PostgreSQL稱為WAL日誌),這個主要是當停電的時候,伺服器當機,重新啟動的時候進行恢復處理的時候使用的。另外,把日誌歸檔儲存起來,可在需要進行恢復的時候使用。在PostgreSQL 9.0以後,通過把WAL日誌傳送其他的postgreSQL,可以實時得進行資料庫複製,這就是所謂的‘資料庫複製’功能。

   1.1.1.3 其他的程序

Postgres之外還有一些輔助的程序。這些程序都是由常駐postgres啟動的程序。

(1) Postmaster主程序和服務程序

當PG資料庫啟動時,首先會啟動Postmaster主程序。這個程序是PG資料庫的總控制程序,負責啟動和關閉資料庫例項。實際上Postmaster程序是一個指向postgres命令的連結,如下:

 ll/opt/postgresql/bin/postmaster

 /opt/postgresql/bin/postmaster-> postgres

當用戶和PG資料庫建立連線時,要先與Postmaster程序建立連線,此時客戶端程序會發送身份驗證訊息給Postmaster主程序,Postmaster主程序根據訊息進行身份驗證,驗證通過後,Postmaster主程序會fork出一個會話服務程序為這個使用者連線服務。可以通過pg_stat_activity表來檢視服務程序的pid,如下:

test=# select pid,usename,client_addr,client_port frompg_stat_activity;

(2) Writer process

Writer process在適當的時間點把共享記憶體上的快取寫往磁碟。通過這個程序,可以防止在檢查點的時候(checkpoint),大量的往磁碟寫而導致效能惡化,使得伺服器可以保持比較穩定的效能。Background writer起來以後就一直常駐記憶體,但是並非一直在工作,它會在工作一段時間後進行休眠,休眠的時間間隔通過postgresql.conf裡面的引數bgwriter_delay設定,預設是200微秒。

這個程序的另外一個重要的功能是定期執行檢查點(checkpoint)。

檢查點的時候,會把共享記憶體上的快取內容往資料庫檔案寫,使得記憶體和檔案的狀態一致。通過這樣,可以在系統崩潰的時候可以縮短從WAL恢復的時間,另外也可以防止WAL無限的增長。 可以通過postgresql.conf的checkpoint_segments、checkpoint_timeout指定執行檢查點的時間間隔。

Writer程序是把共享記憶體中的髒頁寫到磁碟上的程序。它的作用有兩個:一是定期把髒資料從記憶體緩衝區刷出到磁碟中,減少查詢時的阻塞;二是PG在定期作檢查點時需要把所有髒頁寫出到磁碟,通過BgWriter預先寫出一些髒頁,可以減少設定檢查點(CheckPoint,資料庫恢復技術的一種)時要進行的IO操作,使系統的IO負載趨向平穩。BgWriter是PostgreSQL8.0以後新加的特性,它的機制可以通過postgresql.conf檔案中以"bgwriter_"開頭配置引數來控制:

bgwriter_delay:

backgroud writer程序連續兩次flush資料之間的時間的間隔。預設值是200,單位是毫秒。

bgwriter_lru_maxpages:

backgroud writer程序每次寫的最多資料量,預設值是100,單位buffers。如果髒資料量小於該數值時,寫操作全部由backgroud writer程序完成;反之,大於該值時,大於的部分將有server process程序完成。設定該值為0時表示禁用backgroud writer寫程序,完全有server process來完成;配置為-1時表示所有髒資料都由backgroud writer來完成。(這裡不包括checkpoint操作)

bgwriter_lru_multiplier:

這個引數表示每次往磁碟寫資料塊的數量,當然該值必須小於bgwriter_lru_maxpages。設定太小時需要寫入的髒資料量大於每次寫入的資料量,這樣剩餘需要寫入磁碟的工作需要server process程序來完成,將會降低效能;值配置太大說明寫入的髒資料量多於當時所需buffer的數量,方便了後面再次申請buffer工作,同時可能出現IO的浪費。該引數的預設值是2.0。

bgwriter的最大資料量計算方式:

1000/bgwriter_delay*bgwriter_lru_maxpages*8K=最大資料量

bgwriter_flush_after:

 

資料頁大小達到bgwriter_flush_after時觸發BgWriter,預設是512KB。

 

(3) WAL writer process(預寫式日誌寫)

WAL writer process把共享記憶體上的WAL快取在適當的時間點往磁碟寫,通過這樣,可以減輕後端程序在寫自己的WAL快取時的壓力,提高效能。另外,非同步提交設為true的時候,可以保證在一定的時間間隔內,把WAL快取上的內容寫入WAL日誌檔案。

預寫式日誌WAL(Write Ahead Log,也稱為Xlog)的中心思想是對資料檔案的修改必須是隻能發生在這些修改已經記錄到日誌之後,也就是先寫日誌後寫資料(日誌先行)。使用這種機制可以避免資料頻繁的寫入磁碟,可以減少磁碟I/O。資料庫在宕機重啟後可以運用這些WAL日誌來恢復資料庫。postgresql.conf檔案中與WalWriter程序相關的引數如下:

wal_level:控制wal儲存的級別。wal_level決定有多少資訊被寫入到WAL中。 預設值是最小的(minimal),其中只寫入從崩潰或立即關機中恢復的所需資訊。replica 增加 wal 歸檔資訊 同時包括 只讀伺服器需要的資訊。(9.6 中新增,將之前版本的 archive 和 hot_standby 合併)

logical 主要用於logical decoding 場景

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負擔。

wal_writer_flush_after:

commit_delay:表示一個已經提交的資料在WAL緩衝區中存放的時間,預設值是0毫秒,表示不用延遲;設定為非0值時事務執行commit後不會立即寫入WAL中,而仍存放在WAL緩衝區中,等待WalWriter程序週期性地寫入磁碟。

commit_siblings:表示當一個事務發出提交請求時,如果資料庫中正在執行的事務數量大於commit_siblings值,則該事務將等待一段時間(commit_delay的值);否則該事務則直接寫入WAL。系統預設值是5,該引數還決定了commit_delay的有效性。

 wal_writer_flush_after:當髒資料超過閾值時,會被刷出到磁碟。

 

(4) Archive process

Archive process把WAL日誌轉移到歸檔日誌裡。如果儲存了基礎備份以及歸檔日誌,即使實在磁碟完全損壞的時候,也可以回覆資料庫到最新的狀態。

類似於Oracle資料庫的ARCH歸檔程序,不同的是ARCH是吧redo log進行歸檔,PgArch是把WAL日誌進行歸檔。再深入點,WAL日誌會被迴圈使用,也就是說,過去的WAL日誌會被新產生的日誌覆蓋,PgArch程序就是為了在覆蓋前把WAL日誌備份出來。歸檔日誌的作用是為了資料庫能夠使用全量備份和備份後產生的歸檔日誌,從而讓資料庫回到過去的任一時間點。PG從8.X版本開始提供的PITR(Point-In-Time-Recovery)技術,就是運用的歸檔日誌。

PgArch程序通過postgresql.conf檔案中的如下引數進行

 

archive_mode:

表示是否進行歸檔操作,可選擇為off(關閉)、on(啟動)和always(總是開啟),預設值為off(關閉)。

archive_command:

由管理員設定的用於歸檔WAL日誌的命令。在用於歸檔的命令中,預定義變數“%p”用來指代需要歸檔的WAL全路徑檔名,“%f”表示不帶路徑的檔名(這裡的路徑都是相對於當前工作目錄的路徑)。每個WAL段檔案歸檔時將呼叫archive_command所指定的命令。當歸檔命令返回0時,PostgreSQL就會認為檔案被成功歸檔,然後就會刪除或迴圈使用該WAL段檔案。否則,如果返回一個非零值,PostgreSQL會認為檔案沒有被成功歸檔,便會週期性地重試直到成功。

archive_timeout:

表示歸檔週期,在超過該引數設定的時間時強制切換WAL段,預設值為0(表示禁用該功能)。

(5) stats collector process

統計資訊的收集程序。收集好統計表的訪問次數,磁碟的訪問次數等資訊。收集到的資訊除了能被autovaccum利用,還可以給其他資料庫管理員作為資料庫管理的參考資訊。

PgStat程序是PostgreSQL資料庫的統計資訊收集器,用來收集資料庫執行期間的統計資訊,如表的增刪改次數,資料塊的個數,索引的變化等等。收集統計資訊主要是為了讓優化器做出正確的判斷,選擇最佳的執行計劃。postgresql.conf檔案中與PgStat程序相關的引數,如下:

track_activities:表示是否對會話中當前執行的命令開啟統計資訊收集功能,該引數只對超級使用者和會話所有者可見,預設值為on(開啟)。

track_counts:表示是否對資料庫活動開啟統計資訊收集功能,由於在AutoVacuum自動清理程序中選擇清理的資料庫時,需要資料庫的統計資訊,因此該引數預設值為on。

track_io_timing:定時呼叫資料塊I/O,預設是off,因為設定為開啟狀態會反覆的呼叫資料庫時間,這給資料庫增加了很多開銷。只有超級使用者可以設定

track_functions:表示是否開啟函式的呼叫次數和呼叫耗時統計。

track_activity_query_size:設定用於跟蹤每一個活動會話的當前執行命令的位元組數,預設值為1024,只能在資料庫啟動後設置。

stats_temp_directory:統計資訊的臨時儲存路徑。路徑可以是相對路徑或者絕對路徑,引數預設為pg_stat_tmp,設定此引數可以減少資料庫的物理I/O,提高效能。此引數只能在postgresql.conf檔案或者伺服器命令列中修改。

 

(6) Logger process

把postgresql的活動狀態寫到日誌資訊檔案(並非事務日誌),在指定的時間間隔裡面,對日誌檔案進行rotate.

(7) Autovacuum(自動清理)啟動程序

autovacuum launcher process是依賴於postmaster間接啟動vacuum程序。而其自身是不直接啟動自動vacuum程序的。通過這樣可以提高系統的可靠性。

在PG資料庫中,對資料進行UPDATE或者DELETE操作後,資料庫不會立即刪除舊版本的資料,而是標記為刪除狀態。這是因為PG資料庫具有多版本的機制,如果這些舊版本的資料正在被另外的事務開啟,那麼暫時保留他們是很有必要的。當事務提交後,舊版本的資料已經沒有價值了,資料庫需要清理垃圾資料騰出空間,而清理工作就是AutoVacuum程序進行的。postgresql.conf檔案中與AutoVacuum程序相關的引數有:

autovacuum:是否啟動系統自動清理功能,預設值為on。

log_autovacuum_min_duration:這個引數用來記錄 autovacuum 的執行時間,當 autovaccum 的執行時間超過 log_autovacuum_min_duration引數設定時,則autovacuum資訊記錄到日誌裡,預設為 "-1", 表示不記錄。

autovacuum_max_workers:設定系統自動清理工作程序的最大數量。

autovacuum_naptime:設定兩次系統自動清理操作之間的間隔時間。

autovacuum_vacuum_threshold和autovacuum_analyze_threshold:設定當表上被更新的元組數的閾值超過這些閾值時分別需要執行vacuum和analyze。

autovacuum_vacuum_scale_factor和autovacuum_analyze_scale_factor:設定表大小的縮放係數。

autovacuum_freeze_max_age:設定需要強制對資料庫進行清理的XID上限值。

autovacuum_vacuum_cost_delay:當autovacuum程序即將執行時,對 vacuum 執行 cost 進行評估,如果超過 autovacuum_vacuum_cost_limit設定值時,則延遲,這個延遲的時間即為 autovacuum_vacuum_cost_delay。如果值為 -1, 表示使用 vacuum_cost_delay 值,預設值為 20 ms。

autovacuum_vacuum_cost_limit:這個值為autovacuum 程序的評估閥值, 預設為 -1, 表示使用 "vacuum_cost_limit " 值,如果在執行autovacuum 程序期間評估的cost 超過autovacuum_vacuum_cost_limit, 則 autovacuum 程序則會休眠。

(8) 自動vacuum程序

autovacuum worker process程序實際執行vacuum的任務。有時候會同時啟動多個vacuum程序。

(9) wal sender / wal receiver

wal sender 程序和wal receiver程序是實現postgresql複製(streaming replication)的程序。Wal sender程序通過網路傳送WAL日誌,而其他PostgreSQL例項的wal receiver程序則接收相應的日誌。Wal receiver程序的宿主PostgreSQL(也稱為Standby)接受到WAL日誌後,在自身的資料庫上還原,生成一個和傳送端的PostgreSQL(也稱為Master)完全一樣的資料庫。

(10)    CheckPoint(檢查點)程序

檢查點是系統設定的事務序列點,設定檢查點保證檢查點前的日誌資訊刷到磁碟中。postgresql.conf檔案中與之相關的引數有:

   1.1.1.4 後端的處理流程

下面看看資料庫引擎postgres子程序的處理概要。為了簡單起見下面的說明中,把backendprocess簡稱為backend。Backend的main函式是PostgresMain (tcop/postgres.c)。

  1. 接收前端傳送過來的查詢(SQL文)
  2. SQL文是單純的文字,電腦是認識不了的,所以要轉換成比較容易處理的內部形式構文樹parser tree,這個處理的稱為構文解析。構文解析的模組稱為parser.這個階段只能夠使用文字字面上得來的資訊,所以只要沒語法錯誤之類的錯誤,即使是select不存在的表也不會報錯。這個階段的構文樹被稱為raw parse tree. 構文處理的入口在raw_parser (parser/parser.c)。
  3. 構文樹解析完以後,會轉換為查詢樹(Query tree)。這個時候,會訪問資料庫,檢查表是否存在,如果存在的話,則把表名轉換為OID。這個處理稱為分析處理(Analyze), 進行分析處理的模組是analyzer。 另外,PostgreSQL的程式碼裡面提到構文樹parser tree的時候,更多的時候是指查詢樹Query tree。分析處理的模組的入口在parse_analyze (parser/analyze.c)
  4. PostgreSQL還通過查詢語句的重寫實現檢視(view)和規則(rule), 所以需要的時候,在這個階段會對查詢語句進行重寫。這個處理稱為重寫(rewrite),重寫的入口在QueryRewrite (rewrite/rewriteHandler.c)。
  5. 通過解析查詢樹,可以實際生成計劃樹。生成查詢樹的處理稱為‘執行計劃處理’,最關鍵是要生成估計能在最短的時間內完成的計劃樹(plan tree)。這個步驟稱為’查詢優化’(不叫query optimize, 而是optimize), 而完成這個處理的模組稱為查詢優化器(不叫query optimizer,而是optimizer, 或者稱為planner)。執行計劃處理的入口在standard_planner (optimizer/plan/planner.c)。
  6. 按照執行計劃裡面的步驟可以完成查詢要達到的目的。執行執行計劃樹裡面步驟的處理稱為執行處理‘execute’, 完成這個處理的模組稱為執行器‘Executor’, 執行器的入口地址為,ExecutorRun (executor/execMain.c)
  7. 執行結果返回給前端。
  8. 返回到步驟一重複執行。