雲計算

DTS 及其在PG 數據庫生態中的應用

一、PostgreSQL 數據傳輸通道關鍵技術

(一)什麼是數據傳輸通道?

數據通道並不是一個很新的概念,很早以前就已經有人或者企業提出了。從數據庫的視角來看,數據通道是要去解決各個數據庫、數據平臺還有信息系統之間的數據連通性的題,然後來支持數據高速自由的流動。

數據通道建立之後,可以從TP 數據庫流轉到AP 數據庫進行分析;或者流轉到大數據平臺,進行實時計算;或流轉到kv 上去做的cache;或從AP 數據庫再將分析結果流回到TP 數據庫,以便於支撐業務對統計信息的查詢。

在一條數據通道上,流動的數據類型大概有兩種:

第一種,存量數據,存量數據不是實時產生的,比如說一些基礎的信息數據。

第二種,增量數據, 增量數據是實時產生的數據。

從另一個維度去劃分,數據通道上的數據會分成真實的數據和對數據描述的數據。拿數據庫來講,表結構或者說DDL 信息,以及這張表對應的真實數據,作為數據傳輸通道,它就像我們的路一樣,越快越好,“快”就是數據傳輸通道的傳輸效率問題。

image.png

解決了在數據通道上的傳輸,傳輸效率之後,我們在數據通道上也應該提供一些ETL的能力,ETL 的能力可以做數據的清洗(比如非法的數據,把它清洗成合法的數據,寫入到這個目標端去)。或者對一些敏感的數據進行脫敏,再放到大數據的系統裡面進行分析。或者若干張表的數據,在數據通道內部進行多表合併,然後再把它放到AP 的庫裡面分析。

做為一條數據通道,在數據質量產生了問題或者數據的鏈路出現了擁塞的時候,一定要有較強的數據保障能力。

(二)PostgreSQL 內置數據類型

PG 內置的數據類型:

數據通道要解決數據的傳輸問題,那麼就一定要有具體數據。

對於不同的DB 庫來講會有不同的類型, PG 提供了幾種基礎類型:數值型、字符型、二進制型、時間型、貝爾型、比特型等。

PG 除此之外還提供了增強的類型,比如地理位置、信息類型、網絡型等。

系統ID 類型——tid ,tid 對PG 來講,是PG 的內置字段。在使用上,往往會對ctid 的錯誤使用,通過PK 或UK 或索引字段,查出來ctid,緊接著使用ctid 對錶進行操作。這個使用方式其實是不太靠譜的,因為ctid 它代表的是這一行數據所屬的頁以及在頁內的偏移。PG 是通過copy of direct 實現的macc 機制,在查詢出來之後,這行數據的ctid 可能發生變化,如果我們固化了使用ctid,就會產生數據不一致的問題。

在大部分的時候,因為我們是通過PG 的driver 實現的數據的讀取,所以不需要關注各種數據類型內部的存儲情況。如果要去看,比如說對Wal 的日誌進行細膩度的分析,或者對一頁的數據進行細膩度的分析,可能就會需要了解每一個不同的類型在PG 內部的存儲的格式。

image.png

(三)PostgreSQL 分區表

在讀取PG 數據的時候,數據通道里面有兩種不同的數據的類型,一種是存量數據,一種是增量數據。

在PG 的數據庫裡面,對於存量數據的讀取分區表是一個非常獨特的case,分區表從PG10 開始,有兩個截然不同的表現,在PG10 以前,分區表是基於PG 的CHECK-IN HERIT 語法來實現,同時需要手動的在主表上創建trigger,這種方式實現比較脆弱。

物理表和邏輯表其實沒有明確的區分。

從PG10 之後,我們可以看得到PG 引入了partition by range 這樣的支持,支持

分區表的語法,在此之後PG 的原數據庫部分能夠明確的區分出來,哪張表是主表,哪張表是物理表。

比如下圖的例子,可以看得到logical table 它的relation kind 是p 它代表的是分區表,也就是說主表; physical table 1 它的relation kind 是r,代表的是物理表,就是一張正常的、普通的表。

image.png

為什麼要區分主表和物理表?

因為在讀取全量數據的時候,對於一張分區表,我們希望讀取它物理表的數據,這樣會讀的快,而不去讀取主表的數據。

如果不能區分物理表和主表,那就既讀取了主表的數據還有物理表的數據,這個數據就會有大量的重複,相當於我們讀取了兩次。

(四)PostgreSQL 增量數據獲取

怎樣獲取到增量的數據?

PG 的增量獲取方式有三個大的版本:

1. 在PG 的9.3 之前,它是不支持Stream Replictaion 的,一般常用的做法都是基於trigger 的方式進行增量的獲取。當然也可以進行業務的侵入,比如說使用業務的

GMT modify,要求業務有GMT modify 的字段,通過這個字段,我們可以拿出某一

個時間點之後的數據,這個也是一個比較間接的來獲取增量數據的方式。

2. 從PG9.3 之後,PG 支持了叫做stream replication 這樣的方式,基於此我們就可以通過這種方式來獲取到增量數據。獲取增量數據有兩種不同的類型,一種叫做logical slot;還有一種是physical slot。在業內目前都是居於logical slot 的方式進行獲取。在PG9.3 之後,在PG10 之前, logical slot 的decoding 是沒有一個能夠正式應用於生產環境的decoding 的,所以我們提供出一個叫做ali decoding 的基於讓logical slot 使用的解碼器。通過它我們可以把PG 的wal 數據,解碼成string類型的邏輯數據,再給到增量獲取的模塊。

3. 在PG10 之後提供了PGoutput slot 的解碼器,通過它可以實現ali decoding 相似的功能,在PG10 之後提供了一個叫做訂閱的概念,能夠從下圖最右邊的語句上看出來,在最右邊的語句上展示了在PG10 或10 以後是怎麼樣去創建一個邏輯訂閱的。

image.png

首先會通過叫做PG_create_logical_reputation_slot 的方式來創建出邏輯slot,然後會創建出來一個訂閱,這個訂閱能夠指定訂閱哪張表,或是訂閱所有的表給邏輯slot,這裡的“%s”是需要填充的上個階段創建的邏輯slot 的名稱。

對於較少的表,可以指定具體的表名字,如果表很多,就可以寫成FOR ALL TABLES,訂閱所有表的增量數據,隨後使用start replication 開啟讀取訂閱數據。

在這裡需要注意的是PG 的REPLICA IDENTIFY 是表級別的,在這個表級它有不同的級別,比如說default 是默認的級別; using index 是PK 或者是UK;FULL 是所有的; nothing 是什麼都沒有。

從PG10 開始支持邏輯訂閱,在邏輯訂閱中有一個限制,對無主鍵、無唯一鍵的表,如果針對這張表開啟邏輯訂閱,要求這個表的REPLICA IDENTIFY 是負才可以。否則的話,這張表是不能夠進行delete 和update 操作的,關於這點要特別注意。

(五)PostgreSQL Stream Replication

PG 的stream,application 內部的實現原理

PG backend 是PG 的一個服務,接受用戶的TP 數據,形成WAL 寫入到WAL 日誌裡面去,並且通知walsender 讀取wal 的數據,walsender 根據接收到的signal 的通知之後,讀取wal 的數據。walsender 根據當前slot 註冊情況,如果logical_slot,那就讀取一個完整的Excel record,然後通過logicaldecode 的方式進行解碼,獲取到解碼後的數據。

如果是physical_slot,那就是通過physical_decode 進行簡單的xlog 的數據讀取,然後獲取到待發送的數據之後,最後由Walsender 將待發送的數據發送給增量的訂閱客戶端。

從這兒可以看得到,無論是logical 的還是physical 的,其實數據都是wal 的日誌,只不過logical 的數據它要求是一個完整的xlog 的記錄,而physical 的只要是一個完整的xlog 數據塊就可以了。

在這裡面的關鍵點, logical slot 它是通過logical_decode 這樣的一個框架進行解碼,框架裡面會調用具體的output_plugin,進行整行數據的輸出與格式的轉換。

Logical_decode 框架,對於每行數據是要求知道這行數據的relation 信息,要求PG 知道信息的具體狀態。關於這一塊如果logical slot 是以歷史的點位進行數據拉取,PG 這邊是沒辦法保證一定能夠找得到當時點位所對應的表的結構信息。

所以這就是為什麼PG 的logical slot 在創建的時候,只能以當前的點位進行創建,而不能以歷史的點位。一旦PG 的logical slot 創建出來之後, PG 的backend 會根據各個logical slot 裡歷史最早的點位進行數據保存。通過這種方式能夠保證所有的logical slot在需要matter 信息的時候,PG 這邊都能夠得到,都沒有被釋放掉。

image.png

(六)PostgreSQL 數據導入

如何讓鏈路的效率更快?

PG 有兩種數據的寫入方式的:

第一種是batch lnsert,是把一些數據整合成一條sql,進行插入;

第二種方式就是PG copy,經過測試, PG copy 的性能要遠超於batch lnsert,大概是batch lnsert 的4 倍左右,是PG 線路里面一個重要的提升傳輸效率的一種方式。

image.png

二、DTS PostgreSQL 數據傳輸通道實現

理解了PG 數據庫對數據通道能夠提供的基礎能力後,下面以DTS 數據傳輸服務為例來看一下,怎麼樣基於這些基礎能力進行整合,打造出來一條數據通道。

(一)DTS 是什麼——異地多活的數據通道

DTS 是阿里雲的服務,中文名稱是數據傳輸服務,DTS 是數據通道的具體的實現。DTS 的一個重要的屬性是異地多活的數據通道。

什麼叫異地多活呢?

比如,解決杭州到北京之間數據庫之間的數據傳輸;多活是杭州和北京之間的兩邊都支持數據的寫入。DTS 在阿里巴巴集團內部已經是重要的數據數據傳輸通道,支持了阿里巴巴歷年的雙11。

看下圖,在2019 年雙11 的時候,整個的TP 的數據洪峰大概是54.4 萬米每秒,在DTS 異地多活的數據通道的強力保障之下,我們做到了毫秒記的延遲,DTS 同時也是阿里雲內部、阿里雲上客戶數據同步的重要的利器。

從下圖可以看出,DTS 支撐了全球的數據同步。

image.png

(二)DTS 是什麼——用戶上雲的高速公路

DTS 是雲下的用戶和其他雲廠商的用戶上阿里雲的高速通道。

雲下的用戶可以很方便地使用dts 的服務,將自己雲下的數據搬到雲上的數據庫中,享受不停機數據遷移的能力,並且能夠基於DTS 的雙向同步能力,在發現雲上數據庫出現問題時,能夠快速將自己的業務切換到本地。

DTS 支持雲下的專線連接,支持公網連接,支持VPN 連接等多種連接方式。

可以讓雲下的用戶,很方便的享受到雲上的數據庫能力。比如,雲上強大的IP 數據庫的分析能力,大數據的計算能力。

image.png

(三)DTS 是什麼——高價值數據的分發源頭

DTS 支持各種TP 數據庫的增量數據。

DTS 在獲取到這些增量數據之後,可以把這些附加值很高的數據分發到,比如ES、Redis、Kafka、Flinkt 等這種大數據平臺,進行各種數據計算,將數據的價值最大化。

image.png

(四)DTS 邏輯架構概覽

DTS 是雲上的分佈式數據傳輸通道,在源端的DTS 支持各種TP 數據庫、Redis、SQL 數據庫,以及分佈式數據庫,在目標端DTS 可以把這種數據寫入到TP 數據庫,mango 或者說大數據平臺、Kafka、訂閱客戶端去。

DTS 自身給用戶提供了兩個基礎接口,用戶可以通過控制檯操作DTS 相應的任務,也可以通過這種open API 進行批量化的創建與管理。

DTS 是自身的分成預檢查模塊、結構遷移模塊、全量遷移模塊、日誌解析模塊以及數據寫入模塊。DTS 通過這個數據校驗,提供數據質量的保證能力。

DTS 的數據都存儲在DStore 中,我們可以通過DTS 的ETL 模塊,對DStore 中的數據進行數據清洗、數據轉換,並且最終由writer 同步到目標端,或者由數據訂閱的客戶端消費。

在原端的DTS 支持兩種數據,一種是存量數據,包括數據還有表結構;另一種是增量日誌,這一部分可能包括具體的數據以及DDL。

DTS 有三大功能:

第一個就是數據遷移,數據遷移這一塊主要用來解決用戶的數據庫遷移;

第二個是數據同步,數據同步主要的場景是異地多活的場景;

第三個是數據訂閱,數據訂閱是將增量的數據交給客戶端,進行大數據分析,或者用戶自定義的業務。

DTS 提供Numan 運維平臺,在運維平臺之上可以完成任務的告警監控,可以完成用戶的任務管理、任務告警、資源管理以及對源庫和目標端的異常情況監控。

DTS 的分佈式能力主要體現在它的調度服務。DTS 將資源池化之後,對各個用戶的鏈路提供了HA 能力,保證了99.99%的服務能力。

image.png

(五)DTS 高效讀寫PostgreSQL

DTS 如何提升存量數據的傳輸效率?

除了使用前面提到的PG 自身的PG copy 之外,我們對全量採用了表兼併發的能力。首先會對一張PG 表進行切片,將其切分成若干個小片段,針對每個片段使用併發讀取、併發寫入的方式,將存量數據高效的同步到目標表。

右邊是DTS 針對PG 增量數據進行的高效寫入。對於增量數據,DTS 會將其拆分成原始的一個事物,對於沒有衝突的事物, DTS 會採用併發寫入的方式。對於有衝突的事物,DTS 會採用串行寫的方式。通過這種方式在提升效率的同時,也保證了數據的最終一致性。

關於這一塊的增量和全量的併發寫入DTS 是有相應的專利的。

還有一部分數據就是針對一張表的某一個字段的頻繁的熱點的更新,這種情況之下因為都是衝突的數據,沒辦法進行併發寫入,DTS 是採用熱點合併的方式進行解決。

image.png

(六)DTS 捕獲PostgreSQL 增量數據

DTS 有著非常豐富的手段獲取到PG 增量數據。

第一個就是dml trigger,針對PG 9.3 以前的版本, DTS 可以通過在原庫創建trigger 的方式,拉取到增量數據。針對9.3 之後的版本, GTS 是通過logical slot 的方式來獲取到dml 數據。

由於PG 自身是不支持DDL 的原始語句寫入到wal 中的,所以DTS 通過在PG 源庫創建DDL Trigger 的方式,來捕獲到DDL 的原始數據,再進行同步。

基於logical slot 的方式有一定的限制,比如說logical slot 它不能夠支持以歷史的點位進行數據拉取,logical slot 必須針對無PK/UK 的表,設置成IDENTITY FULL,所以現在DTS 也在公關physical slot 的增量獲取技術,目前已經進入到了測試階段,在不久的將來能夠在DTS 的雲上上線。

image.png

(七)DTS 解決長鏈路高RT問題

在異地多活的場景裡面,要跨Region 同步數據,必然涉及到高RT 的問題。DTS 解決問題的基本思想就是近DB 的部署原則。以增量的數據同步舉例,在增量裡面,我們的DTS reader 就是拉取增量數據的模塊和源庫部署在同一個Region。

DTS Writer 就是增量數據寫入模塊和目標庫部署在同一個Region,通過這兩個模塊近DB 的部署,最高限度的提升數據的拉取和數據的寫入效率。

DTS Reader 是要把拉取到的數據投遞到DTS Store,而DTS Writer 是要從DTS Store 裡面拉取到同步數據,在這一塊DTS Store 可以部署在源庫的位置,也可以部署在目標庫的位置,甚至可以部署在中間位置。

DTS Reader 到DTS Store,DTS Store 到DTS writer,數據傳輸通道是DTS自身經過高度優化的,通過高度優化過的一個數據通道,我們就解決了高RT的問題。

在這裡面的優化點有兩個:

第一個,儘可能的減少數據傳輸量,在這塊我們主要是通過壓縮,以及源端的數據重刪達到的目標。

第二個,因為長鏈路高RT 長,但是數據的Throughpu 是大的,所以我們就儘可能的使用數據推,而不採用Ping-pong 的方式,以儘可能的降低長鏈路RT的問題。

image.png

(八)DTS 提供ETL 能力

DTS 的數據傳輸通道里面,它實現了幾個ETL 能力:

第一個就是表級別的,它可以針對庫、表、列進行映射。比如,下圖例子裡面,它是把原庫的Schema 為a.religion_source 這個Relation 映射成b.relation_target 這樣的一個表。在原表的c1、c2 列,通過DTS 可以映射成d1、d2 列。

第二個維度就是數據維度。舉個例子裡數據清洗,比如說它對c2 列null 字段的清洗成good。同時DTS 的ETL 能力也提供了數據的多表合併。

image.png

三、DTS PostgreSQL 經典案例

在瞭解了DTS 基於PG 的基礎能力,所做的數據通道鏈路之後,基於這個數據通道能夠解決哪些問題。

(一)不停機上雲

所謂的不停機上雲就是源庫的業務不需要停,可以很平滑的將源庫遷移到雲上。我們有一個比較成功的大型應用案例:

東南亞的一個電商,我們支撐了電商大概8tb 的核心數據,然後涉及到11000 個Oracle 數據庫對象的不停機上雲。在這個方案裡面,我們提供的是雙向同步的方案。

先來說正向的方式,首先DTS 會做結構遷移1 動作,在這個階段主要是負責把源庫的庫、表、列信息以及PK、UK 信息,遷移到目標庫去。在這個階段完成之後會進行全量數據的遷移,也就是存量數據的遷移。

在存量數據完成之後,我們會進行結構遷移2 階段的這樣的一個遷移動作。在這個階段主要是去遷移原庫的索引。

為什麼結構遷移要分成兩個階段呢?

因為經過大量的測試,發現在數據完成之後,創建索引的效率要遠高於數據完成之前創建索引,所以把結構遷移拆成了兩個階段。在數據完成之後,我們使用結構牽引二的方式創建索引。

在結構遷移整個的完成之後,我們就開始進行增量遷移。

增量遷移的起始位置是從全量遷移之前開始的,這樣能夠保證整個數據一致性,當增量遷移整個的數據追平之後(就是增量遷移的內容沒有延遲),初步的認為這條鏈路達到了可以切流的階段。為了進一步的驗證數據質量,可以做全鏈校驗的動作。

全鏈校驗是通過拉取源庫的數據,以及拉取目標庫的數據進行全字段的比較,驗證兩邊的數據是一致的。

當全鏈校驗沒有問題之後,就可以進行切流的動作。在切流之前還會搭建出來一條反向鏈路,所謂的反向鏈路,我們去啟動增量數據的拉取服務,去拉取目標庫增量數據,增加增量數據的寫入模塊,將增量拉取的數據寫入到源庫。

通過反向鏈路的建立,如果在切流的過程之中,目標庫出現了一些不適配,或者業務有一些不適配,我們可以快速的回切到源庫。

這個不停機上雲的方案,我們在雲上已經服務了很多這樣的用戶了,有著非常廣泛的應用。

image.png

(二)異地災備

來看下圖中的例子,這個案例是基於DTS 數據傳入通道來實現的異地災備。

用戶兩邊都是自建庫,但是這兩邊自建庫它是在兩地的,通過DTS 雲上的高效數據傳輸能力,幫助用戶搭建了一條從杭州到青島的災備鏈路。

image.png

(三)數據集成

下圖是一個數據集成的例子,DTS 將TP 數據庫,把這樣的數據拉取到DTS 的DTSStore 裡面,通過DTS 的同步鏈路,可以寫到如ADB、Kafka 這樣的AP 的數據分析平臺裡面去。

也支持用戶使用數據訂閱的客戶端,拉取增量的數據出來,按照用戶自己的場景進行靈活的應用。

image.png

(四)大數據下游

下圖是大數據下游的案例, 首先用戶是在雲下,通過專線上雲,通過數據同步鏈路用戶在雲上的Ecs 上也有一個數據庫,通過專線完成線下到雲上的一個同步。

在上雲之後,用戶在異地又建立了一個災備庫,通過DTS 完成在災備庫同步。對於災備庫自身,用戶為了儘可能的發揮災備庫的價值,又在災備庫上建立了一條訂閱的鏈路。通過DTS 把數據同步到Kafka,然後再由用戶大數據的下游,從Kafka 託舉數據進行消費。同時在雲上的庫,用戶通過DTS 建立了一條反向鏈路,通過這條反向鏈路,再回流到用戶雲下的數據庫裡面去。

image.png

四、總結

總結來說,我們以數據傳輸通道的視角,講述了PG 在數據傳輸通道上的能力,以及以DTS 為例,說明了基於這些能力,如何構建一條數據傳輸通道,並且例舉了數據上雲、數據災備、數據訂閱等經典的使用案例,希望對大家有所幫助。

Leave a Reply

Your email address will not be published. Required fields are marked *