您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么用Kafka與Debezium構(gòu)建實(shí)時(shí)數(shù)據(jù)同步”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么用Kafka與Debezium構(gòu)建實(shí)時(shí)數(shù)據(jù)同步”吧!
在進(jìn)行架構(gòu)轉(zhuǎn)型與分庫分表之前,我們一直采用非常典型的單體應(yīng)用架構(gòu):主服務(wù)是一個(gè) Java WebApp,使用 Nginx 并選擇 Session Sticky 分發(fā)策略做負(fù)載均衡和會(huì)話保持;背后是一個(gè) MySQL 主實(shí)例,接了若干 Slave 做讀寫分離。在整個(gè)轉(zhuǎn)型開始之前,我們就知道這會(huì)是一塊難啃的硬骨頭:我們要在全線業(yè)務(wù)飛速地?cái)U(kuò)張迭代的同時(shí)完成架構(gòu)轉(zhuǎn)型,因?yàn)檫@是實(shí)實(shí)在在的”給高速行駛的汽車換輪胎”。
為了最大限度地減少服務(wù)拆分與分庫分表給業(yè)務(wù)帶來的影響(不影響業(yè)務(wù)開發(fā)也是架構(gòu)轉(zhuǎn)型的前提),我們采用了一種溫和的漸進(jìn)式拆分方案:
對(duì)于每塊需要拆分的領(lǐng)域,首先拆分出子服務(wù),并將所有該領(lǐng)域的數(shù)據(jù)庫操作封裝為 RPC 接口;
將其它所有服務(wù)中對(duì)該領(lǐng)域數(shù)據(jù)表的操作替換為 RPC 調(diào)用;
拆分該領(lǐng)域的數(shù)據(jù)表,使用數(shù)據(jù)同步保證舊庫中的表與新表數(shù)據(jù)一致;
將該子服務(wù)中的數(shù)據(jù)庫操作逐步遷移到新表,分批上線;
全部遷移完成后,切斷同步,該服務(wù)拆分結(jié)束。
這種方案能夠做到平滑遷移,但其中卻有幾個(gè)棘手的問題:
舊表新表的數(shù)據(jù)一致性如何保證?
如何支持異構(gòu)遷移?(由于舊表的設(shè)計(jì)往往非常范式化,因此拆分后的新表會(huì)增加很多來自其它表的冗余列)
如何保證數(shù)據(jù)同步的實(shí)時(shí)性?(往往會(huì)先遷移讀操作到新表,這時(shí)就要求舊表的寫操作必須準(zhǔn)實(shí)時(shí)地同步到新表)
典型的解決方案有兩種:
雙寫(dual write): 即所有寫入操作同時(shí)寫入舊表和新表,這種方式可以完全控制應(yīng)用代碼如何寫數(shù)據(jù)庫,聽上去簡(jiǎn)單明了。但它會(huì)引入復(fù)雜的分布式一致性問題:要保證新舊庫中兩張表數(shù)據(jù)一致,雙寫操作就必須在一個(gè)分布式事務(wù)中完成,而分布式事務(wù)的代價(jià)太高了。
數(shù)據(jù)變更抓取(change data capture, CDC): 通過數(shù)據(jù)源的事務(wù)日志抓取數(shù)據(jù)源變更,這能解決一致性問題(只要下游能保證變更應(yīng)用到新庫上)。它的問題在于各種數(shù)據(jù)源的變更抓取沒有統(tǒng)一的協(xié)議,如 MySQL 用 Binlog,PostgreSQL 用 Logical decoding 機(jī)制,MongoDB 里則是 oplog。
最終我們選擇使用數(shù)據(jù)變更抓取實(shí)現(xiàn)數(shù)據(jù)同步與遷移,一是因?yàn)閿?shù)據(jù)一致性的優(yōu)先級(jí)更高,二是因?yàn)殚_源社區(qū)的多種組件能夠幫助我們解決沒有統(tǒng)一協(xié)議帶來的 CDC 模塊開發(fā)困難的問題。在明確要解決的問題和解決方向后,我們就可以著手設(shè)計(jì)整套架構(gòu)了。
只有一個(gè) CDC 模塊當(dāng)然是不夠的,因?yàn)橄掠蔚南M(fèi)者不可能隨時(shí)就位等待 CDC 模塊的推送。因此我們還需要引入一個(gè)變更分發(fā)平臺(tái),它的作用是:
提供變更數(shù)據(jù)的堆積能力;
支持多個(gè)下游消費(fèi)者按不同速度消費(fèi);
解耦 CDC 模塊與消費(fèi)者;
另外,我們還需要確定一套統(tǒng)一的數(shù)據(jù)格式,讓整個(gè)架構(gòu)中的所有組件能夠高效而安全地通信。
現(xiàn)在我們可以正式介紹 Vimur [?vi?m?r] 了,它是一套實(shí)時(shí)數(shù)據(jù)管道,設(shè)計(jì)目標(biāo)是通過 CDC 模塊抓取業(yè)務(wù)數(shù)據(jù)源變更,并以統(tǒng)一的格式發(fā)布到變更分發(fā)平臺(tái),所有消費(fèi)者通過客戶端庫接入變更分發(fā)平臺(tái)獲取實(shí)時(shí)數(shù)據(jù)變更。
我們先看一看這套模型要如何才解決上面的三個(gè)問題:
一致性:數(shù)據(jù)變更分發(fā)給下游應(yīng)用后,下游應(yīng)用可以不斷重試保證變更成功應(yīng)用到目標(biāo)數(shù)據(jù)源——這個(gè)過程要真正實(shí)現(xiàn)一致性還要滿足兩個(gè)前提,一是從數(shù)據(jù)變更抓取模塊投遞到下游應(yīng)用并消費(fèi)這個(gè)過程不能丟數(shù)據(jù),也就是要保證至少一次交付;二是下游應(yīng)用的消費(fèi)必須是冪等的。
異構(gòu)遷移:異構(gòu)包含多種含義:表的 Schema 不同、表的物理結(jié)構(gòu)不同(單表到分片表)、數(shù)據(jù)庫不同(如 MySQL -> EleasticSearch) ,后兩者只要下游消費(fèi)端實(shí)現(xiàn)對(duì)應(yīng)的寫入接口就能解決;而 Schema 不同,尤其是當(dāng)新庫的表聚合了多張舊庫的表信息時(shí),就要用反查源數(shù)據(jù)庫或 Stream Join 等手段實(shí)現(xiàn)。
實(shí)時(shí)性:只要保證各模塊的數(shù)據(jù)傳輸與寫入的效率,該模型便能保證實(shí)時(shí)性。
可以看到,這套模型本身對(duì)各個(gè)組件是有一些要求的,我們下面的設(shè)計(jì)選型也會(huì)參照這些要求。
在設(shè)計(jì)階段,我們調(diào)研對(duì)比了多個(gè)開源解決方案:
databus: Linkedin 的分布式數(shù)據(jù)變更抓取系統(tǒng);
Yelp’s data pipeline: Yelp 的數(shù)據(jù)管道;
Otter: 阿里開源的分布式數(shù)據(jù)庫同步系統(tǒng);
Debezium: Redhat 開源的數(shù)據(jù)變更抓取組件;
這些解決方案關(guān)注的重點(diǎn)各有不同,但基本思想是一致的:使用變更抓取模塊實(shí)時(shí)訂閱數(shù)據(jù)庫變更,并分發(fā)到一個(gè)中間存儲(chǔ)供下游應(yīng)用消費(fèi)。下面是四個(gè)解決方案的對(duì)比矩陣:
Linkedin databus 的架構(gòu)圖
Linkedin databus 的論文有很強(qiáng)的指導(dǎo)性,但它的 MySQL 變更抓取模塊很不成熟,官方支持的是 Oracle,MySQL 只是使用另一個(gè)開源組件 OpenReplicator 做了一個(gè) demo。另一個(gè)不利因素 databus 使用了自己實(shí)現(xiàn)的一個(gè) Relay 作為變更分發(fā)平臺(tái),相比于使用開源消息隊(duì)列的方案,這對(duì)維護(hù)和外部集成都不友好。
otter 的架構(gòu)圖
Otter 和 Canal 在國(guó)內(nèi)相當(dāng)知名,Canal 還支持了阿里云 DRDS 的二級(jí)索引構(gòu)建和小表同步,工程穩(wěn)定性上有保障。但 Otter 本身無法很好地支持多表聚合到新表,開源版本也不支持同步到分片表當(dāng)中,能夠采取的一個(gè)折衷方案是直接將 Canal 訂閱的變更寫入消息隊(duì)列,自己寫下游程序?qū)崿F(xiàn)聚合同步等邏輯。該方案也是我們的候選方案。
Yelp’s data pipeline 是一個(gè)大而全的解決方案。它使用 Mysql-Streamer(一個(gè)通過 binlog 實(shí)現(xiàn)的 MySQL CDC 模塊)將所有的數(shù)據(jù)庫變更寫入 Kafka,并提供了 Schematizer 這樣的 Schema 注冊(cè)中心和定制化的 Python 客戶端庫解決通信問題。遺憾的是該方案是 Python 構(gòu)建的,與我們的 Java 技術(shù)棧相性不佳。
最后是 Debezium , 不同于上面的解決方案,它只專注于 CDC,它的亮點(diǎn)有:
支持 MySQL、MongoDB、PostgreSQL 三種數(shù)據(jù)源的變更抓取,并且社區(qū)正在開發(fā) Oracle 與 Cassandra 支持;
Snapshot Mode 可以將表中的現(xiàn)有數(shù)據(jù)全部導(dǎo)入 Kafka,并且全量數(shù)據(jù)與增量數(shù)據(jù)形式一致,可以統(tǒng)一處理;
利用了 Kafka 的 Log Compaction 特性,變更數(shù)據(jù)可以實(shí)現(xiàn)”不過期”永久保存;
利用了 Kafka Connect,自動(dòng)擁有高可用與開箱即用的調(diào)度接口;
社區(qū)活躍:Debezium 很年輕,面世不到1年,但它的 Gitter上每天都有百余條技術(shù)討論,并且有兩位 Redhat 全職工程師進(jìn)行維護(hù);
最終我們選擇了 Debezium + Kafka 作為整套架構(gòu)的基礎(chǔ)組件,并以 Apache Avro 作為統(tǒng)一數(shù)據(jù)格式,下面我們將結(jié)合各個(gè)模塊的目標(biāo)與設(shè)計(jì)闡釋選型動(dòng)機(jī)。
變更數(shù)據(jù)抓取通常需要針對(duì)不同數(shù)據(jù)源訂制實(shí)現(xiàn),而針對(duì)特定數(shù)據(jù)源,實(shí)現(xiàn)方式一般有兩種:
基于自增列或上次修改時(shí)間做增量查詢;
利用數(shù)據(jù)源本身的事務(wù)日志或 Slave 同步等機(jī)制實(shí)時(shí)訂閱變更;
第一種方式實(shí)現(xiàn)簡(jiǎn)單,以 SQL 為例:相信大家都寫過類似的 SQL, 每次查詢時(shí),查詢 [last_query_time, now) 區(qū)間內(nèi)的增量數(shù)據(jù),lastmodified 列也可以用自增主鍵來替代。這種方式的缺點(diǎn)是實(shí)時(shí)性差,對(duì)數(shù)據(jù)庫帶來了額外壓力,并且侵入了表設(shè)計(jì) —— 所有要實(shí)現(xiàn)變更抓取的表都必須有用于增量查詢的列并且在該列上構(gòu)建索引。另外,這種方式無法感知物理刪除(Delete), 刪除邏輯只能用一個(gè) delete 列作為 flag 來實(shí)現(xiàn)。
第二種方式實(shí)現(xiàn)起來相對(duì)困難,但它很好地解決了第一種方式的問題,因此前文提到的開源方案也都采用了這種方式。下面我們著重分析在 MySQL 中如何實(shí)現(xiàn)基于事務(wù)日志的實(shí)時(shí)變更抓取。
MySQL 的事務(wù)日志稱為 binlog,常見的 MySQL 主從同步就是使用 Binlog 實(shí)現(xiàn)的:
我們把 Slave 替換成 CDC 模塊,CDC 模塊模擬 MySQL Slave 的交互協(xié)議,便能收到 Master 的 binlog 推送:
CDC 模塊解析 binlog,產(chǎn)生特定格式的變更消息,也就完成了一次變更抓取。但這還不夠,CDC 模塊本身也可能掛掉,那么恢復(fù)之后如何保證不丟數(shù)據(jù)又是一個(gè)問題。這個(gè)問題的解決方案也是要針對(duì)不同數(shù)據(jù)源進(jìn)行設(shè)計(jì)的,就 MySQL 而言,通常會(huì)持久化已經(jīng)消費(fèi)的 binlog 位點(diǎn)或 Gtid(MySQL 5.6之后引入)來標(biāo)記上次消費(fèi)位置。其中更好的選擇是 Gtid,因?yàn)樵撐稽c(diǎn)對(duì)于一套 MySQL 體系(主從或多主)是全局的,而 binlog 位點(diǎn)是單機(jī)的,無法支持主備或多主架構(gòu)。
那為什么最后選擇了 Debezium 呢?
MySQL CDC 模塊的一個(gè)挑戰(zhàn)是如何在 binlog 變更事件中加入表的 Schema 信息(如標(biāo)記哪些字段為主鍵,哪些字段可為 null)。Debezium 在這點(diǎn)上處理得很漂亮,它在內(nèi)存中維護(hù)了數(shù)據(jù)庫每張表的 Schema,并且全部寫入一個(gè) backup 的 Kafka Topic 中,每當(dāng) binlog 中出現(xiàn) DDL 語句,便應(yīng)用這條 DDL 來更新 Schema。而在節(jié)點(diǎn)宕機(jī),Debezium 實(shí)例被調(diào)度到另一個(gè)節(jié)點(diǎn)上后,又會(huì)通過 backup topic 恢復(fù) Schema 信息,并從上次消費(fèi)位點(diǎn)繼續(xù)解析 Binlog。
在我們的場(chǎng)景下,另一個(gè)挑戰(zhàn)是,我們數(shù)據(jù)庫已經(jīng)有大量的現(xiàn)存數(shù)據(jù),數(shù)據(jù)遷移時(shí)的現(xiàn)存數(shù)據(jù)要如何處理。這時(shí),Debezium 獨(dú)特的 Snapshot 功能就能幫上忙,它可以實(shí)現(xiàn)將現(xiàn)有數(shù)據(jù)作為一次”插入變更”捕捉到 Kafka 中,因此只要編寫一次客戶端就能一并處理全量數(shù)據(jù)與后續(xù)的增量數(shù)據(jù)。
變更分發(fā)平臺(tái)可以有很多種形式,本質(zhì)上它只是一個(gè)存儲(chǔ)變更的中間件,那么如何進(jìn)行選型呢?首先由于變更數(shù)據(jù)數(shù)據(jù)量級(jí)大,且操作時(shí)沒有事務(wù)需求,所以先排除了關(guān)系型數(shù)據(jù)庫, 剩下的 NoSQL 如 Cassandra,mq 如 Kafka、RabbitMQ 都可以勝任。其區(qū)別在于,消費(fèi)端到分發(fā)平臺(tái)拉取變更時(shí),假如是 NoSQL 的實(shí)現(xiàn),那么就能很容易地實(shí)現(xiàn)條件過濾等操作(比如某個(gè)客戶端只對(duì)特定字段為 true 的消息感興趣); 但 NoSQL 的實(shí)現(xiàn)往往會(huì)在吞吐量和一致性上輸給 mq。這里就是一個(gè)設(shè)計(jì)抉擇的問題,最終我們選擇了 mq,主要考慮的點(diǎn)是:消費(fèi)端往往是無狀態(tài)應(yīng)用,很容易進(jìn)行水平擴(kuò)展,因此假如有條件過濾這樣的需求,我們更希望把這樣的計(jì)算壓力放在消費(fèi)端上。
而在 mq 里,Kafka 則顯得具有壓倒性優(yōu)勢(shì)。Kafka 本身就有大數(shù)據(jù)的基因,通常被認(rèn)為是目前吞吐量最大的消息隊(duì)列,同時(shí),使用 Kafka 有一項(xiàng)很適合該場(chǎng)景的特性:Log Compaction。Kafka 默認(rèn)的過期清理策略(log.cleanup.policy)是delete,也就是刪除過期消息,配置為compact則可以啟用 Log Compaction 特性,這時(shí) Kafka 不再刪除過期消息,而是對(duì)所有過期消息進(jìn)行”折疊” —— 對(duì)于 key 相同的所有消息會(huì),保留最新的一條。
舉個(gè)例子,我們對(duì)一張表執(zhí)行下面這樣的操作:對(duì)應(yīng)的在 mq 中的流總共會(huì)產(chǎn)生 4 條變更消息,而最下面兩條分別是 id:1 id:2 下的最新記錄,在它們之前的兩條 INSERT 引起的變更就會(huì)被 Kafka 刪除,最終我們?cè)?Kafka 中看到的就是兩行記錄的最新狀態(tài),而一個(gè)持續(xù)訂閱該流的消費(fèi)者則能收到全部4條記錄。
這種行為有一個(gè)有趣的名字,流表二相性(Stream Table Durability):Topic 中有無盡的變更消息不斷被寫入,這是流的特質(zhì);而 Topic 某一時(shí)刻的狀態(tài),恰恰是該時(shí)刻對(duì)應(yīng)的數(shù)據(jù)表的一個(gè)快照(參見上面的例子),每條新消息的到來相當(dāng)于一次 Upsert,這又是表的特性。落到實(shí)踐中來講,Log Compaction 對(duì)于我們的場(chǎng)景有一個(gè)重要應(yīng)用:全量數(shù)據(jù)遷移與數(shù)據(jù)補(bǔ)償,我們可以直接編寫針對(duì)每條變更數(shù)據(jù)的處理程序,就能兼顧全量遷移與之后的增量同步兩個(gè)過程;而在數(shù)據(jù)異常時(shí),我們可以重新回放整個(gè) Kafka Topic —— 該 Topic 就是對(duì)應(yīng)表的快照,針對(duì)上面的例子,我們回放時(shí)只會(huì)讀到最新的兩條消息,不需要讀全部四條消息也能保證數(shù)據(jù)正確。
關(guān)于 Kafka 作為變更分發(fā)平臺(tái),最后要說的就是消費(fèi)順序的問題。大家都知道 Kafka 只能保證單個(gè) Partition 內(nèi)消息有序,而對(duì)于整個(gè) Topic,消息是無序的。一般的認(rèn)知是,數(shù)據(jù)變更的消費(fèi)為了邏輯的正確性,必須按序消費(fèi)。按著這個(gè)邏輯,我們的 Topic 只能有單個(gè) Partition,這就大大犧牲了 Kafka 的擴(kuò)展性與吞吐量。其實(shí)這里有一個(gè)誤區(qū),對(duì)于數(shù)據(jù)庫變更抓取,我們只要保證 同一行記錄的變更有序 就足夠了。還是上面的例子,我們只需要保證對(duì)id:2 這行的 insert 消息先于 update 消息,該行數(shù)據(jù)最后就是正確的。而實(shí)現(xiàn)”同一行記錄變更有序”就簡(jiǎn)單多了,Kafka Producer 對(duì)帶 key 的消息默認(rèn)使用 key 的 hash 決定分片,因此只要用數(shù)據(jù)行的主鍵作為消息的 key,所有該行的變更都會(huì)落到同一個(gè) Parition 上,自然也就有序了。這有一個(gè)要求就是 CDC 模塊必須解析出變更數(shù)據(jù)的主鍵 —— 而這點(diǎn) Debezium 已經(jīng)幫助我們解決了。
數(shù)據(jù)格式的選擇同樣十分重要。首先想到的當(dāng)然是 json, 目前最常見的消息格式,不僅易讀,開發(fā)也都對(duì)它十分熟悉。但 json 本身有一個(gè)很大的不足,那就是契約性太弱,它的結(jié)構(gòu)可以隨意更改:試想假如有一個(gè)接口返回 String,注釋上說這是個(gè)json,那我們?cè)撛趺淳帉憣?duì)應(yīng)的調(diào)用代碼呢?是不是需要翻接口文檔,提前獲知這段 json 的 schema,然后才能開始編寫代碼,并且這段代碼隨時(shí)可能會(huì)因?yàn)檫@段 json 的格式改變而 break。
在規(guī)模不大的系統(tǒng)中,這個(gè)問題并不顯著。但假如在一個(gè)擁有上千種數(shù)據(jù)格式的數(shù)據(jù)管道上工作,這個(gè)問題就會(huì)很麻煩,首先當(dāng)你訂閱一個(gè)變更 topic 時(shí),你完全處于懵逼狀態(tài)——不知道這個(gè) topic 會(huì)給你什么,當(dāng)你經(jīng)過文檔的洗禮與不斷地調(diào)試終于寫完了客戶端代碼,它又隨時(shí)會(huì)因?yàn)?topic 中的消息格式變更而掛掉。
參考 Yelp 和 Linkedin 的選擇,我們決定使用 Apache Avro 作為統(tǒng)一的數(shù)據(jù)格式。Avro 依賴模式 Schema 來實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)定義,而 Schema 通常使用 json 格式進(jìn)行定義,一個(gè)典型的 Schema 如下:這里要介紹一點(diǎn)背景知識(shí),Avro 的一個(gè)重要特性就是支持 Schema 演化,它定義了一系列的演化規(guī)則,只要符合該規(guī)則,使用不同的 Schema 也能夠正常通信。也就是說,使用 Avro 作為數(shù)據(jù)格式進(jìn)行通信的雙方是有自由更迭 Schema 的空間的。
在我們的場(chǎng)景中,數(shù)據(jù)庫表的 Schema 變更會(huì)引起對(duì)應(yīng)的變更數(shù)據(jù) Schema 變更,而每次進(jìn)行數(shù)據(jù)庫表 Schema 變更就更新下游消費(fèi)端顯然是不可能的。所以這時(shí)候 Avro 的 Schema 演化機(jī)制就很重要了。我們做出約定,同一個(gè) Topic 上傳輸?shù)南ⅲ?Avro Schema 的變化必須符合演化規(guī)則,這么一來,消費(fèi)者一旦開始正常消費(fèi)之后就不會(huì)因?yàn)橄⒌?Schema 變化而掛掉。
上圖展現(xiàn)了以變更分發(fā)平臺(tái)(Kafka) 為中心的系統(tǒng)拓?fù)?。其中有一些上面沒有涉及的點(diǎn):我們使用 Kafka 的 MirrorMaker 解決了跨數(shù)據(jù)中心問題,使用 Kafka Connect 集群運(yùn)行 Debezium 任務(wù)實(shí)現(xiàn)了高可用與調(diào)度能力。
我們?cè)倏纯?Vimur 是如何解決數(shù)據(jù)遷移與同步問題的,下圖展示了一次典型的數(shù)據(jù)同步過程:
下圖是一次典型的數(shù)據(jù)遷移過程,數(shù)據(jù)遷移通常伴隨著服務(wù)拆分與分庫分表:
這里其實(shí)同步任務(wù)的編寫是頗有講究的,因?yàn)槲覀円话阈枰哂嗪芏嘈碌牧械叫卤砩?,所以單個(gè)流中的數(shù)據(jù)是不夠的,這時(shí)有兩種方案:
反查數(shù)據(jù)庫:邏輯簡(jiǎn)單,只要查詢所需要的冗余列即可,但所有相關(guān)的列變動(dòng)都要執(zhí)行一次反查會(huì)對(duì)源庫造成額外壓力;Stream Join:Stream Join 通常需要額外存儲(chǔ)的支持,無論用什么框架實(shí)現(xiàn),最終效果是把反查壓力放到了框架依賴的額外存儲(chǔ)上;這兩種方案見仁見智,Stream Join 邏輯雖然更復(fù)雜,但框架本身如 Flink、Kafka Stream 都提供了 DSL 簡(jiǎn)化編寫。最終的選型實(shí)際上取決于需不需要把反查的壓力分散出去。
Vimur 的另一個(gè)深度應(yīng)用是解決跨庫查詢,分庫分表后數(shù)據(jù)表 JOIN 操作將很難實(shí)現(xiàn),通常我們都會(huì)查詢多個(gè)數(shù)據(jù)庫,然后在代碼中進(jìn)行 JOIN。這種辦法雖然麻煩,但卻不是不采取的妥協(xié)策略(框架來做跨庫 JOIN ,可行但有害,因?yàn)橛泻芏嘈阅芟葳灞仨毷謩?dòng)編碼去避免)。然而有些場(chǎng)景這種辦法也很難解決,比如多表 INNER JOIN 后的分頁。這時(shí)我們采取的解決方案就是利用 Vimur 的變更數(shù)據(jù),將需要 JOIN 的表聚合到搜索引擎或 NoSQL 中,以文檔的形式提供查詢。
除了上面的應(yīng)用外,Vimur 還被我們應(yīng)用于搜索索引的實(shí)時(shí)構(gòu)建、業(yè)務(wù)事件通知等場(chǎng)景,并計(jì)劃服務(wù)于緩存刷新、響應(yīng)式架構(gòu)等場(chǎng)景?;仡櫘?dāng)初的探索歷程,很多選擇可能不是最好的,但一定是反復(fù)實(shí)踐后我們認(rèn)為最適合我們的。假如你也面臨復(fù)雜數(shù)據(jù)層中的數(shù)據(jù)同步、數(shù)據(jù)遷移、緩存刷新、二級(jí)索引構(gòu)建等問題,不妨嘗試一下基于 CDC 的實(shí)時(shí)數(shù)據(jù)管道方案。
感謝各位的閱讀,以上就是“怎么用Kafka與Debezium構(gòu)建實(shí)時(shí)數(shù)據(jù)同步”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)怎么用Kafka與Debezium構(gòu)建實(shí)時(shí)數(shù)據(jù)同步這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。