# 關於 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逻辑复制原理](https://zhuanlan.zhihu.com/p/163204827)
4. [Logical Decoding Concepts](https://www.postgresql.org/docs/12/logicaldecoding-explanation.html#LOGICALDECODING-REPLICATION-SLOTS)
5. [PostgreSQL WAL日志发展史](https://zhuanlan.zhihu.com/p/163245243)
6. [PostgreSQL WAL日志清理](https://zhuanlan.zhihu.com/p/383485177)
7. [Postgres WAL Replication: Easy Step-By-Step Guide](https://hevodata.com/learn/postgres-wal-replication/#introR)
8. [29.5. WAL Internals](https://www.postgresql.org/docs/12/wal-internals.html)
9. [PostgreSQL流复制之一:原理+环境搭建(转发+整理)](https://www.cnblogs.com/yickel/p/11161706.html)
10. [Postgres 9.3 feature highlight - pg_xlogdump](https://paquier.xyz/postgresql-2/postgres-9-3-feature-highlight-pg_xlogdump/)
11. [A Brief History of PostgreSQL](https://www.postgresql.org/docs/9.1/history.html)
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](https://developer.aliyun.com/article/78028?spm=a2c6h.13813017.content3.1.72b66e082Uq5rX)
14. [[转]一篇超赞的 PostgreSQL query 生命周期分析](https://github.com/digoal/blog/blob/master/201510/20151016_01.md)