PostgreSQL的架构
是最先進的數(shù)據(jù)庫。他的第一個版本在1989年發(fā)布,從那時開始,他得到了很多擴展。根據(jù)db-enginers上的排名情況,PostgreSQL目前在數(shù)據(jù)庫領域排名第四。
本篇博客,我們來討論一下PostgreSQL的內部架構,以及各個組件之間如何交互。這將是本期PostgreSQL DBA系列博客的基石。
一、PostgreSQL的架構
PostgreSQL的物理架構非常簡單,它由共享內存、一系列后臺進程和數(shù)據(jù)文件組成。 (如下圖)
二、Shared Memory
共享內存是服務器服務器為數(shù)據(jù)庫緩存和事務日志緩存預留的內存緩存空間。其中最重要的組成部分是Shared Buffer和WAL Buffer。
Shared Buffer
Shared Buffer的目的是減少磁盤IO。為了達到這個目的,必須滿足以下規(guī)則:
當需要快速訪問非常大的緩存時(10G、100G等)
如果有很多用戶同時使用緩存,需要將內容盡量縮小
頻繁訪問的磁盤塊必須長期放在緩存中
WAL Buffer
WAL Buffer是用來臨時存儲數(shù)據(jù)庫變化的緩存區(qū)域。存儲在WAL Buffer中的內容會根據(jù)提前定義好的時間點參數(shù)要求寫入到磁盤的WAL文件中。在備份和恢復的場景下,WAL Buffer和WAL文件是極其重要的。
三、PostgreSQL 進程類型
PostgreSQL有四種進程類型
Postmaster (Daemon) Process(主后臺駐留進程)
Background Process(后臺進程)
Backend Process(后端進程)
Client Process(客戶端進程)
Postmaster Process
主后臺駐留進程是PostgreSQL啟動時第一個啟動的進程。啟動時,他會執(zhí)行恢復、初始化共享內存愛你的運行后臺進程操作。正常服役期間,當有客戶端發(fā)起鏈接請求時,它還負責創(chuàng)建后端進程。
如果通過pstree命令查看進程之間的關系,你會發(fā)現(xiàn)Postmaster進程是其他所有進程的父進程。
Background Process
PostgreSQL操作需要的后臺進程列表如下:
| 進程 | 作用 |
|---|---|
| logger | 將錯誤信息寫到log日志中 |
| checkpointer | 當檢查點出現(xiàn)時,將臟內存塊寫到數(shù)據(jù)文件 |
| writer | 周期性的將臟內存塊寫入文件 |
| wal writer | 將WAL緩存寫入WAL文件 |
| Autovacuum launcher | 當自動vacuum被啟用時,用來派生autovacuum工作進程。autovacuum進程的作用是在需要時自動對膨脹表執(zhí)行vacuum操作。 |
| archiver | 在歸檔模式下時,復制WAL文件到特定的路徑下。 |
| stats collector | 用來收集數(shù)據(jù)庫統(tǒng)計信息,例如會話執(zhí)行信息統(tǒng)計(使用pg_stat_activity視圖)和表使用信息統(tǒng)計(pg_stat_all_tables視圖) |
Backend Process
最大后臺鏈接數(shù)通過max_connections參數(shù)設定,默認值為100。后端進程用于處理前端用戶請求并返回結果。查詢運行時需要一些內存結構,就是所謂的本地內存(local memory)。本地內存涉及的主要參數(shù)有:
work_mem:用于排序、位圖索引、哈希鏈接和合并鏈接操作。默認值為4MB。
maintenance_work_mem:用于vacuum和創(chuàng)建索引操作。默認值為64MB。
temp_buffers:用于臨時表。默認值為8MB。
Client Process
客戶端進程需要和后端進程配合使用,處理每一個客戶鏈接。通常情況下,Postmaster進程會派生一個紫禁城用來處理用戶鏈接。
四、數(shù)據(jù)庫結構
想要理解PostgreSQL的數(shù)據(jù)庫結構,需要先了解一些重要的概念。
數(shù)據(jù)庫相關概念:
PostgreSQL由一系列數(shù)據(jù)庫組成。一套PostgreSQL程序稱之為一個數(shù)據(jù)庫群集。
當initdb()命令執(zhí)行后,template0 , template1 , 和postgres數(shù)據(jù)庫被創(chuàng)建。
template0和template1數(shù)據(jù)庫是創(chuàng)建用戶數(shù)據(jù)庫時使用的模版數(shù)據(jù)庫,他們包含系統(tǒng)元數(shù)據(jù)表。
initdb()剛完成后,template0和template1數(shù)據(jù)庫中的表是一樣的。但是template1數(shù)據(jù)庫可以根據(jù)用戶需要創(chuàng)建對象。
用戶數(shù)據(jù)庫是通過克隆template1數(shù)據(jù)庫來創(chuàng)建的;
表空間相關概念:
initdb()后馬上創(chuàng)建pg_default和pg_global表空間。
建表時如果沒有指定特定的表空間,表默認被存在pg_default表空間中。
用于管理整個數(shù)據(jù)庫集群的表默認被存儲在pg_global表空間中。
pg_default表空間的物理位置為$PGDATAase目錄。
pg_global表空間的物理位置為$PGDATAglobal目錄。
一個表空間可以被多個數(shù)據(jù)庫同時使用。此時,每一個數(shù)據(jù)庫都會在表空間路徑下創(chuàng)建為一個新的子路徑。
創(chuàng)建一個用戶表空間會在$PGDATApg_tblspc目錄下面創(chuàng)建一個軟連接,連接到表空間制定的目錄位置。
表相關概念:
每個表有三個數(shù)據(jù)文件。
一個文件用于存儲數(shù)據(jù),文件名是表的OID。
一個文件用于管理表的空閑空間,文件名是OID_fsm。
一個文件用于管理表的塊是否可見,文件名是OID_vm。
索引沒有_vm文件,只有OID和OID_fsm兩個文件
其他需要注意的地方
表和索引創(chuàng)建時文件名是OID,此時的OID和pg_class.relfilenode的值是一樣的。不管怎樣,當我們執(zhí)行重寫操作時(truncate,cluster,vacuum full,reindex等),被修改對象的relfilenode值也會被修改,文件名也會隨著reffilenode值一起改變。我們可以通過pg_relation_filepath('<object_name>')視圖很容易的檢查文件位置和名稱。
五、運行測試
initdb()完成后,如果登錄數(shù)據(jù)庫查詢視圖pg_database,我們可以看到template0 , template1和 postgres數(shù)據(jù)庫已經被創(chuàng)建好了。
通過datistemplate列,我們可以看到template0和template1是用戶創(chuàng)建數(shù)據(jù)庫時使用的模版數(shù)據(jù)庫,其他的都不是模版數(shù)據(jù)庫。
通過datlowconn列,可以看出該數(shù)據(jù)庫是否允許訪問。因為template0數(shù)據(jù)庫不能被訪問,所以該數(shù)據(jù)庫的內容不能被修改。
設置兩個模版數(shù)據(jù)庫的原因是template0是初始狀態(tài),而template1數(shù)據(jù)庫則是可以集成用戶某些需求的模版數(shù)據(jù)庫。
postgres數(shù)據(jù)庫時使用模版template1創(chuàng)建的默認數(shù)據(jù)庫,如果鏈接時不指定數(shù)據(jù)庫名稱,默認連接到postgres數(shù)據(jù)庫。
數(shù)據(jù)庫存儲在$PGDATAase目錄下。路徑的名稱和數(shù)據(jù)庫OID的名稱一致。
六、創(chuàng)建用戶數(shù)據(jù)庫
上文提過,用戶數(shù)據(jù)庫創(chuàng)建是通過克隆template1數(shù)據(jù)庫。為了驗證這個規(guī)則,我們現(xiàn)在template1中創(chuàng)建一個表t1,緊接著創(chuàng)建一個mydb01數(shù)據(jù)庫,檢查t1表是否在mydb01中存在。
pg_default tablespace
initdb()后,如果登錄數(shù)據(jù)庫查詢pg_tablespace視圖,會發(fā)現(xiàn)pg_global和pg_default表空間已經創(chuàng)建好。
pg_default表空間的位置為$PGDATAase。每一個數(shù)據(jù)庫都擁有一個以自己OID命令的子路徑。
pg_global表空間
pg_global表空間用于存儲集群級別的數(shù)據(jù)。
例如pg_開頭的表
pg_global表空間路徑為$PGDATAglobal.
七、創(chuàng)建用戶表空間
pg_tablespace視圖顯示myts01表空間已經被創(chuàng)建好。
$PGDATA/pg_tblspc路徑下有一個符號鏈接指到目標目錄。
下面分別連接到postgres和mydb01數(shù)據(jù)庫,創(chuàng)建表。
如果查看/data01路徑下的內容,會發(fā)現(xiàn)上面創(chuàng)建的兩個數(shù)據(jù)庫中的t1表,分別在下面有一個對應OID的文件夾存在。
修改表空間位置
PostgreSQL在創(chuàng)建表空間時指定一個特定的路徑。因此,如果該特定路徑已經滿了,數(shù)據(jù)就不能在向里面存儲了。為了解決該問題,我們可以使用磁盤管理程序擴展空間。但是如果不想使用磁盤管理程序,我們可以通過該表表空間的位置來解決該問題。命令如下:
八、Vacuum是什么?
vacuum執(zhí)行如下操作:
收集表和索引的統(tǒng)計信息
整理表
清理表和索引中的死亡塊
被XID凍結,防止XID回繞
#1 和 #2 是數(shù)據(jù)庫管理需要的。#3 和 #4 PostgreSQL MVCC 特性的要求。
九、PostgreSQL和Oracle MySQL之間的區(qū)別
二者之間最大的不同是MVCC模型和共享池(shared pool)。
| 指標 | ORACLE | PostgreSQL |
|---|---|---|
| MVCC模型 | UNDO | Store previous |
| 實現(xiàn)方法 | Segment | record within block |
| 共享池 | exists | it does not exist |
MVCC模型的區(qū)別
為了增加并發(fā),必須遵循“讀操作不阻塞寫操作,寫操作不阻塞讀操作”的原則。為了實現(xiàn)這個原則,多版本并發(fā)控制(MVCC)理論被引入。Oracle使用UNDO段實現(xiàn)MVCC。而PostgreSQL存儲之前的記錄在數(shù)據(jù)塊中,它通過事務XID和事務的xmin、xmax來控制事務版本。
Shared Pool
PostgreSQL不提供共享池。這對于熟悉Oracle的用戶來說有點尷尬。共享池是Oracle中最基本和最重要的組件。PostgreSQL在進程級別提供SQL信息的共享能力,而不是共享池。換句話說,如果我們在同一個進程中多次執(zhí)行相同的SQL,它只會硬解析一次。
總結
以上是生活随笔為你收集整理的PostgreSQL的架构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 肠胃炎能不能吃芹菜
- 下一篇: 面向开发人员的Windows错误报告(W