DBus數據庫表結構變動處理方案

導讀:DBus是咱們要介紹的在敏捷大數據(Agile BigData)背景下的第一個平臺。企業中大量業務數據保存在各個業務系統數據庫中,爲同時解決數據同步的一致性和實時性問題,DBus(數據總線)平臺應運而生。java

DBus專一於數據的實時採集和實時分發,是一種基於日誌的解決方案,同時可以提供消息訂閱的方式給下游系統使用。本篇文章主要介紹在DBus的設計中,它是如何處理表結構變動及其帶來的各類問題的。git

數據庫表結構變動在軟件產品快速迭代過程當中是廣泛存在的現象,抽取數據庫中的數據是DBus最重要的功能之一,那麼對於數據庫中表結構變動及其帶來的各類問題,DBus是如何處理的呢? (本文僅討論DBus for Oracle的實現方案)github

貼源輸出是DBus的基本設計原則之一,經過解析後的數據庫日誌獲取數據轉換成UMS輸出到Kafka,當表結構發生變動時DBus必須可以及時的調整輸出UMS的結構,以確保和數據庫中表結構保持一致,這裏有兩個問題須要解決:數據庫

1)如何感知表結構變動?服務器

2)表結構變動後,新的表結構要如何與OGG輸出的二進制數據關聯?網絡

1、感知表結構變動

對於感知表結構變動,Oracle已經經過DDL trigger爲咱們提供了很好的支持,接下來咱們要考慮的是如何讓DBus感知到表結構變動? 咱們討論出如下兩種方案:併發

1.1 RPC方案

在DDL trigger中調用DBus提供的REST服務,將表結構變動事件發送給DBus。oracle

該方案思路簡單容易實現,但也有一些明顯的弊端,好比DBus須要提供高可用、低延時的REST服務,不然可能會使數據庫中的DDL操做變得緩慢甚至執行出現錯誤; DBus 的REST服務器對有數據實時同步需求的全部數據庫都必須開通防火牆策略,這將給DBus的部署帶來很大的麻煩。大數據

1.2 OGG實時同步方案

在DDL trigger中將表結構變動事件存儲到一張Event表裏,而後經過OGG實時的從日誌中將數據同步到Kafka,從而感知表結構變動事件。設計

該方案實現相對複雜但具備不少優勢,好比對數據庫的侵入性相對較小,DDL執行時只是將數據寫入到Event表中,相對網絡通訊來講,其延時更低、可靠性更高;更明顯的優點是這種方案基於數據庫日誌實現,可以使用Event表的數據,嚴格的將表結構變動先後的數據區分開。

舉例來講,對於表:test來講,依次執行insert → alter → insert 三個操做,由於OGG讀取數據庫日誌存在延時,若是利用RPC方案,可能出現這樣的一種狀況:DBus REST服務接收到alter事件以後,第一個insert的記錄才被OGG捕獲併發送給DBus,此時DBus會認爲這條數據中包含alter變化後的數據。這是一個很嚴重的問題,而OGG實時同步方案不管數據仍是時間均經過OGG讀取日誌的方案實現,能夠完美的避免這種問題的發生。

對比兩種方案OGG實時同步方案優點明顯,最終咱們採用此方案。

然而,採用這種方案也並不是一路順風,按照該方案的整體思路實現之後,咱們遇到了一個很奇怪的問題:經過DDL trigger寫到Event表中的數據沒法被OGG讀取,在經歷多番嘗試無解以後,咱們試圖到OGG的文檔中尋找答案,而最終的結果倒是:DML or DDL operations performed from within a DDL trigger are not captured.

這個答案讓問題變得更棘手,但這是最佳方案,咱們沒有理由放棄。因而咱們開始嘗試在DDL trigger中調用存儲過程,在存儲過程當中執行Event表的insert操做,但因爲存儲過程和DDL trigger仍然屬於同一個事務,所以Event表的數據依然不能被OGG捕獲,但經過這個嘗試咱們以爲只要在另一個事務中寫Event表就能解決咱們面臨的問題,因而咱們又想到了RPC,但RPC缺點太過明顯。那麼有沒有其餘能夠替代的方案呢?

實際上oracle數據庫裏可使用多種語言來編寫存儲過程,Oracle 8i開始支持java編寫存儲過程,因而咱們當即開始實現java存儲過程,經過JDBC鏈接數據庫實現Event表的寫入並提交事務,最終經過實踐驗證了這種辦法的可行性,OGG成功的獲取到了DDL trigger調用java存儲過程寫入到Event表的數據。

然而,這種實現並不算完美。當咱們在生產環境部署DDL trigger的時候,發現數據庫服務器中並無安裝執行java所須要的組件,每次部署都須要DBA同窗安裝執行java存儲過程所須要的組件,咱們試圖找到一個不使用java存儲過程的方案。這裏要感謝韓鋒老師對咱們的幫助,韓老師在聽了我 們的實現原理以後,啓發咱們自治事務應該能夠解決這個問題,咱們即刻動手開始改造DDL trigger,使之支持自治事務,通過改造以後該方案纔算完美,最終實現邏輯如圖1所示:

2、處理表結構變動事件

DBus已經具有經過事件方式感知表結構變動的能力,接下來詳細說明一下表結構變動事件該如何處理。

下圖描述了Event的完整處理流程:

Event中描述了發生結構變動的表名、該表所屬的schema以及元數據版本號,DBus接受並解析Event以後,根據表名、schema以及版本號調用元數據抓取模塊獲取該表的元數據(包括表的字段類型、長度以及註釋等)信息,實際上DDL trigger和alter語句在一個事務中執行,這樣在trigger執行過程當中沒法從oracle的數據字典裏獲取到修改以後表結構元數據,咱們寫入到meta_history表中的元數據只是執行alter語句以前的元數據信息(所以咱們給這個表取名爲table_meta_his),要獲得完整的元數據信息須要聯合table_meta_his和數據字典進行查詢,示意SQL以下:

這個SQL的結果有兩種可能:

1)只包含all_tab_cols視圖中的數據

2)既包含all_tab_cols視圖中的數據又包含table_meta_his表的數據(is_current字段的做用是區別該字段的來源)

結果A代表在table_meta_his表中沒有找到數據,這說明在生成表結構變動Event至元數據抓取程序成功獲取元數據期間沒有再次發生表結構變動,結果B則說明在此期間又發生過一次或屢次表結構變動。

爲何要使用union all?

單獨使用上圖中的兩個SQL可能致使元數據獲取程序獲取到錯誤的結果,例如:接到表結構變動Event 1後,咱們調用SQL 1 查詢table_meta_his結果集爲空,在調用SQL 2以前表結構再次發生變動(命名爲Event 2),這種狀況下咱們經過SQL 2 查詢到的結果其實是再次變動後的結果,使用這個結果產生的元數據去解析Event 1和Event 2之間的數據,若是兩次表結構變動是不兼容的,那麼必然會致使解析失敗。

感知表結構變動以及處理表結構變動事件的最終目的是可以生成正確的輸出結果,其中的更多細節以及實現能夠參考:

https://github.com/BriData/DBus

做者:張玉峯

來源:宜信技術學院

相關文章
相關標籤/搜索