Dbus所支援兩類資料來源的實現原理與架構拆解。
大體來說,Dbus支援兩類資料來源:
- RDBMS資料來源
- 日誌類資料來源
一、RMDBMS類資料來源的實現
以mysql為例子. 分為三個部分:
- 日誌抽取模組
- 增量轉換模組
- 全量拉取模組
1.1 日誌抽取模組(Extractor)
mysql 日誌抽取模組由兩部分構成:
- canal server:負責從mysql中抽取增量日誌。
- mysql-extractor storm程式:負責將增量日誌輸出到kafka中,過濾不需要的表資料,保證at least one和高可用。
我們知道,雖然mysql innodb有自己的log,mysql主備同步是通過binlog來實現的。而binlog同步有三種模式:Row 模式,Statement 模式,Mixed模式。因為statement模式有各種限制,通常生產環境都使用row模式進行復制,使得讀取全量日誌成為可能。
通常我們的mysql佈局是採用 2個master主庫(vip)+ 1個slave從庫 + 1個backup容災庫 的解決方案,由於容災庫通常是用於異地容災,實時性不高也不便於部署。
為了最小化對源端產生影響,我們讀取binlog日誌從slave從庫讀取。
讀取binlog的方案比較多,DBus也是站在巨人的肩膀上,對於Mysql資料來源使用阿里巴巴開源的Canal來讀取增量日誌。這樣做的好處是:
- 不用重複開發避免重複造輪子
- 享受canal升級帶來的好處
關於Canal的介紹可參考:https://github.com/alibaba/ca... 由於canal使用者抽取許可權比較高,一般canal server節點也可以由DBA組來維護。
日誌抽取模組的主要目標是將資料從canal server中讀出,儘快落地到第一級kafka中,避免資料丟失(畢竟長時間不讀日誌資料,可能日誌會滾到很久以前,可能會被DBA刪除),因此需要避免做過多的事情,主要就做一下資料拆包工作防止資料包過大。
從高可用角度考慮,在使用Canal抽取過程中,採用的基於zookeeper的Canal server高可用模式,不存在單點問題,日誌抽取模組extractor也使用storm程式,同樣也是高可用架構。
不同資料來源有不同的日誌抽取方式,比如oracle,mongo等都有相應的日誌抽取程式。
DBus日誌抽取模組獨立出來是為了相容這些不同資料來源的不同實現方式。
1.2 增量轉換模組(Stream)
增量資料處理模組,根據不同的資料來源型別的格式進行轉換和處理。
1)分發模組dispatcher
- 將來自資料來源的日誌按照不同的schema分發到不同topic上。這樣做的目的
- 是為了資料隔離(因為一般不同的shema對應不同的資料庫)
- 是為了分離轉換模組的計算壓力,因為轉換模組計算量比較大,可以部署多個,每個schema一個提高效率。
2)轉換模組appender
- 實時資料格式轉換:Canal資料是protobuf格式,需要轉換為我們約定的UMS格式,生成唯一識別符號ums_id和ums_ts等;
- 捕獲後設資料版本變更:比如表加減列,欄位變更等,維護版本資訊,發出通知觸發告警
- 實時資料脫敏:根據需要對指定列進行脫敏,例如替換為*,MD5加鹽等。
- 響應拉全量事件:當收到拉全量請求時為了保證資料的相應順序行,會暫停拉增量資料,等全量資料完成後,再繼續。
- 監控資料:分發模組和轉換模組都會響應心跳event,統計每一張表在兩次心跳中的資料和延時情況,傳送到statistic作為監控資料使用。
- 分發模組和轉換模組都會相應相關reload通知事件從Mgr庫和zk上進行載入配置操作。
1.3 全量拉取模組(FullPuller)
全量拉取可用於初始化載入(Initial load), 資料重新載入,實現上我們借鑑了sqoop的思想。將全量過程分為了2 個部分:
1)資料分片
分片讀取max,min,count等資訊,根據片大小計算分片數,生成分片資訊儲存在split topic中。下面是具體的分片策略:
以實際的經驗,對於mysql InnDB,只有使用主鍵索引進行分片,才能高效。因為mysql innDB的主鍵列與資料儲存順序一致。
2)實際拉取
每個分片代表一個小任務,由拉取轉換模組通過多個併發度的方式連線slave從庫進行拉取。 拉取完成情況寫到zookeeper中,便於監控。
全量拉取對源端資料庫是有一定壓力的,我們做法是:
- 從slave從庫拉取資料
- 控制併發度6~8
- 推薦在業務低峰期進行
全量拉取不是經常發生的,一般做初始化拉取一次,或者在某種情況下需要全量時可以觸發一次。
1.3 全量和增量的一致性
在整個資料傳輸中,為了儘量的保證日誌訊息的順序性,kafka我們使用的是1個partition的方式。在一般情況下,基本上是順序的和唯一的。 但如果出現寫kafka非同步寫入部分失敗, storm也用重做機制,因此,我們並不嚴格保證exactly once和完全的順序性,但保證的是at least once。
因此ums_id_變得尤為重要。 對於全量抽取,ums_id是一個值,該值為全量拉取event的ums_id號,表示該批次的所有資料是一批的,因為資料都是不同的可以共享一個ums_id_號。ums_uid_流水號從zk中生成,保證了資料的唯一性。 對於增量抽取,我們使用的是 mysql的日誌檔案號 + 日誌偏移量作為唯一id。Id作為64位的long整數,高6位用於日誌檔案號,低13位作為日誌偏移量。 例如:000103000012345678。 103 是日誌檔案號,12345678 是日誌偏移量。 這樣,從日誌層面保證了物理唯一性(即便重做也這個id號也不變),同時也保證了順序性(還能定位日誌)。通過比較ums_id_就能知道哪條訊息更新。
ums_ts_的價值在於從時間維度上可以準確知道event發生的時間。比如:如果想得到一個某時刻的快照資料。可以通過ums_ts 來知道截斷時間點。
二、日誌類資料來源的實現
業界日誌收集、結構化、分析工具方案很多,例如:Logstash、Filebeat、Flume、Fluentd、Chukwa. scribe、Splunk等,各有所長。在結構化日誌這個方面,大多采用配置正規表示式模板:用於提取日誌中模式比較固定、通用的部分,例如日誌時間、日誌型別、行號等。對於真正的和業務比較相關的資訊,這邊部分是最重要的,稱為message部分,我們希望使用視覺化的方式來進行結構化。
例如:對於下面所示的類log4j的日誌:
如果使用者想將上述資料轉換為如下的結構化資料資訊:
我們稱這樣的日誌為“資料日誌”
DBUS設計的資料日誌同步方案如下:
- 日誌抓取端採用業界流行的元件(例如Logstash、Flume、Filebeat等)。一方面便於使用者和業界統一標準,方便使用者的整合;另一方面也避免無謂的重造輪子。抓取資料稱為原始資料日誌(raw data log)放進Kafka中,等待處理。
- 提供視覺化介面,配置規則來結構化日誌。使用者可配置日誌來源和目標。同一個日誌來源可以輸出到多個目標。每一條“日誌源-目標”線,中間資料經過的規則處理使用者根據自己的需求來自由定義。最終輸出的資料是結構化的,即:有schema約束,可以理解為類似資料庫中的表。
- 所謂規則,在DBUS中,即“規則運算元”。DBUS設計了豐富易用的過濾、拆分、合併、替換等運算元供使用者使用。使用者對資料的處理可分多個步驟進行,每個步驟的資料處理結果可即時檢視、驗證;可重複使用不同運算元,直到轉換、裁剪得到自己需要的資料。
- 將配置好的規則運算元組運用到執行引擎中,對目標日誌資料進行預處理,形成結構化資料,輸出到Kafka,供下游資料使用方使用。
系統流程圖如下所示:
根據配置,我們支援同一條原始日誌,能提取為一個表資料,或者可以提取為多個表資料。
每個表是結構化的,滿足相同的schema。
- 每個表是一個規則 運算元組的合集,可以配置1個到多個規則運算元組
- 每個規則運算元組,由一組規則運算元組合而成
拿到一條原始資料日誌, 它最終應該屬於哪張表呢?
每條日誌需要與規則運算元組進行匹配:
- 符合條件的進入規則運算元組的,最終被規則組轉換為結構化的表資料。
- 不符合的嘗試下一個規則運算元組。
- 都不符合的,進入unknown_table表。
2.1 規則運算元
規則運算元是對資料進行過濾、加工、轉換的基本單元。常見的規則運算元如下:
運算元之間是獨立的,通過組合不同的運算元達到更復雜的功能,對運算元進行迭代使用最終達到對任意資料進行加工的目的。
我們試圖使得運算元儘量滿足正交性或易用性(雖然正規表示式很強大,但我們仍然開發一些簡單運算元例如trim運算元來完成簡單功能,以滿足易用性)。
三、UMS統一訊息格式
無論是增量、全量還是日誌,最終輸出到結果kafka中的訊息都是我們約定的統一訊息格式,稱為UMS(unified message schema)格式。如下圖所示:
3.1 Protocol
資料的型別,被UMS的版本號
3.2 schema
1)namespace 由:型別. 資料來源名.schema名 .表名.表版本號. 分庫號 .分表號 組成,能夠描述所有表。
例如:mysql.db1.schema1.testtable.5.0.0
2)fields是欄位名描述。
- ums_id_ 訊息的唯一id,保證訊息是唯一的
- ums_ts_ canal捕獲事件的時間戳;
- ums_op_ 表明資料的型別是I (insert),U (update),B (before Update),D(delete)
- ums_uid_ 資料流水號,唯一值
3)payload是指具體的資料。
一個json包裡面可以包含1條至多條資料,提高資料的有效載荷。
四、心跳監控和預警
RDBMS類系統涉及到資料庫的主備同步,日誌抽取,增量轉換等多個模組等。
日誌類系統涉及到日誌抽取端,日誌轉換模模組等。
如何知道系統正在健康工作,資料是否能夠實時流轉? 因此對流程的監控和預警就尤為重要。
4.1 對於RDBMS類系統
心跳模組從dbusmgr庫中獲得需要監控的表列表,以固定頻率(比如每分鐘)向源端dbus庫的心跳錶插入心跳資料(該資料中帶有傳送時間),該心跳錶也作為增量資料被實時同步出來,並且與被同步表走相同的邏輯和執行緒(為了保證順序性,當遇到多併發度時是sharding by table的,心跳資料與table資料走同樣的bolt),這樣當收到心跳資料時,即便沒有任何增刪改的資料,也能證明整條鏈路是通的。
增量轉換模組和心跳模組在收到心跳包資料後,就會傳送該資料到influxdb中作為監控資料,通過grafana進行展示。 心跳模組還會監控延時情況,根據延時情況給以報警。
4.2 對於日誌類系統
從源端就會自動產生心跳包,類似RDBMS系統,將心跳包通過抽取模組,和運算元轉換模組同步到末端,由心跳模組負責監控和預警。