阿里雲DTS訂閱實現實時運營服務的方案及注意事項

一、背景

嘗試在數據層面實現一個業務事件的偵聽和發佈的服務(即實時運營)。以使在公司多個不同系統或服務中都可以實時獲取到事件通知,進而做各自對應的觸發業務(比如 C 端可以即時爲用戶發送通知,B 端可以爲運營人員發送短信和郵件等等)。

本文主要針對使用阿里雲 DTS 同步訂閱,實現類似【實時運營】這樣的服務的過程中需要注意的點。

二、拋出問題

  • 爲什麼不放在業務層?
  • 如何獲取數據的變化?
  • 數據怎樣具體定義一個事件?

2.1 爲什麼不放在業務層

想要監聽某個業務事件,最簡單的方式肯定是在業務代碼裏添加一些事件發佈的邏輯(比如向DB或MQ中放置一條事件記錄),當需要監聽另一個業務事件時,重複這些操作,繼續添加另外一些邏輯。

但是這樣處理也有兩方面的缺點:

  1. 核心業務代碼和事件監聽代碼沒有解耦(當然可以通過恰當的設計模式或方案來一定程度上避免)
  2. 每次添加一些新事件的監聽,都要重新發版(當然監聽事件比較少的情況下,這一點的影響較小,可以提前都規劃好所有的事件;但是對於監聽事件比較多且可能容易變化的情況就比較頭疼),而對於很多業務系統來說,可能不會這麼頻繁地發佈新版。

而結合我們自身的實際情況,選擇在數據層做處理。 

2.2 如何獲取數據的變化

數據層要做事件的監聽處理,必然需要實時得知數據的變化,然後再以特定的數據變化動作,來定義某種業務事件的發生。那麼如何實時獲取數據的變化?答案是可以藉助數據庫的 binlog 監聽服務。

這種服務也有一些開源的實現,也可以藉助於阿里雲的 DTS 訂閱服務(https://help.aliyun.com/document_detail/145715.html),其本質上也一樣,另外具備Kafka生產者的功能,用來將 binlog 數據放在 Kafka 中。

2.3 數據怎樣具體定義一個事件

假設我們已經購買並配置好了 DTS 訂閱服務,且官方給出的 消費者 Demo 也跑通拿到數據了,我們先看一下消費者 Demo 輸出的數據長什麼樣:

[2020-05-06 13:47:13,162] INFO recordID [3313806458]source [{"sourceType": "MySQL", "version": "5.7.20-log"}]dbTable [unifiedorder_db.checkoutapply]recordType [UPDATE]recordTimestamp [1588744030]extra tags [{pk_uk_info={"PRIMARY":["pid"]}, readerThroughoutTime=1588744030271},]
Field [pid]Before [30598]After [30598]
Field [contractId]Before [59008]After [59008]
Field [userId]Before [211072]After [211072]
Field [roomId]Before [13042]After [13042]
Field [unitMode]Before [0]After [0]
Field [operateType]Before [1]After [1]
Field [blame]Before [1]After [1]
Field [checkOutDate]Before [2019-08-31 00:00:00]After [2019-08-31 00:00:00]
Field [status]Before [450]After [450]
Field [lockState]Before [0]After [1]
Field [createBy]Before [[email protected]]After [[email protected]]
Field [createAt]Before [2019-08-31 21:06:31]After [2019-08-31 21:06:31]
Field [modifyBy]Before [batchAdmin]After [batchAdmin]
Field [modifyAt]Before [2020-05-06 13:42:12]After [2020-05-06 13:47:10]
Field [displayStatus]Before [WRD]After [WRD]
Field [remark]
 (NotifyDemo)

結合上面日誌的打印,可以看出這是一個完整的 binlog 變化的數據,數據還是比較全的,需要重點關注的是數據庫操作類型 recordType、庫表名 dbName、數據變化前後鏡像 Field 和 Before 和 After。

通過這些關鍵信息,對於絕大多數事件的定義來說,已經完全足夠。但是 Demo 處理後的數據的樣式似乎不太令人滿意,我們更期望是一個對象,即可以用 JSON 表示出來,所以我們可以自己做一下處理。

接着終於到了定義事件的時候了,不需要過多解釋,我的表結構和數據定義如下:

三、填坑

目前相當數量的企業都選擇企業雲,使用各種服務,比如我們用到的阿里雲上的 ECS、RDS、Redis、OSS、Kafka、DTS 同步/訂閱、DataV、SSL、CDN、SLB、域名和容器等等。

然而,在某些雲服務的使用中,才能發現一些不在說明文檔中提到的坑和 Bug。是的,一般選擇企業雲有一部分原因都是信賴其可靠性,但是至少在我使用 Kafka 和 DTS 訂閱時,踩了幾步坑。

本文只提一下 DTS 訂閱服務中需要注意的問題。在此之前,首先貼一下官方文檔中的注意事項: 

  • 訂閱通道保存最近24小時的數據,過時的數據將會從訂閱通道中刪除。
  • 在訂閱通道運行過程中,請勿使用gh-ost或pt-online-schema-change等類似工具執行在線DDL變更,否則可能導致訂閱失敗。

下面是筆者遇到的坑及解決方案:

3.1 官方Demo存在疑似Bug

官方給的 Java 版的 Demo 中,存在疑似 bug,我已提交到 github。該 bug 會導致消費者Demo服務重啓後不能接着上次的消費進度繼續消費。

bug 鏈接:https://github.com/LioRoger/subscribe_example/issues/17

解決方案也在 bug 中提到了。

3.2 數據分區只有1個

經筆者實踐及與售後客服確認,DTS 訂閱服務的 Kafka 數據分區只有1個。

確認對話截圖如下:

 

所以帶來的問題是,無法讓多個消費者並行消費,在同一時刻只能有 1 個 DTS 消費者端工作。因此爲了讓我們的服務達到無感知切換,必須要啓另一個服務作爲主備中的備份,等到主節點需要升級或者宕掉的時候,副節點自動接着消費。

爲了達到上述目的,有以下兩種方案:

  1. 可以考慮配置 Kafka 的消費模式爲 Subscribe(ps:Demo 默認 Assign 模式),這樣通過消費組的作用,輕鬆實現。但是 Demo 貌似對 Subscribe 模式的支持有問題,導致指定開始消費的時間戳不生效。所以需要自己熟悉並修改 Demo 中的處理。
  2. 面對分佈式系統地問題,理所當然地可以藉助 ZooKeeper 來實現主備切換,也比較簡單,這裏不去延伸。

3.3 消息冪等

嚴格來說,這一點不算坑,很多消息中間件的消費端都需要開發者們自己去考慮消息冪等性的問題。

就 Demo 來說,每次啓動服務都是從指定的開始消費的時間戳開始消費數據的,而非消息偏移量。在這樣的場景中可能會出現重複消費的問題,假設某一時間戳的數據量很大,在服務停掉時,這一時間戳的數據仍未消費完,那麼在下次啓動服務後,仍舊將從這個時間戳開始消費,而且是從這個時間戳最開始的那個偏移量開始,而前面這些偏移量對應的消息其實在我們上一次的服務中已經消費過了。

解決方案:

可以從 Demo 記錄最新消費進度的文件 localCheckpointStore 中找到答案,將文件 localCheckpointStore 內容格式化後的數據結構如下:

{
    "groupID": "dtstdfg57le212ittt",
    "streamCheckpoint": [
        {
            "partition": 0,
            "offset": 239468271,
            "topic": "cn_hangzhou_rm_bp1r439675jqu3028_test_user",
            "timestamp": 1590469246,
            "info": "1590469246"
        }
    ]
}

可以看到裏面記錄了每次提交的最新消費時間戳和偏移量,所以我們在每次啓動服務時,讀取這個文件中的最新偏移量 offset 值,並在每條消息消費之前,比較當前消息的 offset 和文件中的 offset,若前者小於等於後者,則拋棄當前消息。

3.4 DTS控制檯操作不生效

經與售後客服確認,DTS 訂閱服務在控制檯的某些操作是無效的(ps:而控制檯沒有給出應有的提示,讓用戶誤以爲操作成功。文檔中也沒看到這些注意事項說明)。

3.4.1 DTS控制檯不能移除訂閱對象

確認對話截圖如下:

3.4.2 DTS控制檯不能修改配置訂閱數據類型

DTS 訂閱的數據類型有兩種:

一旦創建好了一個數據訂閱以後,再去修改它的訂閱的數據類型是不生效的。

確認對話截圖如下:

 

以上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章