最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux寶塔面板使用Canal實(shí)現(xiàn)Mysql和Redis數(shù)據(jù)同步(圖文教程)

 更新時(shí)間:2025年12月20日 15:49:07   作者:劉登輝  
本文詳細(xì)描述了一個(gè)項(xiàng)目如何通過(guò)Canal解決從MySQL讀取配置文件的壓力問(wèn)題,包括Linux環(huán)境設(shè)置、MySQL配置、Canal服務(wù)端安裝與配置,以及在SpringBoot中接入Canal進(jìn)行MySQL信息的實(shí)時(shí)監(jiān)控

前言

最近有一個(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("================&gt; 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("-------&gt; before");
                    printColumn(rowData.getBeforeColumnsList());
                    System.out.println("-------&gt; 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)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

旬邑县| 微博| 峡江县| 进贤县| 镇宁| 寿阳县| 宁陵县| 江山市| 滦南县| 澄迈县| 正蓝旗| 岑溪市| 枣强县| 永宁县| 周宁县| 濮阳市| 樟树市| 北海市| 福泉市| 丰顺县| 德保县| 霍州市| 广灵县| 嘉鱼县| 桑日县| 台北县| 嘉鱼县| 开远市| 新邵县| 乳山市| 岢岚县| 青冈县| 雷波县| 佳木斯市| 德昌县| 邛崃市| 阿拉善右旗| 海晏县| 修武县| 吴旗县| 大同县|