Linux寶塔面板使用Canal實(shí)現(xiàn)Mysql和Redis數(shù)據(jù)同步(圖文教程)
前言
最近有一個(gè)項(xiàng)目,頻繁讀配置文件,如果用mysql怕壓力大,一直用的Redis,用Redis雖然解決了讀的問(wèn)題,但是修改的話(huà)也要單獨(dú)寫(xiě)配置,同時(shí)在其他環(huán)境配置也不方便保存,為此找了mysql和redis同步方案Canal。
Canal 是什么
Canal 是阿里巴巴開(kāi)源的一款基于 MySQL 數(shù)據(jù)庫(kù)二進(jìn)制日志(Binlog)增量訂閱和消費(fèi)的中間件。它的名字來(lái)源于 "canal"(運(yùn)河、通道),寓意著在數(shù)據(jù)庫(kù)和應(yīng)用之間建立一條數(shù)據(jù)同步的通道。
工作原理流程: MySQL 主庫(kù) → Binlog(二進(jìn)制日志) → Canal Server(偽裝成從庫(kù)) → 解析日志 → 發(fā)送數(shù)據(jù) → 各種下游系統(tǒng)
技術(shù)原理
Canal 模擬 MySQL Slave 的交互協(xié)議
向 MySQL Master 發(fā)送 dump 請(qǐng)求
MySQL Master 收到請(qǐng)求后,開(kāi)始推送 Binlog 給 Canal
Canal 解析 Binlog 對(duì)象(原始為 byte 流)
將解析后的數(shù)據(jù)發(fā)送到消息隊(duì)列或其他下游系統(tǒng)
主要應(yīng)用場(chǎng)景
| 應(yīng)用場(chǎng)景 | 具體說(shuō)明 | 典型案例 |
|---|---|---|
| 數(shù)據(jù)庫(kù)鏡像 | 實(shí)時(shí)備份數(shù)據(jù)庫(kù)數(shù)據(jù) | 主從數(shù)據(jù)庫(kù)同步、異地多活 |
| 數(shù)據(jù)庫(kù)實(shí)時(shí)備份 | 增量數(shù)據(jù)的實(shí)時(shí)備份 | 災(zāi)備系統(tǒng)、數(shù)據(jù)恢復(fù) |
| 多級(jí)索引構(gòu)建 | 同步數(shù)據(jù)到搜索引擎 | Elasticsearch、Solr 索引更新 |
| 業(yè)務(wù)緩存刷新 | 數(shù)據(jù)庫(kù)變更后更新緩存 | Redis 緩存一致性維護(hù) |
| 價(jià)格變化監(jiān)控 | 監(jiān)控特定數(shù)據(jù)的變化 | 電商價(jià)格監(jiān)控、庫(kù)存預(yù)警 |
| 增量數(shù)據(jù)訂閱 | 為其他系統(tǒng)提供增量數(shù)據(jù) | 數(shù)據(jù)倉(cāng)庫(kù) ETL、大數(shù)據(jù)分析 |
| 異地?cái)?shù)據(jù)同步 | 跨機(jī)房、跨地域數(shù)據(jù)同步 | 全球化業(yè)務(wù)數(shù)據(jù)同步 |
Linux系統(tǒng)環(huán)境準(zhǔn)備
1.寶塔面板mysql修改配置
server-id=1 #master端的ID號(hào)【必須是唯一的】;
log_bin=mysql-bin #同步的日志路徑,一定注意這個(gè)目錄要是mysql有權(quán)限寫(xiě)入的
binlog-format=row #行級(jí),記錄每次操作后每行記錄的變化。
binlog-do-db=game_mqtt #指定庫(kù),縮小監(jiān)控的范圍。


查看是否生效:
show variables like 'log_bin';
查看正在寫(xiě)入的binlog文件狀態(tài):
show master status;

2. mysql為canal配置權(quán)限
在mysql中給canal單獨(dú)建一個(gè)用戶(hù),給全庫(kù)全表的讀,拷貝,復(fù)制的權(quán)限
賬號(hào)密碼都是:canal
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%' IDENTIFIED BY 'canal' ;

3.安裝canal服務(wù)端
安裝 canal.deployer-1.1.6.tar.gz
官網(wǎng)下載地址https://github.com/alibaba/canal/releases
備用下載地址:https://download.csdn.net/download/qq_33215204/88369947

將文件上傳服務(wù)器目錄 /data/soft/canal

解壓文件
tar -zxvf canal.deployer-1.1.6.tar.gz
4.配置canal
查看 conf/canal.properties 配置,發(fā)現(xiàn)需要暴漏三個(gè)端口
canal.admin.port = 11110
canal.port = 11111
canal.metrics.pull.port = 11112

conf/canal.properties 配置
# 指定實(shí)例,多個(gè)實(shí)例使用逗號(hào)分隔: canal.destinations = example1,example2
canal.destinations = example
修改 conf/example/instance.properties 實(shí)例配置
# 配置 slaveId 自定義,不等于 mysql 的 server Id 即可 canal.instance.mysql.slaveId=10 # 數(shù)據(jù)庫(kù)地址:自己的數(shù)據(jù)庫(kù)ip+端口 canal.instance.master.address=127.0.0.1:3306 # 數(shù)據(jù)庫(kù)用戶(hù)名和密碼 canal.instance.dbUsername=canal canal.instance.dbPassword=canal #代表數(shù)據(jù)庫(kù)的編碼方式對(duì)應(yīng)到 java 中的編碼類(lèi)型,比如 UTF-8,GBK , ISO-8859-1 canal.instance.connectionCharset = UTF-8 # 指定庫(kù)和表,這里的 .* 表示 canal.instance.master.address 下面的所有數(shù)據(jù)庫(kù) canal.instance.filter.regex=.*\\..*
配置完成之后啟動(dòng)
5.啟動(dòng)canal
cd /data/soft/canal/bin
./startup.sh


啟動(dòng)完成之后去看下有沒(méi)有日志信息。


2023-09-24 12:14:24.280 [main] INFO c.a.otter.canal.instance.spring.CanalInstanceWithSpring - start CannalInstance for 1-example 2023-09-24 12:14:24.309 [main] WARN c.a.o.canal.parse.inbound.mysql.dbsync.LogEventConvert - --> init table filter : ^.*\..*$ 2023-09-24 12:14:24.309 [main] WARN c.a.o.canal.parse.inbound.mysql.dbsync.LogEventConvert - --> init table black filter : ^mysql\.slave_.*$ 2023-09-24 12:14:24.320 [main] INFO c.a.otter.canal.instance.core.AbstractCanalInstance - start successful.... 2023-09-24 12:14:24.480 [destination = example , address = /127.0.0.1:3306 , EventParser] WARN c.a.o.c.p.inbound.mysql.rds.RdsBinlogEventParserProxy - ---> begin to find start position, it will be long time for reset or first position 2023-09-24 12:14:24.480 [destination = example , address = /127.0.0.1:3306 , EventParser] WARN c.a.o.c.p.inbound.mysql.rds.RdsBinlogEventParserProxy - prepare to find start position just show master status 2023-09-24 12:14:26.135 [destination = example , address = /127.0.0.1:3306 , EventParser] WARN c.a.o.c.p.inbound.mysql.rds.RdsBinlogEventParserProxy - ---> find start position successfully, EntryPosition[included=false,journalName=mysql-bin.000045,position=4,serverId=1,gtid=<null>,timestamp=1695526635000] cost : 1634ms , the next step is binlog dump
啟動(dòng)成功,接下來(lái)就是在springboot中創(chuàng)建客戶(hù)端監(jiān)控了。
canal客戶(hù)端監(jiān)控mysql信息,實(shí)現(xiàn)業(yè)務(wù)邏輯
1.配置pom.xml
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.1.0</version>
</dependency>

2.創(chuàng)建demo
package com.game.Service;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import java.net.InetSocketAddress;
import java.util.List;
public class CanalClient {
public static void main(String args[]) {
// 創(chuàng)建鏈接:換成自己的數(shù)據(jù)庫(kù)ip地址
CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("192.168.0.243",
11111), "example", "", "");
int batchSize = 1000;
int emptyCount = 0;
try {
connector.connect();
connector.subscribe(".*\\..*");
connector.rollback();
int totalEmptyCount = 120;
while (emptyCount < totalEmptyCount) {
Message message = connector.getWithoutAck(batchSize); // 獲取指定數(shù)量的數(shù)據(jù)
long batchId = message.getId();
int size = message.getEntries().size();
if (batchId == -1 || size == 0) {
emptyCount++;
System.out.println("empty count : " + emptyCount);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
} else {
emptyCount = 0;
printEntry(message.getEntries());
}
connector.ack(batchId); // 提交確認(rèn)
}
System.out.println("empty too many times, exit");
} finally {
connector.disconnect();
}
}
private static void printEntry(List<CanalEntry.Entry> entrys) {
for (CanalEntry.Entry entry : entrys) {
if (entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONBEGIN || entry.getEntryType() == CanalEntry.EntryType.TRANSACTIONEND) {
continue;
}
CanalEntry.RowChange rowChage = null;
try {
rowChage = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
} catch (Exception e) {
throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),
e);
}
CanalEntry.EventType eventType = rowChage.getEventType();
System.out.println(String.format("================> binlog[%s:%s] , name[%s,%s] , eventType : %s",
entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
eventType));
for (CanalEntry.RowData rowData : rowChage.getRowDatasList()) {
if (eventType == CanalEntry.EventType.DELETE) {
printColumn(rowData.getBeforeColumnsList());
} else if (eventType == CanalEntry.EventType.INSERT) {
printColumn(rowData.getAfterColumnsList());
} else {
System.out.println("-------> before");
printColumn(rowData.getBeforeColumnsList());
System.out.println("-------> after");
printColumn(rowData.getAfterColumnsList());
}
}
}
}
private static void printColumn(List<CanalEntry.Column> columns) {
for (CanalEntry.Column column : columns) {
System.out.println(column.getName() + " : " + column.getValue() + " update=" + column.getUpdated());
}
}
}
3.測(cè)試刪除一條記錄


后面的就是監(jiān)控?cái)?shù)據(jù)同步Redis,就不寫(xiě)了
到此這篇關(guān)于Linux寶塔面板使用Canal實(shí)現(xiàn)Mysql和Redis數(shù)據(jù)同步(圖文教程)的文章就介紹到這了,更多相關(guān)Linux使用Canal實(shí)現(xiàn)Mysql和Redis同步內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Redis和數(shù)據(jù)庫(kù)的一致性(Canal+MQ) 的實(shí)現(xiàn)
- 使用Canal實(shí)現(xiàn)MySQL數(shù)據(jù)同步的完整指南
- canal實(shí)現(xiàn)mysql數(shù)據(jù)同步的詳細(xì)過(guò)程
- 兩個(gè)windows服務(wù)器使用canal實(shí)現(xiàn)mysql實(shí)時(shí)同步
- Canal實(shí)現(xiàn)MYSQL實(shí)時(shí)數(shù)據(jù)同步的示例代碼
- Canal進(jìn)行MySQL到MySQL數(shù)據(jù)庫(kù)全量+增量同步踩坑指南
- 基于Docker結(jié)合Canal實(shí)現(xiàn)MySQL實(shí)時(shí)增量數(shù)據(jù)傳輸功能
- MySQL數(shù)據(jù)實(shí)時(shí)同步Redis的方案全解析
- 保證MySQL與Redis數(shù)據(jù)一致性的6種實(shí)現(xiàn)方案
- Redis與MySQL數(shù)據(jù)一致性問(wèn)題的策略模式及解決方案
- 詳解讓MySQL和Redis數(shù)據(jù)保持一致的四種策略
- Java使用Canal同步MySQL數(shù)據(jù)到Redis
相關(guān)文章
mybatis 項(xiàng)目配置文件實(shí)例詳解
這篇文章主要介紹了mybatis 項(xiàng)目配置文件實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03
SQL Server數(shù)據(jù)庫(kù)性能優(yōu)化技術(shù)
SQL Server數(shù)據(jù)庫(kù)性能優(yōu)化技術(shù)...2007-06-06
Neo4j數(shù)據(jù)備份與恢復(fù)的多種方法
在管理 Neo4j 圖數(shù)據(jù)庫(kù)時(shí),備份和恢復(fù)是確保數(shù)據(jù)安全和系統(tǒng)可靠性的關(guān)鍵操作,無(wú)論是為了災(zāi)難恢復(fù)、數(shù)據(jù)遷移,還是開(kāi)發(fā)測(cè)試環(huán)境的搭建,掌握 Neo4j 的備份和恢復(fù)方法至關(guān)重要,本文將詳細(xì)介紹 Neo4j 數(shù)據(jù)備份(導(dǎo)出)和恢復(fù)(導(dǎo)入)的多種方法,需要的朋友可以參考下2025-09-09
淺談關(guān)系型數(shù)據(jù)庫(kù)中如何進(jìn)行事務(wù)管理
這篇文章主要介紹了淺談關(guān)系型數(shù)據(jù)庫(kù)中如何進(jìn)行事務(wù)管理,事務(wù)是一組數(shù)據(jù)庫(kù)操作,它們必須全部執(zhí)行或全部回滾,這意味著如果在事務(wù)執(zhí)行期間出現(xiàn)錯(cuò)誤,所有的更改都將撤銷(xiāo),數(shù)據(jù)庫(kù)將被恢復(fù)到事務(wù)開(kāi)始之前的狀態(tài),需要的朋友可以參考下2023-07-07
SQL like子句的另一種實(shí)現(xiàn)方法(速度比like快)
這篇文章主要介紹了SQL like子句的另一種實(shí)現(xiàn)方法(速度比like快),需要的朋友可以參考下2015-09-09

