postgresql 學習筆記 下載安裝 參數配置 主從流複製讀寫分離 備份與恢復 增刪改基本操作 python操作 用戶與權限

官網:https://www.postgresql.org

中文社區: http://www.postgres.cn/

官方文檔閱讀: https://www.postgresql.org/docs/

一、簡介:

  • 歷史、歷史版本

​ PostgreSQL 是對象關係型數據庫管理系統,任何人都可以以任何目的免費使用、修改和分發 PostgreSQL。
1989 年6月發佈了版本 1,1990年6月發佈了版本2, 版本 3 在1991年出現,增加了多存儲管理器的支持, 並且改進了查詢執行器、重寫了規則系統。
​ 在 1993 年間,隨着用戶的增加, 用於源代碼維護的時間日益增加並佔用了太多本應該用於數據庫研究的時間,爲了減少支持的負擔,伯克利的 POSTGRES 項目在版本 4.2 時正式終止。
​ 在 1994 年,Andrew Yu 和 Jolly Chen 向 POSTGRES 中增加了 SQL 語言的解釋器。並隨後用新名字Postgres95 將源代碼發佈到互聯網上供大家使用, 成爲最初 POSTGRES 伯克利代碼的開源繼承者。
Postgres95 的源代碼代碼量減少了25%,提高了性能和可維護性,比 POSTGRES 的版本 4.2 快 30-50%,並在前後端上進行了迭代更新。
​ 到了 1996 年,更名爲 PostgreSQL,版本號也從 6.0 開始。

  1. PostgreSQL和oracle是進程模式,MySQL是線程模式 128。
  2. PostgreSQL中有優秀的連接池軟件,如 pgbouncer 和 pgpool。pgadmin
  3. Standby 在應用日誌同步時,還可以提供只讀服務,這對做讀寫分離很有用。
  4. PostgreSQL 中可以有部分索引,也就是隻能表中的部分數據做索引,create index 可以帶 where 條件。同時 PostgreSQL 中的索引可以反向掃描,所以在PostgreSQL中可以不必建專門的降序索引了 。

二、安裝:

​ 開源社區開發,迭代迅速,雖然 9 版本穩,但經過幾個版本迭代,無論是性能還是功能上,更高的版本都有極大提升。而 11 版本是 2018 年出品,至今已有不錯完善。最新版爲 12 版本還在不斷完善測試。
​ 中文版官方文檔第9版已經全部翻譯,10、11也在不斷翻譯完善中,可見pg的開源社區強大。

sudo vim /etc/apt/sources.list.d/pgdg.list

deb http://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

sudo apt-get update

sudo apt install postgresql-11

service postgresql status  

安裝完成後,默認會:

(1)創建名爲"postgres"的Linux用戶

(2)創建名爲"postgres"、不帶密碼的默認數據庫賬號作爲數據庫管理員

(3)創建名爲"postgres"的表

# 查看日誌
cat /var/log/postgresql/postgresql-11-main.log

三、卸載:

sudo apt-get purge 'postgresql-*'
sudo apt-get autoremove 'postgresql-*'

四、Initdb、目錄介紹

​ 一般使用環境變量PGDATA指向數據目錄的根目錄。這個目錄是在安裝時指定的,所以
在安裝時需要指定一個合適的目錄作爲數據目錄的根目錄,而且,每一個數據庫實例都需要
有這麼一個目錄。目錄的初始化是使用initdb來完成的。

完成後,這數據根目錄下就會生成三個配置文件。

  • postgresql.conf:數據庫實例的主配置文件,基本上所有的配置參數都在此文件中。

  • pg_hba.conf:認證配置文件,配置了允許哪些IP的主機訪問數據庫,認證的方法是
    什麼等信息。

  • pg_ident.conf: "ident”認證方式的用戶映射文件。

    此目錄下還會生成如下一些子目錄。

  • base:默認表空間的目錄。

  • global: 一些共享系統表的目錄。

  • pg_clog: commit log 的目錄。

  • pglog:系統日誌目錄,在查詢一些系統錯誤時就可查看此目錄下的日誌文件。

  • pg_stat_tmp:統計信息的存儲目錄。

  • pg_tblsp:存儲了指向各個用戶自建表空間實際目錄的鏈接文件。

  • pg_twophase:使用兩階段提交功能時分佈式事務的存儲目錄。

  • pg_xlog: WAL日誌的目錄。

五、進入PG,基本命令

  1. 進入
# 默認只有 postgres 能夠使用 psql 命令
sudo -u postgres psql 
  1. 基本命令
\password:設置密碼
\q:退出
\h:查看SQL命令的解釋,比如\h select。
\?:查看psql命令列表。
\l:列出所有數據庫。
\c [database_name]:連接其他數據庫。
\d:列出當前數據庫的所有表格。
\d [table_name]:列出某一張表格的結構。
\du:列出所有用戶。
\e:打開文本編輯器。
\conninfo:列出當前數據庫和連接的信息。
  1. PG開啓、重啓、停止
 sudo /etc/init.d/postgresql start   # 開啓
 sudo /etc/init.d/postgresql stop    # 關閉
 sudo /etc/init.d/postgresql restart # 重啓

六、遠程連接PG

psql -h指定服務器 -U指定用戶 -d指定數據庫 -p指定端口

七、修改Linux用戶的密碼

sudo -u postgres passwd

八、配置數據庫以允許遠程連接訪問

  1. 修改監聽地址
sudo vim /etc/postgresql/11/main/postgresql.conf 
# 將 #listen_addresses = 'localhost' 的註釋去掉並改爲 listen_addresses = '*' 
  1. 修改可訪問用戶的IP段
sudo vim /etc/postgresql/11/main/pg_hba.conf 
# 在文件末尾添加: host all all 0.0.0.0 0.0.0.0 md5 ,表示允許任何IP連接
  1. 重啓數據庫
sudo /etc/init.d/postgresql restart

九、創建用戶

# 進入客戶端
sudo -u postgres psql

# 創建用戶並設置密碼
create user videt with password '123456';

# 將 videt 改爲超級管理員
alter user videt with superuser; 

十、創建、刪除數據庫

# 創建所有者爲 videt 的數據庫 testdb
create database testdb owner videt;
# 將 testdb 數據庫的所有權限賦予 videt,否則 videt 只能登錄psql,沒有任何數據庫操作權限:
grant all privileges on database testdb to videt;
# 刪除數據庫
drop database testdb

十一、基本數據庫操作命令

  1. 數據類型介紹

    • 數值類型
    • 貨幣類型(money 類型存儲帶有固定小數精度的貨幣金額。)
    • 字符類型
    • 日期、時間類型
    • 布爾類型
    • 枚舉類型
    • 幾何類型(點、矩形、圓…)
    • 網絡地址類型
    • 位串類型(bit)
    • 文本搜索類型(支持全文搜索,不太瞭解)
    • UUID類型
    • XML類型
    • JSON類型
    • 數組類型
    • 複合類型(不太瞭解)
    • 範圍類型(daterange、numrange…)
    • 對象標識符類型(不太瞭解)
    • 僞類型(不太瞭解)
    名字 別名 描述
    bigint int8 有符號的8字節整數
    bigserial serial8 自動增長的8字節整數
    bit [ (*n*) ] 定長位串
    bit varying [ (*n*) ] varbit 變長位串
    boolean bool 邏輯布爾值(真/假)
    box 平面上的普通方框
    bytea 二進制數據(“字節數組”)
    character [ (*n*) ] char [ (*n*) ] 定長字符串
    character varying [ (*n*) ] varchar [ (*n*) ] 變長字符串
    cidr IPv4或IPv6網絡地址
    circle 平面上的圓
    date 日曆日期(年、月、日)
    double precision float8 雙精度浮點數(8字節)
    inet IPv4或IPv6主機地址
    integer int, int4 有符號4字節整數
    interval [ *fields* ] [ (*p*) ] 時間段
    json 文本 JSON 數據
    jsonb 二進制 JSON 數據,已分解
    line 平面上的無限長的線
    lseg 平面上的線段
    macaddr MAC(Media Access Control)地址
    macaddr8 MAC (Media Access Control) 地址 (EUI-64 格式)
    money 貨幣數量
    numeric [ (*p*, *s*) ] decimal [ (*p*, *s*) ] 可選擇精度的精確數字
    path 平面上的幾何路徑
    pg_lsn PostgreSQL日誌序列號
    point 平面上的幾何點
    polygon 平面上的封閉幾何路徑
    real float4 單精度浮點數(4字節)
    smallint int2 有符號2字節整數
    smallserial serial2 自動增長的2字節整數
    serial serial4 自動增長的4字節整數
    text 變長字符串
    time [ (*p*) ] [ without time zone ] 一天中的時間(無時區)
    time [ (*p*) ] with time zone timetz 一天中的時間,包括時區
    timestamp [ (*p*) ] [ without time zone ] 日期和時間(無時區)
    timestamp [ (*p*) ] with time zone timestamptz 日期和時間,包括時區
    tsquery 文本搜索查詢
    tsvector 文本搜索文檔
    txid_snapshot 用戶級別事務ID快照
    uuid 通用唯一標識碼
    xml XML數據
  2. 基本操作命令

    # 創建新表 
    CREATE TABLE videt(name VARCHAR(20), signup_date DATE);
    # 插入數據 
    INSERT INTO videt(name, signup_date) VALUES('張三', '2013-12-22');
    # 查詢數據 
    SELECT * FROM videt;
    # 更新數據 
    UPDATE videt set name = '李四' WHERE name = '張三';
    # 刪除數據 
    DELETE FROM videt WHERE name = '李四' ;
    # 添加字段 
    ALTER TABLE videt ADD email VARCHAR(40);
    # 更新表結構 
    ALTER TABLE videt ALTER COLUMN signup_date SET NOT NULL;
    # 字段重命名
    ALTER TABLE videt RENAME COLUMN signup_date TO signup;
    # 刪除字段 
    ALTER TABLE videt DROP COLUMN email;
    # 數據表重命名
    ALTER TABLE videt RENAME TO backup_tbl;
    # 刪除數據表 
    DROP TABLE IF EXISTS backup_tbl;
    # 聚合函數、視圖、外鍵、事務、索引等操作 與 mysql 一致或相似
    

十二、配置參數

pg 配置優化

pg 配置參數詳解

Linux系統、版本、CPU、內存查看、硬盤空間

  1. 實操配置

    # 監聽
    listen_addresses= '*'                          
    
    # 日誌
    logging_collector= on
    log_directory= 'pg_log'                 
    # 只保留 7 天日誌,循環覆蓋,還有其他模式
    log_filename= 'postgresql-%a.log'
    log_truncate_on_rotation= on     		                                
    log_rotation_age= 1d             		                                
    log_rotation_size= 0 
    
    # 中國時區
    log_timezone= 'PRC'   
    timezone= 'PRC' 
    
    # 最大連接數  # 物理內存(GB)*1000*(1/4)/5  # 注意從庫需大於此數 
    max_connections= 750   
    # 指定分佈式事務中兩步提交準備事務的最大數量,參數值不應該小於max_connections參數值,這樣每一個session都可以至少有一個可用的準備事務。
    # max_prepared_transactions=max_connections  
    max_prepared_transactions= 750     
    
    # 給超級用戶提供的連接數
    superuser_reserved_connections= 10
    
    # TCP 空閒多長時間發 kpalive,多久沒回復後發送下一個kpalive,直到多少次連接中斷
    tcp_keepalives_idle= 180
    tcp_keepalives_interval= 10
    tcp_keepalives_count= 3
    
    # 用戶密碼認證及加密方法
    password_encryption= md5  
    
    # 大內存頁
    huge_pages= try  
    
    # 主從
    # 啓動搭建Hot Standby
    wal_level= hot_standby
    # 從庫打開
    # hot_standby= on
    # 主庫最多可以有多少個併發的standby數據庫,需要設置爲一個大於0的數
    max_wal_senders= 10 
    # 防止主庫生成 WAL 日誌太快,日誌還沒有來得及傳送到 standby 就被覆蓋,一個WAL日誌文件16M,wal_keep_segments設置爲64,將爲standby庫保留64個WAL日誌文件,佔用16*64=1GB磁盤空間
    wal_keep_segments=64
    # 主庫成爲新主庫的從庫?
    wal_log_hints=on
    
    # 提升性能 30%
    fsync=off
    # 聲明提交一個事務是否需要等待其把 WAL 日誌寫入磁盤後再返回
    synchronous_commit= off
    # 日誌緩存區的大小,-1 時自動計算
    wal_buffers=-1
    
    # 共享緩衝區
    shared_buffers= 4GB  # IF hugepage:主機內存*(1/4) ELSE:min(32GB,主機內存*(1/4))  
    # 工作內存
    work_mem= 4MB      # max(min(物理內存/4096, 64MB), 4MB)             
    # 維護工作內存
    maintenance_work_mem= 1GB             # min( 8G, (主機內存*1/8)/max_parallel_maintenance_workers )              
    autovacuum_work_mem= 1GB              # min( 8G, (主機內存*1/8)/autovacuum_max_workers )
     
    max_wal_size= 48GB                    # shared_buffers*2  
    min_wal_size= 12GB                    # shared_buffers/2  
    
    # 優化器假設一個查詢可以用的最大內存
    effective_cache_size= 8GB            # 主機內存/2 
    
    # 以下多爲新增參數
    # 設置維護命令(例如 CREATE INDEX) 允許的最大並行進程數
    # max_parallel_maintenance_workers= 2   # min( max(2, CPU核數/2) , 16 )   	
    # ax_parallel_workers_per_gather= 2    # min( max(2, CPU核數-4) , 24 )   
    
    # max_parallel_workers_per_gather+max_parallel_maintenance_workers 值應小於或等於 max_parallel_workers。
    # max_parallel_workers= 2              # max(2, CPU核數-4)  
    
    # max_sync_workers_per_subscription = 8  # min ( 32 , max(2, CPU核數-4) )    
       
    # autovacuum_max_workers= 8             # max(min( 8 , CPU核數/2 ) , 5)   
    # checkpoint 參數與commit
    # commit_delay= 0                       # range 0-100000, in microseconds
    # commit_siblings= 5 
    
  2. 配置文件說明

    auto.conf 配置文件優先級高於 conf 文件。值得注意的是 auto.conf這個文件必須在 psql 中使用 alter system 來修改,而conf可以直接在文本編輯器中修改。

  3. 查看配置參數是否需要重啓數據庫

    select namer context from pg_settings where name like '配置參數';
    

    需要重啓:postmaster、

    不需要重啓:sighup、backend

    特殊參數:internal 只讀、superuser超級用戶修改且只會影響自身、user只會影響自身連接

  4. 主要的連接配置項

    1. listen_addresses - 默認 localhost,常配 *
    2. port - 默認 5432
    3. max_connections - 最大併發連接數,只能服務器啓動時設置。hot standby 此值需大於 master。
    4. superuser_reserved_connections - 超級用戶連接數。普通用戶連接數=max_conn - super。
    5. tcp_keepalives_idle - 在一個TCP連接中空閒多長時間後會發送一個 keepalive 報文。默認值爲0,系統會將該參數設置爲 2 小時。
    6. tcp_keepalives_interval - 在一個空閒TCP連接中,定義在發送第一個TCP keepalive包後如果在該參數給定的時間間隔內沒有收到對端的回包,則開始發送第二個TCP keepalive包,若在給定的時間段內還沒有回包則發送第三個keepaliv包,直到達到 tcp_keepalives_count 次後仍沒有收到回包,則認爲連接已中斷,關閉連接。
    7. tcp_keepalives_count

    tcp 推薦配置:

    1. tcp_keepalives_idle = 180
    2. tcp_keepalives_interval = 10
    3. tcp_keepalives_count = 3
  5. 主要的內存配置項

    1. shared_buffers - 共享內存緩衝區數量/大小。 postgresql 對數據操作時都要先將數據從磁盤讀取到內存中,然後進行更新,最後再將數據寫回磁盤。shared_buffers的功能就是用於存放從磁盤讀取的數據。 此緩衝區爲緩存數據塊所用,且是放在共享內存中的。該值必須大於16,並且至少是 max_connections 的兩倍。通常合理的 shared_buffers 值設爲物理內存的 25%~40% 。再大可能與文件系統緩存出現雙緩存問題。

    2. **temp_buffers - 臨時緩衝區, 屬於本地內存。用於數據庫會話訪問臨時表數據,**系統默認值爲8M。可以在單獨的 session 中對該參數進行設置,尤其是需要訪問比較大的臨時表時,將會有顯著的性能提升。

    3. **work_mem - 工作內存或者操作內存。**其負責內部的sort和hash操作,合適的work_mem大小能夠保證這些操作在內存中進行。定義太小的話,sort或者hash操作將需要與硬盤進行swap,這樣會極大的降低系統的性能;太大的話致使在能夠在內存中完成的操作數量減少,其他的部分需要與磁盤進行swap操作,增加IO降低性能。系統提供的默認值是1M,在實際的生產環境中,要對系統監控數據進行分析,作出最好的選擇。
      大致有兩種方式:估計方法與計算方法。第一種是可以根據業務量的大小和類型,一般語句運行時間,來粗略的估計一下。第二種方式是通過對數據庫的監控,數據採集,然後計算其大小。總之合適的大小對系統的性能至關重要。 在實際的維護中可以通過explain analyze分析語句的work_mem大小是否合適。在語句中設置work_mem參數的大小可以充分利用內存,提高語句的執行效率。
      對於work_mem內存分配時還要考慮數據庫的併發情況,max_connections決定了系統的最大的併發連接數。不論如何調整work_mem都要考慮max_connections*work_mem+shared_buffers+temp_buffers+maintenance_work_mem+操作系統所需內存不能夠超過整個的RAM大小,這是非常重要的。
      work_mem參數對系統的性能是如此的重要,讓其實時的適應數據庫的運行狀況顯的不太可能,但是可以通過對數據庫運行週期的監控,總結相應的數據,然後定製一個專用的腳本,專門用來修改work_mem的大小,使其階段性的更加適應系統的狀況

    4. **maintence_work_mem - 維護工作內存 。**主要用於維護操作使用的最大內存數,如 vacuum、create index、alert table add foreign key。 在對整個數據庫進行VACUUM或者較大的index進行重建時,適當的調整該參數非常必要。 通常情況實例不會有太多這樣的操作,可以設置的比 work_mem 大,以提高維護操作的速度。

      在啓用了autoacuum功能的情況下,該參數不能配置的過大。

    5. max_stack_depth - 聲明服務器執行堆棧的最大安全深度, 通常保持默認值。

  6. 配置日誌策略

    這些參數修改都是需要重啓生效的

    1. 打開日誌收集

      logging_collector = on
      log_directory = 'pg_log' 
      
    2. 日誌策略

      1. 每天生成一個新的文件

        log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
        log_truncate_on_rotation = off
        log_rotation_age = 1d
        log_rotation_size = 0
        
      2. 每當日誌寫滿一定的大小,(如10M),則切換一個日誌

        log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
        log_truncate_on_rotation = off
        log_rotation_age = 0
        log_rotation_size = 10M
        
      3. 只保留七天的日誌,進行循環覆蓋

        log_filename = 'postgresql-%a.log'
        log_truncate_on_rotation = on
        log_rotation_age = 1d
        log_rotation_size = 0
        
  7. 預寫式日誌的配置項

    1. **wal level - 決定有多少信息可寫入WAL 日誌中。**改變這個參數需要重啓數據庫服務。默認值 “minimal”,即只寫入在數據庫崩潰或突然關機後進行恢復時所需要的信息。設置爲“archive”,會添加WAL歸檔需要的記錄;設置爲“ hot_standby”,則會添加一些備庫只讀查詢需要的信息。如果想使用 WAL 日誌做歸檔,用歸檔作增量恢復,則需要把此參數設置爲“archive”;如果要搭建hot_standby備庫,則需要把此參數設置爲“hot_standby”。

    2. **fsync - 表示是否使用fsync()系統調用(或等價調用),把文件系統中的髒頁刷新到物理磁盤,確保數據庫在操作系統或者硬件崩滯的情況下可恢寫到誰與改變這個參數需要重新裝載配置文件。**此參數默認值爲“on”,大多數情況下,都應該把這個參數設置爲 “on”。但當此數據庫不是很重要,或者此數據庫中的數據很容易從其他系統中重建出來時,爲了提高性能,可以把此參數設置爲“off”。

    3. synchronous_commit - 聲明提交一個事務是否需要等待其把 WAL 日誌寫入磁盤後再返回,默認值是“on”。爲了事務的安全,通常都應當設置爲 “on”。一般用戶可以直接改變此參數值,且在提交一些不重要的事務時,可以先把此參數設置爲 “off”,然後再提交,這樣可以提高性能。

    4. **wal_sync_method - 用來指定向磁盤強制更新 WAL 日誌數據的方法。**此選項一般保持默認值就可以了。如果 fsync 的設置爲“off”,那麼這個設置就沒有意義。

    5. **wal_buffers - 指定放在共享內存裏用於存儲 WAL 日誌的緩衝區數目。**默認值爲 8,即 64KB 改變這個參數需要重啓數據庫服務。這個設置值只需要能夠保存一次事務生成的 WAL 數據即可,這些數據在每次事務提交時都會寫入磁盤。通常此參數設置爲 8〜128 (即64KB〜1MB)就可以了。

    6. ········

十三、創建用戶、角色

  1. 創建用戶

    # CREATE USER指令創建的用戶默認是有登錄權限的,CREATE ROLE沒有。
    CREATE ROLE rolename;
    CREATE USER username;
    # CREATE ROLE username WITH LOGIN == CREATE USER username;
    
  2. 權限介紹

    key
    superuser 超級用戶
    createuser 是否有執行 創建數據庫的權限
    inherit 是否有創建其他用戶的權限
    login 是否可以連接到數據庫
    in role role_name 加入到角色

    以上 key 都有反向 key,如 nologin 等

  3. 權限管理
    pg中任何數據庫對象都是屬於某個用戶的。自己創建的數據庫對象,自己擁有該對象的所有權限,其他人沒有刪除、修改該對象的權限。

    修改用戶權限的兩種方式

    1. alter role

      ALTER ROLE username WITH NOLOGIN;
      
    2. grant
      grant 擁有兩個功能:

      1. 讓某個用戶加入某個角色,從而擁有該角色的權限。

      2. 把某些數據庫邏輯結構對象的操作權限賦予某個用戶或某個角色

        grant some_privileges on database_object_type object_name to role_name;
        

        創建只讀用戶:

        先把創建表權限收回
        			revoke create on schema public from public;
        			create user readonly with password ‘123456’;
        			grant select on all tables in schema public to readonly;
        			# 上述命令將現有表權限賦予 readonly,新增表權限也自動賦予的話執行如下:
        			alter default privileges in schema public grant select on tables to readonly;
        			# 上述只給schema下名爲public的表賦予了只讀權限,訪問其他schema下的表則重複執行上述步驟
        

十四、備份與恢復

  1. pg_dump
  • 備份數據庫

    pg_dump mydb > db.sql
    
  • 備份數據表

    pg_dump -t mytab mydb > db.sql
    
  1. pg_dumpall

    • 備份所有數據庫

      pg_dumpall > db.out
      
    • 恢復所有數據庫

      psql -f db.out postgres
      
  2. pg_restore
    • 恢復數據庫

      pg_restore -d newdb db.sql
      
  3. 文件系統級備份

    使用壓縮工具直接將數據庫的數據目錄進行備份

    tar -cf backup.tar /usr/local/pgsql/data
    
  4. 連續歸檔和時間點恢復

    1. pg_basebackup(全備)

      pgsql 提供的一個方便基礎備份的工具,經常用來搭建流複製環境,屬於物理備份,邏輯備份是 pg_dump 可遠程執行。

      pg_basebackup -h host -D 數據目錄 -U postgres -F p -l label -P -v -X fetch  -R
      # 示例。 需要注意的是,指定目錄必須爲空
      pg_basebackup -h 10.5.5.235 -D /var/lib/postgresql/11/main -U postgres -F p -l label -P -v -X fetch  -R
      
      • -P 或 -progress :允許在備份過程中實時地打印備份的進度。
      • -v 打印出備份進度的詳細信息
      • -l label 或 -label=label :指定備份的一個標識
      • -X fetch 備份時會把備份中產生的xlog文件也自動備份出來
      • -R 備份生成一個 recovery.conf,啓動備份庫時只需簡單修改此文件
      • 理論上一個數據庫可以被幾個 pg_basebackup 同時連接上去,但爲了不影響主庫的性能,
        建議最好還是一個數據庫上同時只有一個 pg_basebackup 在做備份。
      • PostgreSQL9.2 之後支持級連複製,所以在9.2及之後的版本中,pg_basebackup 也可以從另一個Standby庫上做基礎備份,但從Standby備份有以下一些注意事項:
        • 備份中沒有備份歷史文件。
        • 不確保所有需要的 WAL 文件都備份了,如果想確保,需要加命令行參數“-X”。
        • 如果在備份過程中Standby被提升爲主庫,則備份會失敗。
        • 要求主庫中打開了 “ fiill_page_writes”參數,WAL 文件不能被類似 pg_compresslog 的工具去掉fiill-page writes信息
    2. PostgreSQL利用全備與WAL日誌恢復數據庫

十五、主從配置(流複製)

  • PITR

    ​ PostgreSQL 在數據目錄的 pg.xlog 子目錄中始終維護着一個WAL日誌文件。這個日誌文件用於記錄數據庫數據文件的每次改變。當初設計這個日誌文件的主要目的是爲了在數據庫異常崩潰後,能夠通過重放最後一次checkpoint 點之後的日誌文件,把數據庫推到一致狀態。

    ​ 事實上,這種日誌文件機制,也提供了一種數據庫熱備份方案:在把數據庫使用文件系統的方式備份出來的同時把相應的WAL日誌也備份出來。雖然直接拷貝數據庫數據文件會導致拷貝出來的文件不一致(比如拷貝的多個數據文件不是同一個時間點文件;拷貝一個 8KB 的數據塊時,也存在不一致的情況:假設剛拷貝完前 4KB 的塊,數據庫又寫了後 4KB 的塊內容,那麼所拷貝的塊就不是一個完整的數據塊),但因爲有了 WAL日誌,即使備份出來的數據塊不一致,也可以重放備份開始後的 WAL 日誌,把備份的內容推到一致狀態。由此可見,有了 WAL 日誌之後,備份數據庫時不再需要完美的一致性備份了,備份中任何數據的非一致性都會被重放 WAL 日誌文件進行糾正,所以在備份數據庫時可以通過簡單的 cp 命令或 tar 等拷貝、備份文件來實現數據庫的在線備份。不停地重放 WAL 日誌就可以把數據推到備份結束後的任意一個時間點,這就是基於時間點的備份,英文爲“Point-in-Time Recovery”,縮寫爲 PITR。

    ​ 使用簡單的 cp 命令或其他命令把數據庫給在線拷貝出來的備份,被稱爲基礎備份。後續 WAL 日誌的備份與此基礎備份構成一個完整備份。把基礎備份恢復到另一臺機器,然後不停地從原始數據庫機器上接收 WAL 日誌,在新機器上持續重放 WAL 日誌,這樣就可以在任何時間內在另一臺機器上打開這個新產生的數據庫,它擁有當前數據庫的最新數據狀態。這個新機器上的數據庫被稱爲 Standby 數據庫。

    ​ 當前的主數據庫出現問題或主數據庫的機器出現故障無法正常提供服務時,可以把 Standby 數據庫打開提供服務,從而實現高可用。

    ​ 把 WAL 日誌傳送到另一臺機器上的方法有兩種,一種是通過 WAL 歸檔日誌實現,一種是被稱爲流複製的方法。

  • 流複製

    ​ 使用流複製時,只要Primary數據庫一產生日誌,就會馬上傳遞到Standby數據庫。流複製傳遞日誌的方式有兩種,一種是異步方式,一種是同步方式。

    ​ 若使用同步方式,在Primary數據庫提交事務時,一定會等到WAL 日誌傳遞到Standby後纔會返回,這樣可以做到Standby數據庫完全與Primary數據庫同步,沒有一點落後,當主備庫切換時使用同步方式可以做到零數據丟失。

    ​ 異步方式,則是事務提交後不必等日誌傳遞到Standby就即可返回,所以Standby數據庫通常也只比Primary數據庫落後很少(如幾秒)的時間。

    ​ 流複製功能不僅能傳遞WAL日誌,也能傳遞其他數據,如數據文件。

  • 異步流複製

    1. 編輯 postgres.conf

      要使用流複製,主庫一定要配置的參數

      # max_wal_senders 最多有幾個流複製連接
      max_wal_senders= 5
      # 流複製超時時間
      wal_sender_timeout=60s
      # 最大連接,此值從庫必須大於主庫
      max_connections=101
      # 熱備模式
      wal_level= hot_standby
      # WAL日誌歸檔 歸檔模式與歸檔命令
      # archive_mode= on
      # archive_command='scp %p [email protected],100:/backup/pgarch/%f'
      # 使用上面拷貝WAL文件的方式來同步主、備數據庫之間數據時,備庫會落後主庫一個WAL日誌文件,具體落後多長時間取決於主庫上生成一個完整的WAL文件所需要的時間。
      
    2. 編輯 pg_hba.conf

      # 增加連接許可,trust不需要密碼
      # 允許所有用戶從 10.5.5.235/32 的網絡上發起到本數據庫的流複製連接,使用md5的密碼認證.
      host  replication  all 10.5.5.235/32	md5
      host  all          all 0.0.0.0/0        trust
      
    3. 清空從庫數據目錄,執行 pg_basebackup 備份至備份機器數據目錄下

    4. 修改 全備後從庫生成的 recovery.conf

      # 該節點是從庫
      standby_mode=on
      # 從庫機器信息和連接用戶
      primary_coninfo='host=host port=5432 user=用戶名 password=密碼'
      # 說明恢復到最新狀態
      recovery_target_timelint='latest'
      
    5. 編輯修改 postgresql.conf

      # 熱備模式
      wal_level=hot_standby
      # 最大連接,從庫要大於主庫
      max_connections=101
      # 說明本機不僅用於數據歸檔,還可以用於數據查詢?
      hot_standby=on
      # 流備份的最大延遲時間
      max_standby_streaming_delay=30s
      # 向主機彙報本機狀態的間隔時間
      wal_receiver_status_interval=10s
      # 出現錯誤複製向主機彙報
      hot_standby_feedback=on
      
    6. sudo service postgresql restart

    7. 查看相關進程驗證是否配置成功

      ps aux | grep postgres
      
    8. 在主庫查看主從情況

      select client_addr, sync_state from pg_stat_replication;
      
  • 同步流複製

    PostgreSQL的流複製是異步的,異步的缺點是Standby上的數據落後於主庫上的數據,
    如果使用Hot Standby做讀寫分離,就會存在數據一致性的問題,這對於一些一致性較高的應
    用來說是不可接受的。所以PostgreSQL從9.1版本之後提供了同步流複製的架構。同步複製
    要求在數據寫入Standby數據庫後,事務的commit才返回,所以Standby庫出現問題時,會
    導致主庫被hang住。解決這個問題的方法是啓動兩個Standby數據庫,這兩個Standby數據
    庫只要有一個是正常的,就不會讓主庫hang住。所以在實際應用中,同步流複製,總是有1個主庫和2個以上的Standby庫。

    略。

  • 檢查流複製情況

    select * from pg_stat_replication;
    
    列名稱 類 型 解 釋
    pid integer 數據庫上WAL sender進程的進程ID
    usesysid oid 登錄主庫的流複製用戶的OID
    usename name 登錄主庫的流複製用戶的名稱
    applicationname text 流複製連接中連接參數application name指定的字符申
    clientaddr inet Standby的IP地址
    clienthostname text Standby的主機名。注意,只有打開了 log_hostname和使用了 IP 連接時,這列纔會顯示主機名,否則顯示爲空
    client port integer 流複製連接中Standby端的socket端口
    backendstart timestamp with time zone WAL sender進程啓動的時間。實際也是Standby連接過來的時間, 因爲只有Standby連接過來時,纔會啓動一個WAL sender進程,連 接中斷後,WAL Sender進程也會中止
    state text WAL sender進程的狀態
    sentlocation text 在流複製連接上發送WAL時的發送位置
    writelocation text Standby端寫WAL日誌的位置
    flushjocation text Standby端寫WAL日誌刷新到磁盤的位置
    replay location text Standby端重放WAL日誌的位置
    sync priority integer 同步複製時不同Standby的優先級,對於異步複製,此字段總是0
    sync__state text 同步的狀態,可以爲“sync”、“ potential”、° async"
  • 流複製的注意事項

    • wal_keep_segments

      使用流複製建好備庫後,如果備庫由於各種原因接收日誌較慢,而主庫很快,這容易導
      致主庫上的WAL日誌還沒有傳遞到備庫就被回捲覆蓋掉了,如果被覆蓋掉的WAL日誌文件
      又沒有歸檔備份,那麼備庫就再也無法與主庫同步了,這會導致備庫需要重新搭建。

    • vacuum_defer_cleanup_age

十六、Python操作

psycopg2是非常小,快速,穩定的。 您不需要單獨安裝此模塊,因爲默認情況下它會隨着Python 2.5.x版本一起發佈。

  • 安裝

    pip3 install python-psycopg2
    
  • 連接到數據庫

    import psycopg2
    
    #  如果數據庫不存在,那麼它將自動創建,最後將返回一個數據庫對象
    conn = psycopg2.connect(database="testdb", user="postgres", password="pass123", host="127.0.0.1", port="5432")
    
    print("Opened database successfully")
    
  • 創建表

    import psycopg2
    
    conn = psycopg2.connect(database="testdb", user="postgres", password="pass123", host="127.0.0.1", port="5432")
    print("Opened database successfully")
    
    cur = conn.cursor()
    cur.execute('''CREATE TABLE COMPANY
           (ID INT PRIMARY KEY     NOT NULL,
           NAME           TEXT    NOT NULL,
           AGE            INT     NOT NULL,
           ADDRESS        CHAR(50),
           SALARY         REAL);''')
    print("Table created successfully")
    
    conn.commit()
    conn.close()
    
  • 插入操作

    import psycopg2
    
    conn = psycopg2.connect(database="testdb", user="postgres", password="pass123", host="127.0.0.1", port="5432")
    print("Opened database successfully")
    
    cur = conn.cursor()
    
    cur.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
          VALUES (1, 'Paul', 32, 'California', 20000.00 )");
    
    cur.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
          VALUES (2, 'Allen', 25, 'Texas', 15000.00 )");
    
    cur.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
          VALUES (3, 'Teddy', 23, 'Norway', 20000.00 )");
    
    cur.execute("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) \
          VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 )");
    
    conn.commit()
    print("Records created successfully");
    conn.close()
    
  • SELECT操作

    import psycopg2
    
    conn = psycopg2.connect(database="testdb", user="postgres", password="pass123", host="127.0.0.1", port="5432")
    print("Opened database successfully")
    
    cur = conn.cursor()
    
    cur.execute("SELECT id, name, address, salary  from COMPANY")
    rows = cur.fetchall()
    for row in rows:
       print("ID = ", row[0])
       print("NAME = ", row[1])
       print("ADDRESS = ", row[2])
       print("SALARY = ", row[3], "\n")
    
    print("Operation done successfully");
    conn.close()
    
  • 更新操作

    import psycopg2
    
    conn = psycopg2.connect(database="testdb", user="postgres", password="pass123", host="127.0.0.1", port="5432")
    print("Opened database successfully")
    
    cur = conn.cursor()
    
    cur.execute("UPDATE COMPANY set SALARY = 25000.00 where ID=1")
    conn.commit
    print("Total number of rows updated :", cur.rowcount)
    
    cur.execute("SELECT id, name, address, salary  from COMPANY")
    rows = cur.fetchall()
    for row in rows:
       print("ID = ", row[0])
       print("NAME = ", row[1])
       print("ADDRESS = ", row[2])
       print("SALARY = ", row[3], "\n")
    
    print("Operation done successfully");
    conn.close()
    
  • 刪除操作

    import psycopg2
    
    conn = psycopg2.connect(database="testdb", user="postgres", password="pass123", host="127.0.0.1", port="5432")
    print("Opened database successfully")
    
    cur = conn.cursor()
    
    cur.execute("DELETE from COMPANY where ID=2;")
    conn.commit
    print("Total number of rows deleted :", cur.rowcount)
    
    cur.execute("SELECT id, name, address, salary  from COMPANY")
    rows = cur.fetchall()
    for row in rows:
       print("ID = ", row[0])
       print("NAME = ", row[1])
       print("ADDRESS = ", row[2])
       print("SALARY = ", row[3], "\n")
    
    print("Operation done successfully");
    conn.close()
    

十七、其它

  • pg_ctl 命令使用

  • 預寫式日誌(WAL)寫優化

    ​ 數據文件修改時,先將操作記錄到日誌中,數據文件修改後的髒頁不會馬上刷新至磁盤。在產生 chekpoint 時,會將髒頁刷新至磁盤並向日志文件寫入檢查點記錄,確保之前的所有信息都已經寫到數據文件。

    • 檢查點發生的頻率控制:
      • checkpoint_timeout
      • checkpoint_segment
    • PG 檢查 timeout 接近 warning 就報警:
      • checkpoint_warning
    • 太多髒頁刷新至磁盤導致過多 I/O,導致性能出現大的抖動:
      • checkpoint_completion_target
    • WAL 緩存:
      • wal_buffers 默認 4 MB
  • 熱備份其它方案

    文件系統或塊設備級別的快照功能,LVM 的快照功能,這要求數據庫建立在 LVM 上。

    Logical Volume Manager(邏輯卷管理)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章