1. 程式人生 > 其它 >【趙強老師】史上最詳細的PostgreSQL體系架構介紹

【趙強老師】史上最詳細的PostgreSQL體系架構介紹

PostgreSQL是最像Oracle的開源資料庫,我們可以拿Oracle來比較學習它的體系結構,比較容易理解。PostgreSQL的主要結構如下:

一、儲存結構

PG資料儲存結構分為:邏輯儲存結構和物理儲存儲存。其中:邏輯儲存結構是內部的組織和管理資料的方式;物理儲存結構是作業系統中組織和管理資料的方式。

1、邏輯儲存結構

所有資料庫物件都有各自的oid(object identifiers),oid是一個無符號的四位元組整數,相關物件的oid都存放在相關的system catalog表中,比如資料庫的oid和表的oid分別存放在pg_database,pg_class表中。
在邏輯儲存結構中有幾個術語需要解釋:

  • 資料庫叢集-Database cluster

也叫資料庫集簇。它是指有單個PostgreSQL伺服器例項管理的資料庫集合,組成資料庫叢集的這些資料庫使用相同的全域性配置檔案和監聽埠、共用程序和記憶體結構。一個DataBase Cluster可以包括:多個DataBase、多個User、以及Database中的所有物件。如上圖所示。

  • **資料庫-Database **

在PostgreSQL中,資料庫本身也是資料庫物件,並且在邏輯上彼此分離,除資料庫之外的其他資料庫物件(例如:表、索引等等)都屬於他們各自的資料庫。

  • 表空間-tablespace

資料庫在邏輯上分成多個儲存單元,稱作表空間。表空間用作把邏輯上相關的結構放在一起。資料庫邏輯上是由一個或多個表空間組成。初始化的時候,會自動建立pg_default和pg_global兩個表空間。

\db

其中:
pg_global:用於存放系統表。
pg_default:該表空間的物理檔案儲存在資料目錄中的base目錄中。


建立自己的表空間,並在該表空間上建立表
create tablespace mydemotbs location '/home/postgres/training/pgsql/data/mydemotbs';
create table testtable1(tid int primary key,tname text) tablespace mydemotbs;


  • 模式-Schema

當建立一個數據庫時,會為其建立一個名為public的預設Schema。Schema是資料庫中的名稱空間,在資料庫中建立的所有物件都是在Schema中建立,一個使用者可以從同一個客戶端連線中訪問不同的Schema。而不同的Schema中可以有多個同名的Table、Index、View、Sequence、Function等等資料庫物件。可以通過下面的方式來檢視當前資料庫的Schema

\dn


  • 段-segment

一個段是分配給一個邏輯結構(一個表、一個索引或其他物件)的一組區,是資料庫物件使用的空間的集合;段可以有表段、索引段、回滾段、臨時段和快取記憶體段等。

  • 區-extent

區是資料庫儲存空間分配的一個邏輯單位,它由連續資料塊所組成。第一個段是由一個或多個盤區組成。當一段中間所有空間已完全使用,PostgreSQL為該段分配一個新的範圍。

  • 塊-block(Page)

資料塊是PostgreSQL 管理資料檔案中儲存空間的單位,為資料庫使用的I/O的最小單位,是最小的邏輯部件。預設值8K。

  • 資料庫物件-Database object

如:表、檢視、索引、序列、函式等等。在PostgreSQL中的所有資料庫物件都由各自的物件識別符號(OID)進行內部的管理。例如,資料庫的OID儲存在pg_database系統表中,可以通過下面的語句進行查詢。

select oid,datname from pg_database;


而資料庫中的表、索引、序列等資料庫物件的OID則存在了pg_class系統表中,例如可以通過下面的語句查詢前面建立的testtable1表的OID。

select oid,relname,relkind,relfilenode from pg_class where relname ='testtable1';


2、物理儲存結構

在執行initdb的時候會初始化一個目錄,通常我們都會在系統配置相關的環境變數$PGDATA來表示,初始化完成後,會再這個目錄生成相關的子目錄以及一些檔案。在postgresql中,表空間的概念並不同於其他關係型資料庫,這裡一個Tablespace對應的都是一個目錄。如下圖就是PG的物理結構:

每個目錄的功能與作用如下所示:

而PostgreSQL的物理儲存結構主要是指硬碟上儲存的檔案,包括:資料檔案、日誌檔案、引數檔案、控制檔案、redo日誌(WAL)。下面分別進行介紹。

  • 資料檔案(表文件)

顧名思義,資料檔案用於儲存資料。檔名以OID命名,對於超出1G的表資料檔案,PostgreSQL會自動將其拆分為多個檔案來儲存,而拆分的檔名將由pg_class中的relfilenode欄位來決定。如下所示:

select oid,relname,relkind,relfilenode from pg_class where relname ='testtable1';


檢視目錄表空間mydemotbs的目錄(其中:13578是資料庫OID,16385是表的OID)

在PostgreSQL中,將儲存在磁碟中的塊(Block)稱為Page。資料的讀寫是以Page為最小單位,每個Page預設的大小是8K。在編譯PostgreSQL時指定BLCKSZ大小將決定Page的大小。每個表文件由逗哥BLCKSZ位元組大小的Page組成。在分析型資料庫中,適當增加BLCKSZ大小可以小幅度提升資料庫的效能。

  • 日誌檔案

PostgreSQL日誌檔案的型別,分為以下幾種:
① 執行日誌(pg_log)
預設沒有開啟,開啟後會自動生成。檢視postgresql.conf檔案的配置可以看到相關的引數設定。這個日誌一般是記錄伺服器與DB的狀態,比如各種Error資訊,定位慢查詢SQL,資料庫的啟動關閉資訊,發生checkpoint過於頻繁等的告警資訊,諸如此類。該日誌有.csv格式和.log。建議使用.csv格式,因為它一般會按大小和時間自動切割。pg_log是可以被清理刪除,壓縮打包或者轉移,同時並不影響DB的正常執行。當我們有遇到DB無法啟動或者更改引數沒有生效時,第一個想到的就是檢視這個日誌。

② 重做日誌(pg_xlog)
pg_xlog 這個日誌是記錄的Postgresql的WAL資訊,預設儲存在目錄$PGDATA/pg_wal/,是一些事務日誌資訊(transaction log)。預設單個大小是16M,原始碼安裝的時候可以更改其大小(./configure --with-wal-segsize=target_value 引數,即可設定)這些日誌會在定時回滾恢復(PITR), 流複製(Replication Stream)以及歸檔時能被用到,這些日誌是非常重要的,記錄著資料庫發生的各種事務資訊,不得隨意刪除或者移動這類日誌檔案,不然你的資料庫會有無法恢復的風險。

③ 事務日誌(pg_xact)
pg_xact是事務提交日誌,記錄了事務的元資料。預設開啟。內容一般不能直接讀。預設儲存在目錄$PGDATA/pg_xact/。

④ 伺服器日誌
如果用pg_ctl啟動的時候沒有指定-l引數來指定伺服器日誌,錯誤可能會輸出到cmd前臺。伺服器日誌記錄了資料庫的重要資訊。

  • 引數檔案

主要包括postgresql.conf、pg_hba.conf和pg_ident.conf這三個引數檔案。下面分別進行介紹:
① postgresql.conf
PostgreSQL的主要引數檔案,有很詳細的說明和註釋,和Oracle的pfile,MySQL的my.cnf類似。預設在$PGDATA下。很多引數修改後都需要重啟。9.6之後支援了alter system來修改,修改後的會存在$PGDATA/postgresql.auto.conf下,可以reload或者 restart來使之生效。

② pg_hba.conf
這個是黑白名單的設定。檔案裡有詳細的引數說明,預設引數如下:

③ pg_ident.conf
pg_ident.conf是使用者對映配置檔案,用來配置哪些作業系統使用者可以對映為資料庫使用者。結合pg_hba.conf中,method為ident可以用特定的作業系統使用者和指定的資料庫使用者登入資料庫。

  • 控制檔案

控制檔案記錄了資料庫執行的一些資訊,比如資料庫id,是否open,wal的位置,checkpoint的位置等等。controlfile是很重要的檔案。
控制檔案的位置:$PGDATA/global/pg_control,可以使用命令bin/pg_controldata檢視控制檔案的內容,如下:

  • redo日誌(WAL)

預設儲存在$PGDATA/pg_wal目錄下,如下所示:

檔名稱為16進位制的24個字元組成,每8個字元一組,每組的意義如下:
00000001  00000000  00000001
時間線    邏輯ID	物理ID


通過下面的語句進行WAL的手動切換:

select pg_switch_wal();


再次檢視pg_wal目錄,如下所示:

二、程序結構

執行下面的命令列出所有的PostgreSQL的程序。

ps -ef | grep postgres


① Postmaster程序
主程序Postmaster是整個資料庫例項的總控制程序,負責啟動和關閉資料庫例項。使用者可以執行postmaster,postgres命令加上合適的引數啟動資料庫。實際上,postmaster命令是一個指向postgres的連結,如下圖所示。

更多時候我們使用pg_ctl啟動資料庫,pg_ctl也是通過執行postgres來啟動資料庫,它只是做了一些包裝,讓我們更容易啟動資料庫,所以,主程序Postmaster實際是第一個postgres程序,此程序會fork一些與資料庫例項相關的輔助子程序,並管理他們。
當用戶與PostgreSQL資料庫建立連線時,實際上是先與Postmaster程序建立連線。此時,客戶端程式會發出身份證驗證的訊息給Postmaster程序,Postmaster主程序根據訊息中的資訊進行客戶端身份驗證。如果驗證通過,它會fork一個子程序postgres為這個連線服務,fork出來的程序被稱為服務程序,查詢pg_stat_activity表可以看到的pid,就是這些服務程序的pid。

select pid from pg_stat_activity;


② SysLogger程序
在postgresql.conf裡啟用 執行日誌(pg_log)後,會有SysLogger程序。SysLogger會在日誌檔案達到指定的大小時關閉當前日誌檔案,產生新的日誌檔案。相關配置引數如下:

③ BgWriter後臺寫程序
BgWriter是PostgreSQL中在後臺將髒頁寫出到磁碟的輔助程序,引入該程序主要為達到如下兩個目的:
首先,資料庫在進行查詢處理時若發現要讀取的資料不在緩衝區中時要先從磁碟中讀入要讀取的資料所在的頁面,此時如果緩衝區已滿,則需要先選擇部分緩衝區中的頁面替換出去。如果被替換的頁面沒有被修改過,那麼可以直接丟棄;但如果要被替換的頁已被修改,則必需先將這頁寫出到磁碟中後才能替換,這樣資料庫的查詢處理就會被阻塞。通過使用BgWriter定期寫出緩衝區中的部分髒頁到磁碟中,為緩衝區騰出空間,就可以降低查詢處理被阻塞的可能性。
其次,PostgreSQL在定期作檢查點時需要把所有髒頁寫出到磁碟,通過BgWriter預先寫出一些髒頁,可以減少設定檢查點時要進行的IO操作,使系統的IO負載趨向平穩。通過BgWriter對共享緩衝區寫操作的統一管理,避免了其他服務程序在需要讀入新的頁面到共享緩衝區時,不得不將之前修改過的頁面寫出到磁碟的操作。

④ WalWriter預寫日誌寫程序
該程序用於儲存WAL預寫日誌。預寫式日誌WAL(Write Ahead Log,也稱為Xlog)的中心思想是對資料檔案的修改必須是隻能發生在這些修改已經記錄到日誌之後,也就是先寫日誌後寫資料。如果遵循這個過程,那麼就不需要在每次事務提交的時候都把資料塊刷回到磁碟,這一點與Oracle資料庫是完全一致的。postgresql.conf檔案中與WalWriter程序相關的引數如下:

#------------------------------------------------------------------------------
# WRITE AHEAD LOG
#------------------------------------------------------------------------------
#wal_level = minimal                    # minimal, replica, or logical
                                        # (change requires restart)
#fsync = on                             # flush data to disk for crash safety
                                        # (turning this off can cause
                                        # unrecoverable data corruption)
#synchronous_commit = on                # synchronization level;
                                        # off, local, remote_write, remote_apply, or on
#wal_sync_method = fsync                # the default is the first option
                                        # supported by the operating system:
                                        #   open_datasync
                                        #   fdatasync (default on Linux)
                                        #   fsync
                                        #   fsync_writethrough
                                        #   open_sync
#full_page_writes = on                  # recover from partial page writes
#wal_compression = off                  # enable compression of full-page writes
#wal_log_hints = off                    # also do full page writes of non-critical updates
                                        # (change requires restart)
#wal_buffers = -1                       # min 32kB, -1 sets based on shared_buffers
                                        # (change requires restart)
#wal_writer_delay = 200ms               # 1-10000 milliseconds
#wal_writer_flush_after = 1MB           # measured in pages, 0 disables
#commit_delay = 0                       # range 0-100000, in microseconds
#commit_siblings = 5                    # range 1-1000


⑤ PgArch歸檔程序
從PostgreSQL 8.x開始,有了PITR(Point-In-Time-Recovery)技術,該技術支援將資料庫恢復到其執行歷史中任意一個有記錄的時間點;PITR的另一個重要的基礎就是對WAL檔案的歸檔功能。PgArch輔助程序的目標就是對WAL日誌在磁碟上的儲存形式進行歸檔備份。但在預設情況下,PostgreSQL是非歸檔模式,因此看不到PgArch程序。PgArch程序通過postgresql.conf檔案中的如下引數進行配置:

# - Archiving -
#archive_mode = off             # enables archiving; off, on, or always
                                # (change requires restart)
#archive_command = ''           # command to use to archive a logfile segment
                                # placeholders: %p = path of file to archive
                                #               %f = file name only
                                # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0            # force a logfile segment switch after this
                                # number of seconds; 0 disables


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

#------------------------------------------------------------------------------
# AUTOVACUUM
#------------------------------------------------------------------------------
#autovacuum = on                        # Enable autovacuum subprocess?  'on'
                                        # requires track_counts to also be on.
#log_autovacuum_min_duration = -1       # -1 disables, 0 logs all actions and
                                        # their durations, > 0 logs only
                                        # actions running at least this number
                                        # of milliseconds.
#autovacuum_max_workers = 3             # max number of autovacuum subprocesses
                                        # (change requires restart)
#autovacuum_naptime = 1min              # time between autovacuum runs
#autovacuum_vacuum_threshold = 50       # min number of row updates before
                                        # vacuum
#autovacuum_vacuum_insert_threshold = 1000      # min number of row inserts
                                        # before vacuum; -1 disables insert
                                        # vacuums
#autovacuum_analyze_threshold = 50      # min number of row updates before
                                        # analyze
#autovacuum_vacuum_scale_factor = 0.2   # fraction of table size before vacuum
#autovacuum_vacuum_insert_scale_factor = 0.2    # fraction of inserts over table
                                        # size before insert vacuum
#autovacuum_analyze_scale_factor = 0.1  # fraction of table size before analyze
#autovacuum_freeze_max_age = 200000000  # maximum XID age before forced vacuum
                                        # (change requires restart)
#autovacuum_multixact_freeze_max_age = 400000000        # maximum multixact age
                                        # before forced vacuum
                                        # (change requires restart)
#autovacuum_vacuum_cost_delay = 2ms     # default vacuum cost delay for
                                        # autovacuum, in milliseconds;
                                        # -1 means use vacuum_cost_delay
#autovacuum_vacuum_cost_limit = -1      # default vacuum cost limit for
                                        # autovacuum, -1 means use
                                        # vacuum_cost_limit


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

#------------------------------------------
# RUNTIME STATISTICS
#------------------------------------------
# - Query/Index Statistics Collector -
#track_activities = on
#track_counts = on
#track_io_timing = off
#track_functions = none                 # none, pl, all
#track_activity_query_size = 1024       # (change requires restart)
#stats_temp_directory = 'pg_stat_tmp'


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

# - Checkpoints -
#checkpoint_timeout = 5min              # range 30s-1d
#max_wal_size = 1GB
#min_wal_size = 80MB
#checkpoint_completion_target = 0.5     # checkpoint target duration, 0.0 - 1.0
#checkpoint_flush_after = 256kB         # measured in pages, 0 disables
#checkpoint_warning = 30s               # 0 disables


三、記憶體結構

PostgreSQL的記憶體結構,分為:本地記憶體和共享記憶體。它們的關係如下圖所示:

① 本地記憶體:每個後端程序(backend process)自己使用的

② 共享記憶體:所有程序共同使用