閱讀421 返回首頁    go 技術社區[雲棲]


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

標簽

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。

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

pic

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

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

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

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

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

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

邏輯訂閱例子

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

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-13 16:30:49

  上一篇:go 4月13日雲棲精選夜讀:MongoDB使用常見問題及應用場景全集
  下一篇:go Redis崩潰調試