MathJax

MathJax-2

MathJax-3

Google Code Prettify

置頂入手筆記

EnterproseDB Quickstart — 快速入門筆記

由於考慮採用 EnterpriseDB 或是直接用 PostgreSQL 的人,通常需要一些入手的資料。這邊紀錄便提供相關快速上手的簡單筆記 ~ 這篇筆記以 資料庫安裝完畢後的快速使用 為目標,基本紀錄登入使用的範例:

2016年5月10日 星期二

Point-in-Time Recovery 操作筆記

環境:既有運作的一個 PostgreSQL instance,其資料夾位在/home/aaa/pgsql/9.5/data/,沒有 tablespace,資料庫的 superuser 為 aaa。
WAL archived 目錄亦放置於同一台主機上/home/aaa/pgsql/wals 裡面。
以下備份操作都在同一主機上進行備份與還原。


1. 在 postgresql.conf 編輯:

[aaa@localhost ~]$ vim /home/aaa/pgsql/9.5/data/postgresql.conf

wal_level = archive    # hot_standby、logical 也可以
archive_mode = on
archive_command = 'cp %p /home/aaa/pgsql/wals/%f'
max_wal_senders = 1    # 允許用 pg_basebackup 連入資料庫

2. 在 pg_hba.conf 編輯,允許待會全備份的連線

[aaa@localhost ~]$ vim /home/aaa/pgsql/9.5/data/pg_hba.conf

host    replication     aaa             127.0.0.1/32            trust

3. 重新啟動資料庫

[aaa@localhost ~]$ pg_ctl -D /home/aaa/pgsql/9.5/data/ restart

4. 使用 pg_basebackup 指令進行資料庫全備份,弄成壓縮檔

[aaa@localhost ~]$ mkdir /home/aaa/pgsql/total/
[aaa@localhost ~]$ pg_basebackup -p 5432 -Ft -z \
> -D /home/aaa/pgsql/total/
NOTICE:  pg_stop_backup complete, all required WAL segments have been archived

5. 資料庫繼續進行服務:插入一些資料進去,停頓三十秒,並紀錄時間,如此重複三次。

[aaa@localhost ~]$ psql -p 5432 -d postgres -c "BEGIN;CREATE TABLE \
> dummy1 AS SELECT * FROM pg_class;COMMIT; \
> SELECT pg_sleep(30);SELECT now();"
             now            
-------------------------------
2016-05-10 16:10:01.719448+08
(1 row)

[aaa@localhost ~]$ psql -p 5432 -d postgres -c "BEGIN;CREATE TABLE \
> dummy2 AS SELECT * FROM pg_class;COMMIT; \
> SELECT pg_sleep(30);SELECT now();"
             now            
-------------------------------
2016-05-10 16:11:57.732774+08
(1 row)

[aaa@localhost ~]$ psql -p 5432 -d postgres -c "BEGIN;CREATE TABLE \
> dummy3 AS SELECT * FROM pg_class;COMMIT; \
> SELECT pg_sleep(30);SELECT now();"
             now            
-------------------------------
2016-05-10 16:14:14.526662+08
(1 row)

6. 模擬資料庫發生異常。使用 pg_ctl 的 immediate mode 會造成關檔不完全,用此進行模擬:


[aaa@localhost ~]$ psql -p 5432 postgres\ > -c "BEGIN;SELECT \
> pg_sleep(3);CREATE TABLE \
> dummy4 AS SELECT * FROM \
> pg_class; SELECT \
> pg_sleep(30);SELECT now(); \
> Commit;"
WARNING:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the current transaction
 and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat your command.
server closed the connection unexpectedly
       This probably means the server terminated abnormally
       before or while processing the request.
connection to server was lost
[aaa@localhost ~]$ # 左方過個四~五秒再執行強至關閉指令
[aaa@localhost ~]$ 
[aaa@localhost ~]$ pg_ctl -D \
> /home/aaa/pgsql/9.5/data/ \
> -m immediate stop
waiting for server to shut down.... done
server stopped



目前資料庫的 instance 已經有部份損毀。利用既有的內容完成回復作業

7. 先將突然中止的 /home/aaa/pgsql/9.5/data/ 重新命名,留作備用;接著解壓縮全備份

[aaa@localhost ~]$ mv /home/aaa/pgsql/9.5/data/ \
> /home/aaa/pgsql/9.5/data.crashed
[aaa@localhost ~]$ mkdir /home/aaa/pgsql/9.5/data/
[aaa@localhost ~]$ chmod 700 /home/aaa/pgsql/9.5/data/
[aaa@localhost ~]$ tar zxf /home/aaa/pgsql/total/base.tar.gz \
> -C /home/aaa/pgsql/9.5/data/

8. 移除目前 /home/aaa/pgsql/9.5/data/ 中被一併打包的 pg_xlog/ 內容以及運作標記的 lock

[aaa@localhost ~]$ rm /home/aaa/pgsql/9.5/data/postmaster.*
[aaa@localhost ~]$ rm /home/aaa/pgsql/9.5/data/pg_xlog/*

9. 將/home/aaa/pgsql/9.5/data.crashed/ 裡面的 pg_xlog/ 內容放到等著回復的/home/aaa/pgsql/9.5/data/pg_xlog/裡面

[aaa@localhost ~]$ cp -rp /home/aaa/pgsql/9.5/data.crashed/pg_xlog/* \
/home/aaa/pgsql/9.5/data/pg_xlog/

10. 設置 recovery.conf,指定回復到先前 dummy2 表格建立後,dummy3 建立之前

[aaa@localhost ~]$ vim /home/aaa/pgsql/9.5/data/recovery.conf

restore_command = 'cp /home/cchsu/pgsql/wala95/%f %p'
recovery_target_time = '2016-05-10 16:11:59'

11. 啟動資料庫,並同時觀察狀況

[aaa@localhost ~]$ pg_ctl -D \
> /home/cchsu/pgsql/95stdby2/ \
> start
server starting
bash-4.3$ LOG:  redirecting log output to logging collector process
HINT:  Future log output will appear in directory "pg_log".
[aaa@localhost ~]$ tail -f \
> /home/aaa/pgsql/9.5/data/ \ > pg_log/postgresql-2016-05- \
10_170312.log
LOG:  starting point-in-time recovery to 2016-05-10 16:11:59+08
LOG:  restored log file "00000004.history" from archive
LOG:  restored log file "000000040000000000000028" from archive
LOG:  redo starts at 0/28000060
LOG:  consistent recovery state reached at 0/28000130
LOG:  database system is ready to accept read only connections
LOG:  restored log file "000000040000000000000029" from archive
LOG:  recovery stopping before commit of transaction 1449, time 2016-05-10 16:12:31.941565+08
LOG:  recovery has paused
HINT:  Execute pg_xlog_replay_resume() to continue.


12. 進入資料庫看

postgres=# select tablename from pg_tables
postgres-#  where schemaname = 'public'
postgres-#  order by tablename;
     tablename   
-------------------
 dummy1
 dummy2
(2 rows)
postgres=# select pg_is_in_recovery();
 pg_is_in_recovery
-------------------
 t
(1 row)

由此確定資料庫僅回復到所指定的位置了

13. 確定回復目前狀態,正常啟用

postgres=# SELECT pg_xlog_replay_resume();
 pg_xlog_replay_resume
-----------------------
(1 row)

postgres=# select pg_is_in_recovery();
 pg_is_in_recovery
-------------------
 f
(1 row)


參考資料:



PostgreSQL Point-in-time Recovery (Incremental Backup)

Point In Time Recovery From Backup using PostgreSQL Continuous Archving - Zetetic

PostgreSQL Point-in-time Recovery (using WAL) | Madilator

Point in time recovery: PITR using pg_basebackup with PostgreSQL 9.2

The Scale-Out Blog: Simple HA with PostgreSQL Point-In-Time Recovery

The Internals of PostgreSQL : Chapter 9 Write Ahead Log (WAL)

select * from depesz; » Blog Archive » Write Ahead Log + Understanding postgresql.conf: checkpoint_segments, checkpoint_timeout, checkpoint_warning

Korry Douglas-PostgreSQL - The Comprehensive Guide

2016年5月8日 星期日

PostgreSQL 9.x 連到 Greenplum

Greenplum 基於 PostgreSQL 8.x,照理說要很像 PostgreSQL;那麼兩類資料庫要跨接時,能怎麼做?目前我找到的方式,有使用 DBLink,或是用 postgres_fdw 這個 Foreign Data Wrapper 套件。

使用 DBLink 連到 Greenplum,找到的都是實驗性質的使用。所以在此我用 Foreign Data Wrapper 接到 Greenplum。

Foreign Data Wrapper 是一個 PostgreSQL 的擴充套件(Extension),所以要使用  Foreign Data Wrapper,要先在所連線的資料庫裡面建立 Extension。例如,以下在 postgres 下為例:

postgres=# CREATE EXTENSION postgres_fdw;

若想要之後每次都產生 database 時,都自動加上這個套件的話,則將該套件建立到 template1:

[postgres ~]$ psql -d template1 -c 'create extension postgres_fdw;'

接著便開始要進行設定。

連線設定,要先使用 CREATE SERVER 指令,使用連線字串設定方式設定連線到 Greenplum 的資訊。在此 Greenplum 的 入口 IP (Master Instance)為 192.168.238.152,port 為 5432:
postgres=# CREATE SERVER gp_db
postgres-# FOREIGN DATA WRAPPER postgres_fdw
postgres-# OPTIONS (host '192.168.238.152', port '5432', dbname 'fdwtest');
CREATE SERVER

接著設定登入帳密:值得注意的是,一般帳密都是設在連線字串裡面,不過 Foreign Data Wrapper 則是另外用 CREATE USER MAPPING 指令設定的:

postgres=# CREATE USER MAPPING FOR user4gpfdw SERVER gp_db
postgres-# OPTIONS (user 'fdwuser',password 'fdwuser');
CREATE USER MAPPING

到目前為止,Foreign Data Wrapper 的資訊已經建立完畢了。

再來便是要在 Greenplum 上面建立一個可以連線的測試資料表格。
在 Greenplum 上:

gpadmin=# \c fdwtest brandon
You are now connected to database "test" as user "brandon".
fdwtest=# SET search_path TO testing;
SET
fdwtest=# CREATE TABLE productest
fdwtest-# (name VARCHAR(40), prod_id INTEGER)
fdwtest-# DISTRIBUTED BY (prod_id);
CREATE TABLE

接著,回到 PostgreSQL 上,建立一個上面已經存在於 Greenplum 上的資料表:

postgres=# CREATE FOREIGN TABLE foreigntab(
postgres(# name TEXT,
postgres(# id INTEGER)
postgres-# SERVER gp_db
postgres-# OPTIONS (schema_name 'testing', table_name 'productest');
CREATE FOREIGN TABLE

可以在 Greenplum 上檢查一下連線資訊:

gpadmin=# SELECT datname,usename,client_addr,application_name
gpadmin=#  FROM pg_stat_activity;
  datname | usename |  client_addr   | application_name
 ---------+---------+----------------+------------------
  gpadmin | brandon |                | psql
  fdwtest | fdwuser | 192.168.62.178 | postgres_fdw
  fdwtest | brandon | 192.168.62.178 | psql
(3 rows)

以上可見 postgres_fdw 連線進入的資訊,表示 postgres_fdw 有成功連線到 Greenplum 。

使用會發現,要直接輸入資料,會出現下列錯誤:
Greenplum Database does not support REPEATABLE READ transactions

所以要指定 transaction level,再輸入資料,才能避免上述錯誤:
postgres=# START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION
Time: 0.331 ms

postgres*=# INSERT INTO foreigntab VALUES ('rastberry',101);
INSERT 0 1

Time: 220.690 ms
postgres*=# -- 這時資料輸入進去了。 
postgres*=# -- 從 PostgreSQL裡面檢查一下資料
postgres*=# SELECT * FROM foreigntab;
    name   | prod_id 
-----------+---------
 grava     |     100
 pen       |       1
 rastberry |     101
 pencil    |       2
(4 rows)

Time: 169.112 ms
postgres*=# END;
COMMIT

Time: 110.171 ms

要透過 postgres_fdw 存取 Greenplum 上的資料,都需要向上面所示,使用 SERIALIZABLE 的交易等級才行。

現在到 Greenplum 上直接檢查,也會看到剛剛從 PostgreSQL 輸入進來的資料:

gpadmin=# SELECT * FROM productest;
    name   | prod_id 
-----------+---------
 pen       |       1
 pencil    |       2
 grava     |     100
 rastberry |     101
(4 rows)


[Update 20190325] 如果要用 IMPORT FOREIGN SCHEMA 簡化匯入外部表的方式,也需要指定 isolation level。跟上面一樣,CREATE SERVER 以及 CREATE USER MAPPING 不用包在這個 Transaction 裡面(這邊延續上面的環境~)
postgres=# CREATE SCHEMA gptables;
CREATE SCHEMA
postgres=# BEGIN;
BEGIN
postgres=# SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET
postgres=# IMPORT FOREIGN SCHEMA testing LIMIT TO (productest) FROM SERVER gp_db INTO gptables;
IMPORT FOREIGN SCHEMA
postgres=# COMMIT;
COMMIT
postgres=# 



參考資料:

這是一個 postgres_fdw 的操作介紹
A look at Foreign Data Wrappers Craig Kerstiens 
以下是此次實作中,用到的 Greenplum 資料
What are the Table Distribution Policy in Greenplum - A Web Portal for Greenplum Database Professionals!
SET TRANSACTION | Pivotal Greenplum Database Docs

2016年3月15日 星期二

EDB Failover Manager 使用筆記-I:建立 HA Cluster

    PostgreSQL 之間可以用 Streaming Replication 進行主從資料庫之間的資料同步。並且能夠使用 pg_ctl 指令手動將備份資料庫切換成主要服務資料庫;或是使用 trigger 設定主機異常時的自動切換。PostgreSQL 的高可用性架構( High Availability, HA)就是使用這些功能去組成的。

    提供企業版 PostgreSQL 服務的公司 EnterpriseDB 提供一個能夠管理 PostgreSQL 資料庫 HA 的工具,EDB Failover Manager(EFM)。該工具能夠監控 PostgreSQL 資料庫間的狀況,並且在主要資料庫主機發生異常時作自動切換,並有通知管理者的功能。


2016年3月14日 星期一

PostgreSQL 的 Physical Replication Slot 功能

在 PostgreSQL 9.4 中,引進了用來防止 streaming replication 中斷後就無法再次建立 streaming replication 問題的功能:Replication Slot。

Replication Slot 有兩種:Physical Replication Slot 與 Logical Replication Slot。在此使用的是 Physical Replication Slot,是不涉及解析 WAL 交易日誌內容的 Replication Slot 功能。

一般使用 streaming replication,必須要設定 wal_keep_segment 選項,才能避免在 standby 不小心備份不及(例如,某時段的 primary 交易量太大,交易日誌產生太快),造成 standby 還沒抓交易日誌,就被 primary 洗掉了。如果交易日誌被洗掉,streaming replication 就會中斷,並且無法再繼續進行,這樣就得重設立 streaming replication 了。

現在使用 replication slot, primary 就會知道目前 standby 同步的狀況,primary 就不會把還沒同步完畢的交易日誌洗掉,等待 standby 抓取完交易日誌才刪去舊的日誌。


EDB Failover Manager 使用筆記-II:測試 EFM Cluster 高可用性

接續前一篇設置起 EFM Cluster 之後,接著就是要真的看看 EFM CLuster 在發生資料庫異常時表現的行為了。

首先,再確認一下目前 Cluster 的狀態:

 [root]# /usr/efm-2.0/bin/efm cluster-status efm
 Cluster Status: efm

 Agent Type  Address              Agent  DB         Info
 --------------------------------------------------------------
 Master      192.168.57.102       UP     UP
 Witness     192.168.57.101       UP     N/A
 Standby     192.168.57.103       UP     UP 

 Allowed node host list:
 192.168.57.102 192.168.57.103 192.168.57.101

 Standby priority host list:
 192.168.57.103

 Promote Status:

 DB Type     Address              XLog Loc          Info
 --------------------------------------------------------------
 Master      192.168.57.102       0/F01A4B8
 Standby     192.168.57.103       0/F01A4B8

 Standby database(s) in sync with master. It is safe to promote.

最後一行告訴我們,此時的 Cluster 能夠拿來作資料庫切換。

要模擬 primary 主機有異常,最簡單的方式就是強制中止 primary 上的 PostgreSQL 程序,或者也可以直接關掉 primary 主機的 VM。

關掉 primary 主機之後,EFM Cluster 便無法再檢查到 primary 主機上的 EFM agent 與 資料庫,依照在設定檔內所設定的檢查間隔,local.period、 local.timeout、local.timeout.final三個設定,檢查完畢確認 Primary 主機無法服務之後,便會開始切換過程:

 [root]# /usr/efm-2.0/bin/efm cluster-status efm
 Cluster Status: efm

 Agent Type  Address              Agent  DB       Info
 --------------------------------------------------------------
 Idle        192.168.56.102       UP     UNKNOWN               
 Promoting   192.168.56.103       UP     UP        
 Witness     192.168.56.101       UP     N/A       

 Allowed node host list:
 192.168.56.102 192.168.56.103 192.168.56.101
 Standby priority host list:
 192.168.56.103

 Promote Status:

 DB Type     Address              XLog Loc         Info
 --------------------------------------------------------------
 Master      192.168.56.103       0/D0483C8        

 No standby databases were found.

 Idle Node Status (idle nodes ignored in XLog location comparisons):

 Address              XLog Loc         Info
 --------------------------------------------------------------
 192.168.56.102       0/D0482C0        DB is not in recovery.

到這裡,原先的 Standby 主機已經接替了下線的 primary 主機的工作,並且 EFM Cluster 也寄信告訴你資料庫發生異常了:




當收到信之後,就準備要開始重新啟動整個備份了:

再恢復整個資料庫設置的方式,就是
 (1) 以現在的主機作為新的 primary(上面的 192.168.56.103),而已經下線的機器啟動成為新的 standby(上面的 192.168.56.102),建立之間的 streaming replication

 (2) 再啟動上的 EFM agent:
[root@old_primary]# efm resume efm
Resume command successful on local agent.

這樣,整個 EFM Cluster 便恢復了。

最後,當試用期過了之後,要再啟動 EFM Cluster 就會收到如下訊息:

 

告訴你這次的遊戲結束了,請再投幣囉

2016年3月10日 星期四

在同一台主機上開多個 PostgreSQL 程序

PostgreSQL 的使用方式是先初始化一個資料庫並且啟動它,就會啟動程序,並去監聽 port。一個 Postgres 程序,是用他開啟的資料庫 instance 來區分的。

在同一台主機上,也就能夠開很多個 PostgreSQL,而且也不見得一定要由 PostgreSQL 專有帳戶 postgres 來開一個資料庫 instance。

方式只要初始化一個新的資料庫就有了。

  postgres $ initdb -D /var/lib/pgsql/9.5/data/ --locale=zh_TW.UTF-8 -A md5 -W
  cchsu $ initdb -D /home/cchsu/pgsql/9.5/ --locale=zh_TW.UTF-8 -A md5 -W

接連執行上面兩次指令,就產生出兩個資料夾,這兩個個別就代表一個資料庫了。

接者啟動時,指定不同 port 來開,就會跑兩個出來 Postgres 了

  postgres $ pg_ctl -D /var/lib/pgsql/9.5/data/ -o "-p 5432" -l logfile start
  cchsu $ pg_ctl -D /home/cchsu/pgsql/9.5/ -o "-p 5433" -l logfile start

附上一張截圖
 

要登入的話,記得剛初始化的 instance 裡面預設能連線的只有 postgres database,登入時要記得指定資料庫為 postgres 才行 ~

Streaming Replication 筆記

串流複寫( Streaming Replication )是 PostgreSQL 的資料複寫( Replication )的功能。這功能是用來備份資料到別台機器上,並且在主要資料庫所在的主機發生異常時,利用備份機頂替主要資料庫。

由於 PostgreSQL 的交易日誌設計是和所運行的作業系統及硬體架構有關,所以要進行 Streaming Replication 規劃時,必須要兩端的作業系統一致(如:Linux 對 Linux、Windows 對 Windows);以及硬體架構也要一致才行(例如:32 位元和 64 位元之間就不能用 Streaming Replication) 。

要作實際演練的話,有兩種簡單的環境設置可以選擇:
1. 在同一台機器上開兩個 PostgreSQL instance,兩個 instance 之間進行備份;
2. 或是開兩台虛擬機器( VM ),兩個 VM 間進行備份。
這兩者的操作流程是一樣的。

[20191205 Update] 已經針對 PostgreSQL 12 重新演練一次了~