自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用CDC模式改造遺留系統(tǒng)

原創(chuàng) 精選
開發(fā)
因?yàn)楸桓脑斓臉I(yè)務(wù)是客戶的核心業(yè)務(wù),基于不影響原有業(yè)務(wù)的考慮下選擇了新老并行模式來完成整個遺留系統(tǒng)改造。我們選擇了 CDC 模式(Debezium)來將遺留系統(tǒng)中產(chǎn)生的變化同步到新服務(wù)中。

作者 | 張雙海

項(xiàng)目改造背景及挑戰(zhàn)

在我們經(jīng)歷的各種遺留系統(tǒng)改造之旅中,使用絞殺者模式來改造一個巨大的單體服務(wù),是一種被廣泛采用且驗(yàn)證行之有效的手段,在應(yīng)用傳統(tǒng)的絞殺者模式時,通常采用逐步替換的方式,將遺留系統(tǒng)中某一獨(dú)立的部分抽取出來進(jìn)行改造,最后通過反向代理等方式,將流量倒入到新的服務(wù)中。

但是在我們的案例中,被改造的領(lǐng)域服務(wù)是客戶的核心業(yè)務(wù),客戶強(qiáng)烈希望在整個改造過程中,不要對現(xiàn)有正在運(yùn)行的系統(tǒng)造成影響,所以僅僅采用絞殺者模式是不夠的,我們還需要采用新老并行模式來完成整個遷移改造。

當(dāng)使用并行運(yùn)行時,我們不是調(diào)用新舊實(shí)現(xiàn)的其中之一,而是同時調(diào)用二者,以允許我們比較其結(jié)果以確保它們是等效的。盡管調(diào)用了兩種實(shí)現(xiàn),但在任何給定的時間內(nèi),只有一個實(shí)現(xiàn)的結(jié)果是正確的。一般而言,在不斷校驗(yàn)并相信我們的新實(shí)現(xiàn)之前,我們認(rèn)為舊實(shí)現(xiàn)的結(jié)果是正確的。  

「《Monolith To Microservices》」

通過新老并行模式,原有的系統(tǒng)不會受到影響,可以繼續(xù)提供服務(wù),待新的服務(wù)完成遷移并通過驗(yàn)證之后,再將流量遷移到新的系統(tǒng)。采用新老并行模式可以以增量的模式進(jìn)行遷移改造,并且在出現(xiàn)問題的時候能夠輕松回滾,確保核心業(yè)務(wù)的安全。具體介紹可以參考zalando 的工程實(shí)踐。

圖片

在新老并行模式運(yùn)行過程中,為了達(dá)到使新服務(wù)能夠完全平行替代舊服務(wù),需要將舊服務(wù)里新產(chǎn)生的變化,及時同步到新服務(wù)里來(對于遺留數(shù)據(jù)只需要一次性的遷移即可)。在各種因素以及客戶業(yè)務(wù)需求的影響下,我們選擇了 Event Sourcing 作為基本架構(gòu)來構(gòu)建我們新領(lǐng)域服務(wù)。Event Sourcing 是一種通過記錄一系列的領(lǐng)域事件來完成對系統(tǒng)狀態(tài)的持久化,對于 Event Sourcing 更加詳細(xì)的介紹可以參看之前的這篇《??被誤解的Event Sourcing??》。

鑒于新服務(wù)中持久化的都是一系列的領(lǐng)域事件,所以很難將遺留系統(tǒng)中產(chǎn)生的變化直接持久化到新服務(wù)中,最好的方式是通過調(diào)用新服務(wù)提供的 API,由新服務(wù)通過 Command 產(chǎn)生 Event,然后再存儲到 Event Store 中,完成持久化。

同時遺留單體系統(tǒng)中的代碼倉庫已經(jīng)非常龐大,并且復(fù)雜到難以修改,任何對于遺留系統(tǒng)的代碼修改都需要經(jīng)過繁復(fù)的測試和嚴(yán)格的 Code Review,同時也會增加交付開發(fā)人員的認(rèn)知負(fù)擔(dān),并且還會給現(xiàn)有系統(tǒng)帶來一定的風(fēng)險(xiǎn)。

基于以上背景,我們發(fā)現(xiàn),通過修改遺留系統(tǒng)代碼的方式來完成新老兩個系統(tǒng)之間數(shù)據(jù)的同步代價(jià)是比較大的,而且會引入一定的風(fēng)險(xiǎn)。

以上種種限制使得我們選擇了CDC(Change data capture)模式來完成我們對遺留系統(tǒng)數(shù)據(jù)的捕捉與遷移。

使用 CDC 模式來完成新老數(shù)據(jù)同步

什么是 CDC 模式和 Debezium

CDC 模式是一種對變化的數(shù)據(jù)進(jìn)行監(jiān)控并捕獲,以便其他服務(wù)也能夠響應(yīng)這些變化的模式。對于監(jiān)控?cái)?shù)據(jù)庫的變化而言,Debezium 是 CDC 模式的一個非常成熟的實(shí)現(xiàn)。當(dāng)使用 Debezium 來連接 MySQL 時,Debezium 會讀取 MySQL 的 binary log (binlog) 獲取到數(shù)據(jù)庫產(chǎn)生的變化。同時,Debezium 還是一個 Kafka connect,通過配置,能夠?qū)?shù)據(jù)庫產(chǎn)生的變化推送到特定的 Kakfa Topic 中。

通過 Debezium,我們便可以捕獲到所有遺留系統(tǒng)數(shù)據(jù)庫產(chǎn)生的變化,并將其推送到 Kafaka 特定的 Topic 中去,只要新服務(wù)能夠響應(yīng)這些變化,就可以將舊系統(tǒng)中數(shù)據(jù)產(chǎn)生的變化同步到新系統(tǒng)里去。

圖片

但目前而言,新服務(wù)是無法直接響應(yīng)這些遺留系統(tǒng)數(shù)據(jù)庫的變化的,原因是新服務(wù)接受的是有業(yè)務(wù)含義的 Command,而不僅僅是一些數(shù)據(jù)庫的變化。但根本原因在于,我們捕獲到的數(shù)據(jù)庫變化只是數(shù)據(jù)庫行級別的變化,缺失了特定的業(yè)務(wù)含義,所以我們也無法直接利用這些數(shù)據(jù)與我們的新服務(wù)連接起來。

將這些捕獲到的數(shù)據(jù)庫變化賦予業(yè)務(wù)含義,并將其轉(zhuǎn)換為特定的 Command,這是我們面臨的下一個挑戰(zhàn)。

從 CDC 到 Command

要完成這個挑戰(zhàn),就需要深入細(xì)節(jié)了。為了方便說明,我在這里準(zhǔn)備了一個非常簡單的例子。

還是以我們非常熟悉的電商領(lǐng)域商品項(xiàng)為例,假設(shè)一個 Product 聚合根,管理著多個 Photo 聚合,它們之間的關(guān)系在遺留系統(tǒng)數(shù)據(jù)庫中用 ERD 表示如下:

圖片

經(jīng)過前期的事件風(fēng)暴工作坊,我們可以得到一系列關(guān)于 Product 聚合根的領(lǐng)域事件:

  • Product 已增加
  • Product 的 Photo 已增加

由于我們的新服務(wù)采用了 Event Sourcing 架構(gòu),并且系統(tǒng)內(nèi)的 Event 設(shè)計(jì)嚴(yán)格遵循事件風(fēng)暴工作坊產(chǎn)出的領(lǐng)域事件,在新服務(wù)中,接受的是像在 Product A 下增加 Photo這樣的 Comand。

有了例子之后, 我們可以將之前描述的問題更加具體一點(diǎn):當(dāng)收到一條消息表明 Photo 表中的數(shù)據(jù)發(fā)生了變化,應(yīng)將其識別并轉(zhuǎn)變?yōu)樵?Product A 下增加 Photo或更改 Photo A 為封面圖片這樣的 Command。

接下來讓我們仔細(xì)分析一下 Debezium 所捕獲到的變化數(shù)據(jù)的結(jié)構(gòu),繼續(xù)上面的例子,如下是一個典型的 Debezium 產(chǎn)生的 Kafka 消息的 payload 結(jié)構(gòu):

{
"before": null,
"after": {
"id": "61CFF6E6-A7AA-43BB-8D6D-A8676CFF59AE",
"productId": "E78E3F5A-2275-4C2D-AA6E-1F0282E6CC08",
"filePath": "48F3AE46-D6A5-4F14-8FE3-7B82B7EB6537",
"order": 0,
"isCover": true,
}
"source": {...some source meta information},
"op": "c",
"ts_ms": 1631690854515,
"transaction": {
"Id": "file=mysql-bin-changelog.000010,pos=40908353",
"total_order": 1,
"data_collection_order": 1
}
}

從這個消息的結(jié)構(gòu)和內(nèi)容可以看出,該消息里面不僅完整的展示了數(shù)據(jù)庫里某項(xiàng)記錄在變化前后的所有信息,同時還有一些附加的元信息。在這些元信息中,有兩項(xiàng)數(shù)據(jù)最值得我們?nèi)プ⒁狻?/p>

一個是op,根據(jù)Debezium 的官方文檔,這個字段表明了這次變化的變化類型,這個字段可能的值有:

  • C: 表示創(chuàng)建
  • U: 表示更新
  • D: 表示刪除
  • R: 表示讀?。ㄈ绻且粋€ Snapshot 的話)

通過這個字段,我們可以快速且準(zhǔn)確的推斷出當(dāng)收到某條變化的消息時,遺留系統(tǒng)數(shù)據(jù)庫的某項(xiàng)數(shù)據(jù)發(fā)生了怎樣的變化。比如上面這個例子,我們可以推斷出來,有一張新的圖片被添加到某個 Product 上面。

但是到目前為止,可以將這樣的消息轉(zhuǎn)換為在Product A下增加Photo這樣的 Command 嗎?

很遺憾還不能,因?yàn)楦鶕?jù) Debezium 的實(shí)現(xiàn)以及我們的配置,每張表的更新都會被發(fā)送到不同的 Kafka Topic 中去,當(dāng)收到圖片被添加的消息時,還有可能是添加了一個 Product 的同時添加了這個 Product 的 Photo,所以這個行為不應(yīng)該被識別為添加圖片的 Command,而應(yīng)該被識別為創(chuàng)建一個 Product的 Commnd。

為了能夠準(zhǔn)確地將數(shù)據(jù)庫中發(fā)生的變化識別為 Commnd,我們需要收集并分析更多的數(shù)據(jù),這就需要利用消息體里的另外一個字段——transaction。

Transaction 字段描述了捕獲到的這一次變化里關(guān)于 Transaction 的一些信息,這些信息包括了這次變化的“transactionId”,以及這個變化在這次 transaction 里的順序。

同時,Debezium 捕獲到的不僅僅是某個表中的某項(xiàng)記錄發(fā)生變化,同時它還會捕獲到每次數(shù)據(jù)庫關(guān)于 Transaction 的一些原始信息,消息格式如下:

{
"status": "END",
"id": "file=mysql-bin-changelog.000010,pos=40908353",
"event_count": 2,
"data_collections": [
{
"data_collection": "product-service@photo",
"event_count": 1
},
{
"data_collection": "product-service@product",
"event_count": 1
}
]
}

在每一次數(shù)據(jù)庫的 transaction 開始或者結(jié)束的時候,我們都能通過 debezium 收到這樣一條消息,這個消息里面,我們可以得知某一個 Transaction 的狀態(tài),id,這次 Transaction 里面有哪些表發(fā)生了變化,以及變化的數(shù)量是多少。

在這些數(shù)據(jù)中,我們最為關(guān)注的就是 Transaction 的id,可以發(fā)現(xiàn)在前述關(guān)于數(shù)據(jù)表變化的消息體里面也存在這個字段,通過這個字段,我們可以將某一個 Transaction 下所有產(chǎn)生的變化都聚合到一起,根據(jù)聚合之后的數(shù)據(jù)再來判斷應(yīng)該將其識別轉(zhuǎn)換為哪種 Command。比如說,要是這個變化的聚合里面有一個 Product 被新增了,那么我們就可以確定的是這肯定是一個新增Product的 Command,即便這個變化的聚合里面顯示出有 Photo 被新增,那也不應(yīng)該被識別為成添加圖片的 Command。

其實(shí)作出上面的推論還是有一個隱含前提,就是遺留系統(tǒng)的一些行為和操作,都是在一個 Transaction 中,如果同一個操作不在同一個 Transaction ,那么我們的推論也就無法成立。好在在我們的真實(shí)案例中,客戶采用了成熟的 ORM 框架(Prisma),每一個有業(yè)務(wù)含義的行為所造成的修改都在同一個 Transaction 中并保存到數(shù)據(jù)庫。在開發(fā)過程中,也需要在遺留系統(tǒng)的前端不斷操作驗(yàn)證并加以單元測試才能確保我們能夠準(zhǔn)確地識別出所對應(yīng)的 Command。

至此,我們所有要解決的問題都能夠得到解決了,我們已經(jīng)能夠?qū)⑦z留系統(tǒng)數(shù)據(jù)庫與新系統(tǒng)的數(shù)據(jù)庫之間的 gap 填平了,兩者之間的通道也能夠建立了。我們終于勝利了!

圖片

基于此種解決方案,我們將整個遺留系統(tǒng)改造分為了三個階段,

圖片

  • 階段一:前端對遺留系統(tǒng)讀和寫,但是對遺留系統(tǒng)所造成的修改都會被同步到新系統(tǒng)中
  • 階段二:前端對遺留系統(tǒng)進(jìn)行寫操作,但是對于讀操作都會被引向新系統(tǒng)
  • 階段三:待對新系統(tǒng)做好完整的驗(yàn)證后,新系統(tǒng)就會被作為唯一可信的數(shù)據(jù)源進(jìn)行讀寫了

更多的細(xì)節(jié)

常言道,魔鬼都在細(xì)節(jié)里,不過鑒于篇幅有限,已經(jīng)無法再用文字展開更多了,只能通過時序圖來介紹 CDC Procrssor 服務(wù)里更多的細(xì)節(jié),包括如何通過Transaction來聚合 Debezium 消息以及整個消息處理流程。

圖片

總結(jié)

最后總結(jié)一下,因?yàn)楸桓脑斓臉I(yè)務(wù)是客戶的核心業(yè)務(wù),基于不影響原有業(yè)務(wù)的考慮下選擇了新老并行模式來完成整個遺留系統(tǒng)改造。我們選擇了 CDC 模式(Debezium)來將遺留系統(tǒng)中產(chǎn)生的變化同步到新服務(wù)中。在同步過程中,由數(shù)據(jù)層的變化推導(dǎo)出業(yè)務(wù)意圖是成功的關(guān)鍵。在其他運(yùn)用絞殺模式的改造中,如果能夠在更上層的地方做分支也是一種好的思路(參考 Decorating Collaborator Pattern),這樣可以更好地還原業(yè)務(wù)。最后,在使用 CDC 模式來完成遺留系統(tǒng)改造時,數(shù)據(jù)完整性和性能都是關(guān)鍵指標(biāo),在不丟失數(shù)據(jù)的情況下應(yīng)越快越好。

原文鏈接:??使用CDC模式改造遺留系統(tǒng) (qq.com)??

責(zé)任編輯:趙寧寧 來源: 51CTO
相關(guān)推薦

2020-12-24 08:00:00

數(shù)字化轉(zhuǎn)型遺留系統(tǒng)架構(gòu)

2022-07-08 09:41:20

遺留系統(tǒng)服務(wù)拆分

2010-09-06 16:35:58

SQL函數(shù)

2021-01-15 11:01:42

IT系統(tǒng)漏洞網(wǎng)絡(luò)攻擊

2022-01-13 09:49:40

遺留系統(tǒng)交接開發(fā)

2014-02-13 09:47:41

GartnerERP云ERP

2023-06-25 12:22:25

IT領(lǐng)導(dǎo)者CIO

2013-09-12 09:39:38

遺留系統(tǒng)云遷移API

2018-05-03 15:34:34

組件測試遺留系統(tǒng)微服務(wù)

2013-09-16 13:18:28

遺留系統(tǒng)系統(tǒng)遷移

2024-04-12 10:03:48

2022-08-24 09:50:40

系統(tǒng)運(yùn)維

2021-07-09 05:25:48

CIO遺留系統(tǒng)現(xiàn)代化用戶體驗(yàn)

2017-09-13 15:45:17

交付軟件遺留系統(tǒng)

2021-06-27 17:20:20

遺留系統(tǒng)隱形成本CIO

2023-02-10 11:40:53

2021-12-27 11:02:00

首席信息官技術(shù)發(fā)展企業(yè)管理者

2020-11-30 10:13:17

ITCIO首席信息官

2010-09-01 16:08:03

遺留系統(tǒng)Java

2013-11-11 09:59:29

Boni Satani遺留系統(tǒng)系統(tǒng)遷移
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號