關於 postgres BDR

目前 BDR 2.0 以上已經是商業產品( 沒錢沒人權 ),而且 BDR 1 不支援太新的 postgresSQL.不過基於還要維護舊系統的關係,所以留個紀錄.

關於 BDR 概念

BDR 跟 db 是綁在一起的,每個 DB 可以建立不同的 bdr group
加入任一個在 group 中的 node,其他 nodes 會自動被更新.

bdr 並沒有所謂的 master 跟 slave 的概念

一點測試

已經加入 bdr 的 node, 就算整個 node 刪除,如果重新啟動新的 DB,
依然會被原本的 group 做 bdr sync, 但是新的 DB 可能還沒有 ready,所以會造成錯誤.
因此要在原本的 server 上面重啟一個新的 DB,最保險的方法還是先把 bdr 從 group 中移除,再重新啟動 DB.

Trace BDR 9.4 source code

bdr.c : bdr_establish_connection_and_slot: 建立 bdr connection 跟 slot
bdr.c : bdr_connect 建立 bdr connection 的點

bdr_apply_main -> 
    bdr_establish_connection_and_slot
        -> bdr_connect

操作 BDR

Join bdr group

# join dns1 
SELECT bdr.bdr_group_join(
    local_node_name := 'devns3',
    node_external_dsn := 'dbname=pdns host=<本機 ip> user=postgres sslmode=require sslcert=/run/psql-clientcert.crt sslkey=/run/psql-clientkey.pem',
    join_using_dsn := 'dbname=pdns host=<遠端 ip> user=postgres sslmode=require sslcert=/run/psql-clientcert.crt sslkey=/run/psql-clientkey.pem'
);

比方說 dns3 要 join dns1 group
SELECT bdr.bdr_group_join(
    local_node_name := 'devns3',
    node_external_dsn := 'dbname=pdns host=<dns3 ip> user=postgres sslmode=require sslcert=/run/psql-clientcert.crt sslkey=/run/psql-clientkey.pem',
    join_using_dsn := 'dbname=pdns host=<dns1 ip> user=postgres sslmode=require sslcert=/run/psql-clientcert.crt sslkey=/run/psql-clientkey.pem'
);

list bdr nodes:

select * from bdr.bdr_nodes;

Remove nodes

如果要重新加入節點(相同 ip), 則要先刪除 bdr 上的 nodes 在加入,否則新的 node 一上線就會馬上被 query,但是因為是新的 database 所以沒有任何 bdr 的資訊,此時重新加入 bdr 則狀態會一直呈現 i (initialize)

SELECT
# node 的狀態會被改成 k , 此時可以直接移除.
SELECT bdr.bdr_part_by_node_names(ARRAY['<node_name>']);


DELETE FROM bdr.bdr_nodes WHERE node_status = 'k';

有時候就算是 bdr node 被移除了,還是沒辦法加入 group。 這可能是因為 slot 的關係.因為 slot 的資料是沒有進行同步的,所以必須進入每一個 dns 做刪除的動作

# 找出沒有使用的 slot
select * from pg_replication_slots order by slot_name;

# remove 1 by 1 
select pg_drop_replication_slot('bdr_id');

有時候可能會有多餘的 identifier, 如果有出現 identifier 但是名稱沒有出現在 node. 則可以用下面的方式移除

# 找出沒使用的 identifier
select * from pg_replication_identifier order by riname;

# Remove identifier
select pg_replication_identifier_drop('bdr_id');

Add a record

INSERT INTO <table name> (<colume_name1>, <colume_name2>) VALUES ( 'test1', 'aaa2' );

pg_recvlogical

使用方式可以參考這邊
https://www.postgresql.org/docs/9.5/logicaldecoding-example.html

首先先建立一個 slot

root@host1$ su postgres
postgres@host1:/etc/postgresql/9.4/main$ pg_recvlogical -U postgres -d pdns -S test_slot --create-slot

這邊要注意的是我的帳號是使用 postgres
建立 slot 的 user 跟 pg_hba.conf 有關,如果碰到 authentication 或者 cert issue, 則需要去查 pg_hba 設定
理論上 default 是開給 local 端的 postgres 帳號不用密碼登入,我的設定是 peer 所以要先切成 postgres 帳號

然後開始跑 slot

postgres@host1/etc/postgresql/9.4/main$ pg_recvlogical -U postgres -d test  --slot test_slot --start -f -

這邊指令是說把輸出輸出到 stdout,也就是螢幕輸出
如果 DB 的資料有更動,則會收到以下訊息

BEGIN 3845
table public.records: INSERT: id[integer]:3006 domain_id[integer]:2 name[character varying]:'a3.cc.' type[character varying]:'CNAME' content[character varying]:'fakerecordBBB.dd.' ttl[integer]:60 prio[integer]:0 change_date[integer]:null disabled[boolean]:false ordername[character varying]:null auth[boolean]:true
COMMIT 3845

options

如果想要開啟 timestamp 可以用 --option include-timestamp

pg_recvlogical -U postgres -d test --option include-timestamp --slot test_slot --start -f -

結果就會變成這樣, 在 commit 後面多了一筆 timestamp

BEGIN 3845
table public.records: INSERT: id[integer]:3006 domain_id[integer]:2 name[character varying]:'a3.cc.' type[character varying]:'CNAME' content[character varying]:'fakerecordBBB.dd.' ttl[integer]:60 prio[integer]:0 change_date[integer]:null disabled[boolean]:false ordername[character varying]:null auth[boolean]:true
COMMIT 3845  (at 2021-12-22 06:01:37.59571+00)

這樣就可以做紀錄來觀察 DB 的變化
由於 option 是看 plugin 的支援.
default 的 slot plugin 是 test-decoding. option的部分可以從以下程式碼得知

https://github.com/postgres/postgres/blob/master/contrib/test_decoding/test_decoding.c#L189-L258

Refer

  1. bdr node status symbol description.
    https://web.archive.org/web/20180309011846/http://bdr-project.org/docs/stable/catalog-bdr-nodes.html
  2. BDR2 and BDR3 are not open source.
    https://github.com/2ndQuadrant/bdr/issues/320
  3. 剖析postgresql逻辑复制原理
  4. Logical Decoding Concepts
  5. PostgreSQL WAL日志发展史
  6. PostgreSQL WAL日志清理
  7. Postgres WAL Replication: Easy Step-By-Step Guide
  8. 29.5. WAL Internals
  9. PostgreSQL流复制之一:原理+环境搭建(转发+整理)
  10. Postgres 9.3 feature highlight - pg_xlogdump
  11. A Brief History of PostgreSQL
  12. https://github.com/digoal/blog/blob/master/201302/20130223_01.md?spm=a2c6h.12873639.0.0.60d078dfRyLdtX&file=20130223_01.md
  13. 从redo日志分析数据库的profile
  14. [转]一篇超赞的 PostgreSQL query 生命周期分析