PostgreSQL邏輯訂閱-給業務架構帶來了什麼希望?

德哥發表於2017-04-13

標籤

PostgreSQL , 邏輯訂閱 , 10.0 , 資料匯聚 , 資料共享 , IDC多活 , 雲端線下同步


背景

邏輯訂閱是PostgreSQL 10.0的新特性。

具體的原理,使用方法可以參考如下文章。

《PostgreSQL 10.0 preview 邏輯訂閱 – 原理與最佳實踐》

《PostgreSQL 10.0 preview 邏輯訂閱 – pg_hba.conf變化,不再使用replication條目》

《PostgreSQL 10.0 preview 邏輯訂閱 – 備庫支援邏輯訂閱,訂閱支援主備漂移了》

《PostgreSQL 10.0 preview 邏輯訂閱 – 支援並行COPY初始化資料》

PostgreSQL 早在2010年就支援了物理流式複製,可以用來支援容災、讀寫分離、HA等業務場景。為什麼還需要邏輯訂閱的功能呢?

邏輯訂閱和物理流複製有什麼差別

1. 差別1,物理複製目前只能做到整個叢集的複製。邏輯訂閱可以做到表級。

物理流式複製是基於REDO的塊級別複製,複製出來的資料庫與上游資料庫一模一樣,每個塊都是一樣的,就好像克隆的一樣。

物理流式複製,目前只能做到整個叢集的複製,雖然技術上來講也可以做到按表空間、按資料庫級別的複製,目前PG社群還沒有這麼做。

PS:外圍的公司有這樣的外掛,walbouncer,支援物理的partial replication。

http://www.cybertec.at/en/products/walbouncer-enterprise-grade-partial-replication/

pic

2. 差別2,物理複製的備庫只讀,不能寫入。邏輯訂閱讀寫都可以。

3. 差別3,物理複製不需要等待事務提交,即可將REDO發往備庫,備庫也可以直接apply它。邏輯訂閱,目前需要等待事務提交後,釋出端才會使用wal_sender程式將decode後的資料傳送給訂閱端,訂閱端流式接收與流式apply。

將來邏輯訂閱也可能不需要等事務結束就apply,因為在CLOG中是有2個BIT記錄事務狀態的。

/*
 * Possible transaction statuses --- note that all-zeroes is the initial
 * state.
 *
 * A "subcommitted" transaction is a committed subtransaction whose parent
 * hasn`t committed or aborted yet.
 */
typedef int XidStatus;

#define TRANSACTION_STATUS_IN_PROGRESS          0x00
#define TRANSACTION_STATUS_COMMITTED            0x01
#define TRANSACTION_STATUS_ABORTED                      0x02
#define TRANSACTION_STATUS_SUB_COMMITTED        0x03

4. 差別4,物理複製,需要複製所有的REDO(包括回滾的)。邏輯訂閱,不需要複製所有的REDO,僅僅需要複製”訂閱表產生的REDO解析後的資料”(並且回滾的事務不會被複制)。

5. 差別5,如果要支援邏輯訂閱,需要配置wal_level=logical,如果僅僅需要物理複製,則配置wal_level=replica即可。

邏輯訂閱需要產生額外的REDO資訊(通過alter或create table指定pk, 或 full row)。而物理複製,不需要在REDO中記錄這些資訊。

邏輯訂閱對主庫的效能影響比物理複製更較大的。

REPLICA IDENTITY

This form changes the information which is written to the write-ahead log to identify rows which are updated or deleted. 

This option has no effect except when logical replication is in use. 

DEFAULT (the default for non-system tables) records the old values of the columns of the primary key, if any.  -- 普通表預設使用PK作為old value

USING INDEX records the old values of the columns covered by the named index, which must be unique, not partial, not deferrable, and include only columns marked NOT NULL. 

FULL records the old values of all columns in the row. 

NOTHING records no information about the old row. (This is the default for system tables.) -- 預設情況下系統表的變更不記錄old row

In all cases, no old values are logged unless at least one of the columns that would be logged differs between the old and new versions of the row.

6. 差別6,對於大事務,物理複製的延遲比邏輯訂閱更低。因為差別3。

7. 差別7,邏輯訂閱需要用到釋出端的catalog,將REDO翻譯為可供訂閱者使用的ROW格式,如果在訂閱端與釋出端沒有同步前,釋出端的TABLE定義發生了變化或者被刪除了,翻譯REDO的工作將無法進行下去。PostgreSQL使用多版本來解決這樣的問題,允許CATALOG的變更,但是版本被保留到訂閱端不需要它為止(PG內部通過LSN來實現)。如果你發現釋出端的CATALOG膨脹了,可以從這方面找一下原因(是不是訂閱太慢或者訂閱者停止訂閱了,同時期間釋出端產生了大量的DDL操作)。

物理複製不存在這樣的問題。

8. 差別8,物理複製的備庫,如果要被用來只讀的話,為了避免備庫LONG QUERY與vacuum redo發生衝突,有兩種解決方案,都有一定的損傷。1,主庫延遲VACUUM,一定程度上導致主庫膨脹。2,備庫APPLY禮讓QUERY,一定程度上導致備庫APPLY延遲。

邏輯訂閱不存在以上情形的衝突。

邏輯訂閱與物理流複製的定位差別

邏輯訂閱,適合於釋出端與訂閱端都有讀寫的情況。

邏輯訂閱,更適合於小事務,或者低密度寫(輕度寫)的同步。如果有大事務、高密度寫,邏輯訂閱的延遲相比物理複製更高。

邏輯訂閱,適合於雙向,多向同步。

物理複製,適合於單向同步。

物理複製,適合於任意事務,任意密度寫(重度寫)的同步。

物理複製,適合於HA、容災、讀寫分離。

物理複製,適合於備庫沒有寫,只有讀的場景。

邏輯訂閱給業務架構帶來了什麼

1. 多個業務之間,有少量的資料需要同步時,邏輯訂閱可以解決這樣的問題。

例如A業務和B業務,分別使用兩個資料庫,但是他們有少量的資料是共用的。而且都要對這部分共享資料進行讀寫。

pic

2. 資料彙總,例如多個業務庫的FEED資料,要彙總到一個分析庫。以往可能要構建龐大的ETL和排程系統,並且很難做到實時的同步。現在有了邏輯訂閱,可以方便的應對這樣的場景。

(PostgreSQL 的多個特性表名,它正在朝著HTAP的方向發展,既能高效的處理OLTP線上業務,也能處理分析業務。(LLVM、向量計算、列儲存、多核並行、運算元複用等一系列的特性支援OLAP))

pic

3. 資料拆分,與資料彙總剛好相反,比如在垂直拆分時,使用邏輯訂閱,可以將一個集中式的資料庫拆分成多個資料庫。由於邏輯訂閱是增量的,可以節約拆分過程的停機時間。

另外還有些業務場景,在端上可能不會部署那麼多的小資料庫,統統往一個庫裡寫。下游接一些小的資料庫,是要邏輯訂閱,也能很好的滿足此類需求。

pic

4. 多活架構中,最痛苦的實際上是資料庫,為什麼呢?

比如一個遊戲業務,可能在全國都有IDC,而認證或者賬務系統可能還是集中式的,如果要拆分成多個庫,就會涉及到資料一致性和完整性的問題。

比如按使用者的首次註冊地,將資料庫分為多個區域。根據使用者的登陸來源IP,路由到相應的IDC(訪問這個IDC中的資料庫),這個使用者如果是固定使用者還好,因為註冊地和使用地基本是不變的。對於手機遊戲就扯淡了,因為登陸地不斷的變化,比如出差,原來在杭州登陸的,跑北京登陸了。而北京機房並沒有該使用者的資訊。業務層面就需要解決這樣的問題。

使用邏輯訂閱,可以很好的解決這個場景的問題,每個IDC中的資料都是完整的,當使用者在杭州時,讀寫杭州的資料庫,通過訂閱資料複製到北京的機房。當使用者漫遊到北京時,讀寫北京的資料庫,通過訂閱複製到杭州的機房。

pic

5. 有些企業,在雲上有資料庫,線上下也有資料庫,甚至在多個雲廠商都有資料庫。應了一句話,不要將雞蛋放在同一個籃子裡。

那麼這些資料庫的資料如何在多個域之間同步呢?使用物理複製是很難做到的,存在一些不可避免的問題:1,雲廠商的資料庫核心可能修改過,物理複製不一定相容。2,不同廠商的版本可能不相容。3,資料庫編譯時的資料塊大小可能不一樣導致不相容。4,背後使用的外掛可能不一樣,導致不相容。5,雲廠商不一定會開放物理複製的介面。

邏輯訂閱規避了以上問題:1,邏輯訂閱可以跨版本。2,邏輯訂閱不管資料塊的大小是否一樣,都沒有問題。

pic

6. 從雲上將資料遷移到線下,或者從線下將資料遷移到雲上。

使用邏輯訂閱,可以實現增量的遷移。減少遷移的業務停機時間。

7. 跨版本、跨平臺升級。

跨版本升級,使用邏輯訂閱,增量遷移,可以減少升級版本的業務停機時間。

8. 資料分享給其他的產品,例如快取、搜尋引擎、流計算平臺。

使用邏輯訂閱,可以實時將資料分享給其他的業務平臺,BottledWater-pg就是一個很好的例子。

pic

9. 資料庫的熱插拔。類似Oracle 12C的cdb架構。PostgreSQL cluster 對應Oracle 12c的CDB,cluster中的database對應Oracle 12c的PDB。

當需要將一個CLUSTER的database拔出時,通過訂閱方式複製到其他的CLUSTER。

pic

例子

1. 建立訂閱

2. 接近同步後將資料庫設定為只讀
postgres=# alter database src set default_transaction_read_only =true;
ALTER DATABASE
 
3. 斷開已有連線
pg_terminate_backend(pid) 斷開所有與被遷移庫連線的已有連線。
  
4. 一致性遷移完成

邏輯訂閱例子

邏輯訂閱只需簡單兩步即可完成。

1. 建表、釋出

src=# create table public.t1(id int primary key, info text, crt_time timestamp);  
CREATE TABLE  
  
src=# create publication pub1 for table public.t1;  
CREATE PUBLICATION  

2. 建表、訂閱

dst=# create table public.t1(id int primary key, info text, crt_time timestamp);  
CREATE TABLE  
  
dst=# create subscription sub1_from_pub1 connection `hostaddr=xxx.xxx.xxx.xxx port=1922 user=postgres dbname=src` publication pub1 with (enabled, create slot, slot name=`sub1_from_pub1`);  
NOTICE:  created replication slot "sub1_from_pub1" on publisher  
CREATE SUBSCRIPTION  

詳情請參考

《PostgreSQL 10.0 preview 邏輯訂閱 – 原理與最佳實踐》

邏輯訂閱的衝突解決

邏輯訂閱,本質上是事務層級的複製,需要在訂閱端執行SQL。

如果訂閱端執行SQL失敗(或者說引發了任何錯誤,包括約束等),都會導致該訂閱暫停。

注意,update, delete沒有匹配的記錄時,不會報錯,也不會導致訂閱暫停。

使用者可以在訂閱端資料庫日誌中檢視錯誤原因。

衝突修復方法

1. 通過修改訂閱端的資料,解決衝突。例如insert違反了唯一約束時,可以刪除訂閱端造成唯一約束衝突的記錄先DELETE掉。然後使用ALTER SUBSCRIPTION name ENABLE讓訂閱繼續。

2. 在訂閱端呼叫pg_replication_origin_advance(node_name text, pos pg_lsn)函式,node_name就是subscription name,pos指重新開始的LSN,從而跳過有衝突的事務。

pg_replication_origin_advance(node_name text, pos pg_lsn)           
    
Set replication progress for the given node to the given position.     
    
This primarily is useful for setting up the initial position or a new position after configuration changes and similar.     
    
Be aware that careless use of this function can lead to inconsistently replicated data.    

當前的lsn通過pg_replication_origin_status.remote_lsn檢視。

https://www.postgresql.org/docs/devel/static/view-pg-replication-origin-status.html

參考

《PostgreSQL 10.0 preview 邏輯訂閱 – 原理與最佳實踐》

《PostgreSQL 10.0 preview 邏輯訂閱 – pg_hba.conf變化,不再使用replication條目》

《PostgreSQL 10.0 preview 邏輯訂閱 – 備庫支援邏輯訂閱,訂閱支援主備漂移了》

《PostgreSQL 10.0 preview 邏輯訂閱 – 支援並行COPY初始化資料》


相關文章