技術乾貨 | 資料中介軟體如何與GreatSQL資料同步?
1. 引入
先前介紹了ElasticSearch,以及ES配合MySQL的問題,這種方案是讓ES上的資料根據MySQL的資料做對照從而形成對應的索引,再將資料通過處理和封裝存放在ES當中。( 可回顧: 技術分析 | 淺析MySQL與ElasticSearch的組合使用 )
回到生產環境,比如,我們如何保證MySQL系開源資料庫GreatSQL中與ES對照的資料,發生更新的時候ES也進行更新呢?下面以ES為例進行分析。
2.傳統方案介紹
2.1 直接的"同步"更新
第一種方式十分直接,當發生對GreatSQL資料的更新操作時,由伺服器對GreatSQL和ES同時進行更新操作,如圖:
這種方式實現起來十分“簡單粗暴”,容易理解,顯然可以解決問題,但絕不是最優解,原因如下:
-
首先,這種方法使得我們進行資料庫的資料寫入、修改、刪除等操作,後面都要跟上ES的同步操作,程式碼書寫也過於冗長,且大大加大了業務的耦合度; -
其次,這種方法不能很好解決“同步”的問題,如果在執行對應操作的時候發生了斷電等情況,就可能導致資料不同步的問題; -
最後,為了保證兩者的更新要麼同時完成要麼都不完成,需要開啟事務來處理,系統的效能有所降低。並且,在高併發情況下,有可能造成服務的“雪崩”。
2.2 非同步的"同步"更新
針對前面的方案,可以考慮加入訊息佇列的中介軟體來優化,與第一種方法不同的是,當發生對GreatSQL資料的更新操作時,伺服器會完成GreatSQL資料的更新,並通過MQ的佇列設定好的交換機傳送更新ES的訊息,給對應的接收更新訊息的佇列,進而完成對應ES資料更新的實現。如圖:
這種方案將直接的更新方式轉換為非同步的更新方式,效能顯然提高了,同時降低了業務耦合度,也優化了資料“同步”的問題。但是,這種方案會出現MQ的消費者在消費時可能因為網路等原因導致使用者資料有延時。同時,從編碼角度看,每次系統要進行同步時都要編寫MQ程式碼,仍然存在業務的耦合,且系統架構的設計也因為加入新的中介軟體要重新考慮維護的問題。
3.監控binlog實現"同步"更新
上面兩種方案中都存在硬編碼問題,同時存在強的業務耦合,以至於實現GreatSQL資料更新後的資料同步問題的代價要麼是植入ES更新程式碼,要麼替換為MQ程式碼,程式碼的侵入性太強,且效能降低。 因此可以通過監控GreatSQL的binlog來實現資料的同步。
3.1 問題分析
binlog,該日誌存在於Server層次中,是使用儲存引擎都可以使用的日誌模組,binlog是邏輯日誌,記錄的是這個語句的原始邏輯,比如“給test表id=5這一行的col1欄位值加1”。binlog的日誌檔案是可以追加寫入的。“追加寫入”是指binlog日誌檔案寫到一定大小後會切換到下一個檔案進行寫入,可以設定sync_binlog為1,讓每次事務的binlog都持久化儲存到磁碟中。binlog在ROW模式下會記錄每次操作後每行記錄的變化。雖然此模式下所佔用的空間較大,但此模式可以保持資料的一致性。因此不管SQL是什麼,引用了什麼函式,他記錄的是執行後的效果。
3.2 使用Canal來監控binlog
Canal是阿里用Java開發的基於資料庫增量的日誌解析,是提供增量資料訂閱&消費的中介軟體。目前,Canal主要支援了 MySQL 的 binlog 解析,解析後可利用 Canal Client 來處理獲得的相關資料。
詳細可參考:
Canal的實現原理基於MySQL主從複製進行設計:
-
Master主庫將改變記錄到邏輯日誌(binary log)中(這些記錄叫做邏輯日誌事件,binary log events,可以通過 show binlog events 進行檢視); -
Slave從庫將Master主庫的binary log events拷貝到它的中繼日誌(relay log); -
Slave從庫讀取從重做中繼日誌中的事件,將改變反映它自己的資料同步到資料庫 中。
(源自canal官方文件)
而Canal就是將自身偽裝成一個Slave從庫,假裝從Master主庫複製資料:
-
Canal模擬MySQL Slave的互動協議,偽裝自己為MySQL Slave,向MySQL Master傳送dump協議; -
MySQL Master收到dump請求,開始推送binary log給Slave(也就是Canal); Canal解析binary log物件(原始為byte流)。
這種方案的好處是程式中沒有程式碼侵入、沒有硬編碼。同時,原有系統不需要任何變化對原方案的高耦合進行了業務解耦,不需要關注原來系統的業務邏輯。
對於自建 MySQL如GreatSQL , 需要先開啟 Binlog 寫入功能,配置 binlog-format 為 ROW 模式,my.cnf 中配置如下:
[mysqld]# 開啟 binloglog-bin=mysql-bin # 選擇 ROW 模式binlog-format=ROW # 指定開啟binlog的資料庫,不指定則全部資料庫開啟binlog-do-db=databasename# 配置 MySQL replaction 需要定義,不要和 canal 的 slaveId 重複server_id=1
建立canal賬戶,授權 canal 連結 MySQL 賬號具有作為 MySQL slave 的許可權
CREATE USER canal IDENTIFIED BY 'canal'; GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;FLUSH PRIVILEGES;
下載並啟動Canal
wget
mkdir /tmp/canal
tar zxvf canal.deployer-1.1.2.tar.gz -C /tmp/canal
修改Canal的配置檔案
vi conf/example/instance.properties
# # mysql serverId
canal.instance.mysql.slaveId = 1234
#position info,需要改成自己的資料庫資訊
canal.instance.master.address = 127.0.0.1:3306
canal.instance.master.journal.name =
canal.instance.master.position =
canal.instance.master.timestamp =
#canal.instance.standby.address =
#canal.instance.standby.journal.name =
#canal.instance.standby.position =
#canal.instance.standby.timestamp =
#username/password,需要改成自己的資料庫資訊
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal
canal.instance.defaultDatabaseName =
canal.instance.connectionCharset = UTF-8
#table regex
canal.instance.filter.regex = .\*\\\\..\*
Canal操作
# 啟動sh bin/startup.sh# 檢視server日誌vi logs/canal/canal.log</pre># 檢視 instance 的日誌vi logs/example/example.log# 關閉sh bin/stop.sh
以Java為例,建立測試專案Maven工程,匯入應用開發場景:
<dependencies> <dependency> <groupId>com.alibaba.otter</groupId> <artifactId>canal.client</artifactId> <version>1.1.2</version> </dependency> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.4.1</version> </dependency> </dependencies>
編寫日誌監視類CanalClient來從日誌中抓取資訊,首先,獲取canal的連線物件並連線:
//獲取 canal 連線物件CanalConnector canalConnector = CanalConnectors.newSingleConnector(new InetSocketAddress("127.0.0.1", 11111),"example", "canal","canal");//連線canalConnector.connect();
指定需要監控的資料庫,並根據資料量來獲取 Message :
//指定要監控的資料庫canalConnector.subscribe("databasename.*");//獲取 MessageMessage message = canalConnector.get(100);
接著就可以通過處理 Message 來得到監控資訊內容了:
List<CanalEntry.Entry>entries = message.getEntries(); if (entries.size() > 0) { for (CanalEntry.Entry entry : entries) { //獲取表名 String tableName = entry.getHeader().getTableName(); //Entry 型別 CanalEntry.EntryType entryType = entry.getEntryType(); //判斷 entryType 是否為 ROWDATA if (CanalEntry.EntryType.ROWDATA.equals(entryType)) { //序列化資料 ByteString storeValue = entry.getStoreValue(); //反序列化 CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(storeValue); //獲取事件型別 CanalEntry.EventType eventType = rowChange.getEventType(); //獲取具體的資料 List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList(); //遍歷並列印資料 for (CanalEntry.RowData rowData : rowDatasList) { List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList(); JSONObject beforeData = new JSONObject(); for (CanalEntry.Column column : beforeColumnsList) { beforeData.put(column.getName(), column.getValue()); } JSONObject afterData = new JSONObject(); List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList(); for (CanalEntry.Column column : afterColumnsList) { afterData.put(column.getName(), column.getValue()); } System.out.println("TableName:" + tableName + ",EventType:" + eventType + ",Before:" + beforeData + ",After:" + afterData); } } }}
從程式碼中可以看出,當系統與Canal建立連線後可以獲取Message來監控資料庫的操作,Message是一次Canal從MySQL的 bin log 中抓取的資訊,一個Message中可以有多個SQL執行的結果,每個SQL執行結果(SQL命令)稱為Entry,如圖:
Entry中包含 TableName 、EntryType和StoreValue,其中StoreValue 包含了資料變化的內容。如下:
要想進行使用還需要進行反序列化操作才可以進行使用,如下:
當然,實際生產環境Canal可以配置MQ模式,配合RocketMQ或者Kafka,canal會把資料傳送到MQ的topic中,然後通過訊息佇列的消費者進行處理。首先需要修改canal.properties檔案,這個檔案是 canal 的基本通用配置,canal 埠號預設就是 11111,修改 canal 的輸出model,預設 tcp,改為輸出到 kafka,instance.properties檔案輸出得到主 題 為kafka,可配置叢集,再次啟動canal就可以啟動 Kafka 消費客戶端測試,檢視消費情況了。
4. 總結
本文介紹了三種方式使得中介軟體的資料與GreatSQL的資料儲存同步,前兩種方法在使用效能和設計上都存在較大漏洞,而第三種通過讀取 GreatSQL的bin log日誌,獲取指定表的日誌資訊來實現資料同步的方法,在編碼上看沒有程式碼侵入,業務耦合度低,且原有系統不需要任何變化。但構建bin log監控系統需要做好規劃,不過多贅述了。
EnjoyGreatSQL :)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69997641/viewspace-2904907/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 技術乾貨|如何利用 ChunJun 實現資料離線同步?
- 技術乾貨|如何利用 ChunJun 實現資料實時同步?
- Golang進階,揉碎資料庫中介軟體,乾貨滿滿!Golang資料庫
- DTCC 乾貨 | 中國銀聯跨中心,異構資料同步技術與實踐
- 【技術乾貨】Oracle資料庫漏洞掃描指南Oracle資料庫
- 資料庫中介軟體詳解資料庫
- 大資料技術與應用課堂測試-資料清洗同步大資料
- 技術乾貨 | 阿里雲資料庫PostgreSQL 13大版本揭秘阿里資料庫SQL
- 談談“資料庫中介軟體”生態與發展資料庫
- 技術乾貨 | 解鎖Redis 時間序列資料的應用Redis
- 原生分散式資料庫與子資料庫子表中介軟體的區別分散式資料庫
- 大資料技術體系1(清華:大資料技術體系)大資料
- [乾貨分享]1000篇乾貨好文!量子技術——資訊篇
- 開源資料庫中介軟體-MyCa初探與分片實踐資料庫
- 深度乾貨 | 讓資料存得起 看得見,雲原生多模資料庫Lindorm技術解析資料庫ORM
- 乾貨:PHP與大資料開發實踐PHP大資料
- 分散式資料庫中介軟體 MyCat 搞起來!分散式資料庫
- Mycat中介軟體實現Mysql資料分片(上篇)MySql
- Mycat中介軟體實現Mysql資料分片( 下篇)MySql
- 快速入門大資料訊息中介軟體大資料
- 開源 | MySQL資料傳輸中介軟體—DTLEMySql
- 實戰!Spring Boot 整合 阿里開源中介軟體 Canal 實現資料增量同步!Spring Boot阿里
- 資料庫系列:業內主流MySQL資料中介軟體梳理資料庫MySql
- 大資料技術原理與應用——大資料概述大資料
- 乾貨 :如何看穿資料視覺化的謊言視覺化
- 乾貨 :資料分析師的完整流程與知識結構體系結構體
- 【虹科乾貨】無模式資料庫的利與弊模式資料庫
- 軟體測試之資料庫測試技術系列七資料庫
- 大資料環境下計算機軟體技術分析大資料計算機
- NAS與NAS資料同步
- 資料庫系列:大廠使用資料庫中介軟體解決什麼問題?資料庫
- 乾貨 | 影像資料增強實戰
- 乾貨:mysql索引的資料結構MySql索引資料結構
- 大資料技術原理與應用大資料
- 【Koa】koa-compress中介軟體的使用-壓縮資料
- 資料庫路由中介軟體MyCat - 原始碼篇(15)資料庫路由原始碼
- Redis中介軟體與Web中介軟體RedisWeb
- 雲棲深度乾貨 | 打造“雲邊一體化”,時序時空資料庫TSDB技術原理深度解密資料庫解密