【建議收藏】超詳細的Canal入門,看這篇就夠了!!!

来源:https://www.cnblogs.com/jiagooushi/archive/2023/03/06/17184045.html
-Advertisement-
Play Games

概述 canal是阿裡巴巴旗下的一款開源項目,純Java開發。基於資料庫增量日誌解析,提供增量數據訂閱&消費,目前主要支持了MySQL(也支持mariaDB)。 背景 早期,阿裡巴巴B2B公司因為存在杭州和美國雙機房部署,存在跨機房同步的業務需求。不過早期的資料庫同步業務,主要是基於trigger的 ...


概述

canal是阿裡巴巴旗下的一款開源項目,純Java開發。基於資料庫增量日誌解析,提供增量數據訂閱&消費,目前主要支持了MySQL(也支持mariaDB)。

背景

早期,阿裡巴巴B2B公司因為存在杭州和美國雙機房部署,存在跨機房同步的業務需求。不過早期的資料庫同步業務,主要是基於trigger的方式獲取增量變更,不過從2010年開始,阿裡系公司開始逐步的嘗試基於資料庫的日誌解析,獲取增量變更進行同步,由此衍生出了增量訂閱&消費的業務,從此開啟了一段新紀元。ps. 目前內部使用的同步,已經支持mysql5.x和oracle部分版本的日誌解析

基於日誌增量訂閱&消費支持的業務:

  1. 資料庫鏡像
  2. 資料庫實時備份
  3. 多級索引 (賣家和買家各自分庫索引)
  4. search build
  5. 業務cache刷新
  6. 價格變化等重要業務消息

當前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x

工作原理

Mysql的BinLog

它記錄了所有的DDL和DML(除了數據查詢語句)語句,以事件形式記錄,還包含語句所執行的消耗的時間。主要用來備份和數據同步。

binlog 有三種模式:STATEMENT、ROW、MIXED

  1. STATEMENT 記錄的是執行的sql語句
  2. ROW 記錄的是真實的行數據記錄
  3. MIXED 記錄的是1+2,優先按照1的模式記錄
舉例說明

舉例來說,下麵的sql

COPYupdate user set age=20

對應STATEMENT模式只有一條記錄,對應ROW模式則有可能有成千上萬條記錄(取決資料庫中的記錄數)。

MySQL主備複製原理

img

  1. Slave 上面的IO線程連接上 Master,並請求從指定日誌文件的指定位置(或者從最開始的日誌)之後的日誌內容;
  2. Master 接收到來自 Slave 的 IO 線程的請求後,通過負責複製的 IO 線程根據請求信息讀取指定日誌指定位置之後的日誌信息,返回給 Slave 端的 IO 線程。返回信息中除了日誌所包含的信息之外,還包括本次返回的信息在 Master 端的 Binary Log 文件的名稱以及在 Binary Log 中的位置;
  3. Slave 的 IO 線程接收到信息後,將接收到的日誌內容依次寫入到 Slave 端的Relay Log文件(mysql-relay-bin.xxxxxx)的最末端,並將讀取到的Master端的bin-log的文件名和位置記錄到master- info文件中,以便在下一次讀取的時候能夠清楚的高速Master“我需要從某個bin-log的哪個位置開始往後的日誌內容,請發給我”
  4. Slave 的 SQL 線程檢測到 Relay Log 中新增加了內容後,會馬上解析該 Log 文件中的內容成為在 Master 端真實執行時候的那些可執行的 Query 語句,併在自身執行這些 Query。這樣,實際上就是在 Master 端和 Slave 端執行了同樣的 Query,所以兩端的數據是完全一樣的。
    當然這個過程本質上還是存在一定的延遲的。

mysql的binlog文件長這個樣子。

COPYmysql-bin.003831
mysql-bin.003840  
mysql-bin.003849  
mysql-bin.003858 

啟用Binlog註意以下幾點:

  1. Master主庫一般會有多台Slave訂閱,且Master主庫要支持業務系統實時變更操作,伺服器資源會有瓶頸;
  2. 需要同步的數據表一定要有主鍵;

canal能夠同步數據的原理

理解了mysql的主從同步的機制再來看canal就比較清晰了,canal主要是聽過偽裝成mysql從server來向主server拉取數據。

img

  1. canal模擬mysql slave的交互協議,偽裝自己為mysql slave,向mysql master發送dump協議
  2. mysql master收到dump請求,開始推送binary log給slave(也就是canal)
  3. canal解析binary log對象(原始為byte流)

Canal架構

canal的設計理念

canal的組件化設計非常好,有點類似於tomcat的設計。使用組合設計,依賴倒置,面向介面的設計。

img

canal的組件

  1. canal server 這個代表了我們部署的一個canal 應用
  2. canal instance 這個代表了一個canal server中的多個 mysql instance ,從這一點說明一個canal server可以搜集多個庫的數據,在canal中叫 destionation。

每個canal instance 有多個組件構成。在conf/spring/default-instance.xml中配置了這些組件。他其實是使用了spring的容器來進行這些組件管理的。

instance 包含的組件

這裡是一個cannalInstance工作所包含的大組件。截取自 conf/spring/default-instance.xml

COPY<bean id="instance" class="com.alibaba.otter.canal.instance.spring.CanalInstanceWithSpring">
    <property name="destination" value="${canal.instance.destination}" />
    <property name="eventParser">
        <ref local="eventParser" />
    </property>
    <property name="eventSink">
        <ref local="eventSink" />
    </property>
    <property name="eventStore">
        <ref local="eventStore" />
    </property>
    <property name="metaManager">
        <ref local="metaManager" />
    </property>
    <property name="alarmHandler">
        <ref local="alarmHandler" />
    </property>
</bean>  
EventParser設計

eventParser 最基本的組件,類似於mysql從庫的dump線程,負責從master中獲取bin_log

img

整個parser過程大致可分為幾步:

  1. Connection獲取上一次解析成功的位置 (如果第一次啟動,則獲取初始指定的位置或者是當前資料庫的binlog位點)
  2. Connection建立鏈接,發送BINLOG_DUMP指令
    // 0. write command number
    // 1. write 4 bytes bin-log position to start at
    // 2. write 2 bytes bin-log flags
    // 3. write 4 bytes server id of the slave
    // 4. write bin-log file name
  3. Mysql開始推送Binaly Log
  4. 接收到的Binaly Log的通過Binlog parser進行協議解析,補充一些特定信息
    // 補充欄位名字,欄位類型,主鍵信息,unsigned類型處理
  5. 傳遞給EventSink模塊進行數據存儲,是一個阻塞操作,直到存儲成功
  6. 存儲成功後,定時記錄Binaly Log位置
EventSink設計

eventSink 數據的歸集,使用設置的filter對bin log進行過濾,工作的過程如下。

img

說明:

數據過濾:支持通配符的過濾模式,表名,欄位內容等

數據路由/分發:解決1:n (1個parser對應多個store的模式)

數據歸併:解決n:1 (多個parser對應1個store)

數據加工:在進入store之前進行額外的處理,比如join

數據1:n業務

為了合理的利用資料庫資源, 一般常見的業務都是按照schema進行隔離,然後在mysql上層或者dao這一層面上,進行一個數據源路由,屏蔽資料庫物理位置對開發的影響,阿裡系主要是通過cobar/tddl來解決數據源路由問題。

所以,一般一個資料庫實例上,會部署多個schema,每個schema會有由1個或者多個業務方關註

數據n:1業務

同樣,當一個業務的數據規模達到一定的量級後,必然會涉及到水平拆分和垂直拆分的問題,針對這些拆分的數據需要處理時,就需要鏈接多個store進行處理,消費的位點就會變成多份,而且數據消費的進度無法得到儘可能有序的保證。

所以,在一定業務場景下,需要將拆分後的增量數據進行歸併處理,比如按照時間戳/全局id進行排序歸併.

EventStore設計

eventStore 用來存儲filter過濾後的數據,canal目前的數據只在這裡存儲,工作流程如下

  • 目前僅實現了Memory記憶體模式,後續計劃增加本地file存儲,mixed混合模式
  • 借鑒了Disruptor的RingBuffer的實現思路

img

定義了3個cursor

  • Put : Sink模塊進行數據存儲的最後一次寫入位置
  • Get : 數據訂閱獲取的最後一次提取位置
  • Ack : 數據消費成功的最後一次消費位置

借鑒Disruptor的RingBuffer的實現,將RingBuffer拉直來看:

img

實現說明:

  • Put/Get/Ack cursor用於遞增,採用long型存儲
  • buffer的get操作,通過取餘或者與操作。(與操作: cusor & (size - 1) , size需要為2的指數,效率比較高)
metaManager

metaManager 用來存儲一些原數據,比如消費到的游標,當前活動的server等信息

alarmHandler

alarmHandler 報警,這個一般情況下就是錯誤日誌,理論上應該是可以定製成郵件等形式,但是目前不支持

各個組件目前支持的類型

canal採用了spring bean container的方式來組裝一個canal instance ,目的是為了能夠更加靈活。

canal通過這些組件的選取可以達到不同使用場景的效果,比如單機的話,一般使用file來存儲metadata就行了,HA的話一般使用zookeeper來存儲metadata。

eventParser

eventParser 目前只有三種

  • MysqlEventParser 用於解析mysql的日誌
  • GroupEventParser 多個eventParser的集合,理論上是對應了分表的情況,可以通過這個合併到一起
  • RdsLocalBinlogEventParser 基於rds的binlog 的複製
eventSink

eventSink 目前只有EntryEventSink 就是基於mysql的binlog數據對象的處理操作

eventStore

eventStore 目前只有一種 MemoryEventStoreWithBuffer,內部使用了一個ringbuffer 也就是說canal解析的數據都是存在記憶體中的,並沒有到zookeeper當中。

metaManager

metaManager 這個比較多,其實根據元數據存放的位置可以分為三大類,memory,file,zookeeper

Canal-HA機制

canal是支持HA的,其實現機制也是依賴zookeeper來實現的,用到的特性有watcher和EPHEMERAL節點(和session生命周期綁定),與HDFS的HA類似。

canal的ha分為兩部分,canal server和canal client分別有對應的ha實現

  • canal server: 為了減少對mysql dump的請求,不同server上的instance(不同server上的相同instance)要求同一時間只能有一個處於running,其他的處於standby狀態(standby是instance的狀態)。
  • canal client: 為了保證有序性,一份instance同一時間只能由一個canal client進行get/ack/rollback操作,否則客戶端接收無法保證有序。

server ha的架構圖如下

img

大致步驟:

  1. canal server要啟動某個canal instance時都先向zookeeper_進行一次嘗試啟動判斷_(實現:創建EPHEMERAL節點,誰創建成功就允許誰啟動)
  2. 創建zookeeper節點成功後,對應的canal server就啟動對應的canal instance,沒有創建成功的canal instance就會處於standby狀態
  3. 一旦zookeeper發現canal server A創建的instance節點消失後,立即通知其他的canal server再次進行步驟1的操作,重新選出一個canal server啟動instance。
  4. canal client每次進行connect時,會首先向zookeeper詢問當前是誰啟動了canal instance,然後和其建立鏈接,一旦鏈接不可用,會重新嘗試connect。

Canal Client的方式和canal server方式類似,也是利用zookeeper的搶占EPHEMERAL節點的方式進行控制.

canal的工作過程

dump日誌

啟動時去MySQL 進行dump操作的binlog 位置確定

工作的過程。在啟動一個canal instance 的時候,首先啟動一個eventParser 線程來進行數據的dump 當他去master拉取binlog的時候需要binlog的位置,這個位置的確定是按照如下的順序來確定的(這個地方講述的是HA模式哈)。

  1. 在啟動的時候判斷是否使用zookeeper,如果是zookeeper,看能否拿到 cursor (也就是binlog的信息),如果能夠拿到,把這個信息存到記憶體中(MemoryLogPositionManager),然後拿這個信息去mysql中dump binlog
  2. 通過1拿不到的話(一般是zookeeper當中每一,比如第一次搭建的時候,或者因為某些原因zk中的數據被刪除了),就去配置文件配置當中的去拿,把這個信息存到記憶體中(MemoryLogPositionManager),然後拿這個信息去mysql中dump binlog
  3. 通過2依然沒有拿到的話,就去mysql 中執行一個sql show master status 這個語句會顯示當前mysql binlog最後位置的信息,也就是剛寫入的binlog所在的位置信息。把這個信息存到記憶體中(MemoryLogPositionManager),然後拿這個信息去mysql中dump binlog。

後面的eventParser的操作就會以記憶體中(MemoryLogPositionManager)存儲的binlog位置去master進行dump操作了。

mysql的show master status 操作

COPYmysql> show master status\G
*************************** 1. row ***************************
             File: mysql-bin.000028
         Position: 635762367
     Binlog_Do_DB:
 Binlog_Ignore_DB:
Executed_Gtid_Set: 18db0532-6a08-11e8-a13e-52540042a113:1-2784514,
318556ef-4e47-11e6-81b6-52540097a9a8:1-30002,
ac5a3780-63ad-11e8-a9ac-52540042a113:1-5,
be44d87c-4f25-11e6-a0a8-525400de9ffd:1-156349782
1 row in set (0.00 sec

歸集(sink)和存儲(store)

數據在dump回來之後進行的歸集(sink)和存儲(store)

sink操作是可以支撐將多個eventParser的數據進行過濾filter

filter使用的是instance.properties中配置的filter,當然這個filter也可以由canal的client端在進行subscribe的時候進行設置。如果在client端進行了設置,那麼服務端配置文件instance.properties的配置都會失效

sink 之後將過濾後的數據存儲到eventStore當中去。

目前eventStore的實現只有一個MemoryEventStoreWithBuffer,也就是基於記憶體的ringbuffer,使用這個store有一個特點,這個ringbuffer是基於記憶體的,大小是有限制的(bufferSize = 16 * 1024 也就是16M),所以,當canal的客戶端消費比較慢的時候,ringbuffer中存滿了就會阻塞sink操作,那麼正讀取mysql binlogeventParser線程也會受阻。
  這種設計其實也是有道理的。 因為canal的操作是pull 模型,不是producer push的模型,所以他沒必要存儲太多數據,這樣就可以避免了數據存儲和持久化管理的一些問題。使數據管理的複雜度大大降低。

上面這些整個是canal的parser 線程的工作流程,主要對應的就是將數據從mysql搞下來,做一些基本的歸集和過濾,然後存儲到記憶體中。

binlog的消費者

canal從mysql訂閱了binlog以後主要還是想要給消費者使用。那麼binlog是在什麼時候被消費呢。這就是另一條主線了。就像咱們做一個toC的系統,管理系統是必須的,用戶使用的app或者web又是一套,eventParser 線程就像是管理系統,往裡面錄入基礎數據。canal的client就像是app端一樣,是這些數據的消費方。
  binlog的主要消費者就是canal的client端。使用的協議是基於tcp的google.protobuf,當然tcp的模式是io多路復用,也就是nio。當我們的client發起請求之後,canal的server端就會從eventStore中將數據傳輸給客戶端。根據客戶端的ack機制,將binlog的元數據信息定期同步到zookeeper當中。

canal的目錄結構

配置父目錄:
在下麵可以看到

COPYcanal
├── bin
│   ├── canal.pid
│   ├── startup.bat
│   ├── startup.sh
│   └── stop.sh
└── conf
    ├── canal.properties
    ├── gamer ---目錄
    ├── ww_social ---目錄
    ├── wother ---目錄
    ├── nihao ---目錄
    ├── liveim ---目錄
    ├── logback.xml
    ├── spring ---目錄
    ├── ym ---目錄
    └── xrm_ppp ---目錄

這裡是全部展開的目錄

COPYcanal
├── bin
│   ├── canal.pid
│   ├── startup.bat
│   ├── startup.sh
│   └── stop.sh
└── conf
    ├── canal.properties
    ├── game_center
    │   └── instance.properties
    ├── ww_social
    │   ├── h2.mv.db
    │   ├── h2.trace.db
    │   └── instance.properties
    ├── wwother
    │   ├── h2.mv.db
    │   └── instance.properties
    ├── nihao
    │   ├── h2.mv.db
    │   ├── h2.trace.db
    │   └── instance.properties
    ├── movie
    │   ├── h2.mv.db
    │   └── instance.properties
    ├── logback.xml
    ├── spring
    │   ├── default-instance.xml
    │   ├── file-instance.xml
    │   ├── group-instance.xml
    │   ├── local-instance.xml
    │   ├── memory-instance.xml
    │   └── tsdb
    │       ├── h2-tsdb.xml
    │       ├── mysql-tsdb.xml
    │       ├── sql
    │       └── sql-map
    └── ym
        └── instance.properties

Canal應用場景

同步緩存redis/全文搜索ES

canal一個常見應用場景是同步緩存/全文搜索,當資料庫變更後通過binlog進行緩存/ES的增量更新。當緩存/ES更新出現問題時,應該回退binlog到過去某個位置進行重新同步,並提供全量刷新緩存/ES的方法,如下圖所示。

img

下發任務

  另一種常見應用場景是下發任務,當數據變更時需要通知其他依賴系統。其原理是任務系統監聽資料庫變更,然後將變更的數據寫入MQ/kafka進行任務下發,比如商品數據變更後需要通知商品詳情頁、列表頁、搜索頁等先關係統。這種方式可以保證數據下發的精確性,通過MQ發送消息通知變更緩存是無法做到這一點的,而且業務系統中不會散落著各種下發MQ的代碼,從而實現了下發歸集,如下圖所示。

img

數據異構

在大型網站架構中,DB都會採用分庫分表來解決容量和性能問題,但分庫分表之後帶來的新問題。比如不同維度的查詢或者聚合查詢,此時就會非常棘手。一般我們會通過數據異構機制來解決此問題。

所謂的數據異構,那就是將需要join查詢的多表按照某一個維度又聚合在一個DB中。讓你去查詢。canal就是實現數據異構的手段之一。

img

本文由傳智教育博學谷狂野架構師教研團隊發佈。

如果本文對您有幫助,歡迎關註點贊;如果您有任何建議也可留言評論私信,您的支持是我堅持創作的動力。

轉載請註明出處!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Qt 學習筆記全系列傳送門: Qt 學習筆記 - 第一章 - 快速開始、信號與槽 【本章】Qt 學習筆記 - 第二章 - 添加圖片、佈局、界面切換 1、給 Qt 工程添加圖片 註意:不要隨意更改所需圖片的尾碼,否則可能導致無法正常使用,出現*Image format not supported*文件 ...
  • 字元串(str) 字元串的下標(索引) str_data = "python" p y t h o n 0 1 2 3 4 5 -6 -5 -4 -3 -2 -1 索引就是某數據在序列的位置 正索引:從左至右,從0開始 負索引:從右至左,從-1開始 其中:str_data[0] = str_data ...
  • 函數編程:強大的 Stream API 每博一文案 只要有人的地方,世界就不會是冰冷的,我們可以平凡,但絕對不可以平庸。 —————— 《平凡的世界》 人活著,就得隨時準備經受磨難。他已經看過一些書,知道不論是普通人還是了不起的人, 都要在自己的一生中經歷許多磨難。磨難使人堅強。 —————— 《平 ...
  • 眾所周知,request.getInputStream()只能調一次。如果希望在請求進入Controller之前統一列印請求參數(攔截器或過濾器),又不影響業務,我們只能將獲取到的輸入流緩存起來,後續都從緩存中獲取即可。 首先,自定義一個ServletInputStream package com. ...
  • 不建議使用JDBC直接將您的Cordova應用程式連接到MySQL資料庫,因為它會帶來安全風險.移動設備通常受到安全漏洞的約束,並且從移動應用程式連接到資料庫會增加暴露敏感信息的風險. 一種更好的方法是使用Back-最終服務(例如REST API)與資料庫進行交互.您的Cordova應用程式將與RE ...
  • 函數式編程:Lambda 表達式 每博一文案 曾經讀過的依然令我感動的句子,生活總是不如意,但往往是在無數痛苦中,但往往是在無數痛苦中,在重重矛盾 和艱難中才能成熟起來,堅強起來,愛情啊,它使荒蕪變成繁榮,平庸變得偉大,使死去的複活,活著的閃閃發光, 即使愛情是不盡的煎熬折磨,像冰霜般嚴厲,烈火般烤 ...
  • 背景 項目上需要對接scom微軟監控系統告警,能夠拿到手的資料十分有限,只有幾個官方文檔地址: Operations Manager REST API Reference - Operations Manager REST API | Microsoft Learn SCOM: Quick Star ...
  • 背景 當需要處理規模較大、任務較複雜的優化問題或訓練神經網路時,我們經常會遇到程式運行時間長或無法完成的情況。然而,這不一定是由於問題規模大或電腦硬體能力的限制。即使嘗試使用更高性能的伺服器或電腦,也不能保證能夠有效地加速代碼運行。因為高性能的硬體通常需要與為高性能計算而設計的代碼相匹配。 本文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...