閱讀1012 返回首頁    go 阿裏雲 go 技術社區[雲棲]


PgSQL · 應用案例 · 邏輯訂閱給業務架構帶來了什麼?

背景

邏輯訂閱是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。

https://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初始化數據》

最後更新:2017-04-21 09:01:15

  上一篇:go MSSQL · 應用案例 · 基於內存優化表的列存儲索引分析Web Access Log
  下一篇:go MySQL · 特性分析 · common table expression