Mac系统,Docker的MySQL + 本地 Canal

MySQL 是 Docker 容器安装的8.0.29,这里选择 Canal 1.1.6版本。

先查看当前 MySQL 是否开启了 binlog 模式

这里使用 docker 客户端,直接就能进入到容器内,使用终端就得需要 image Id

复制代码
# 进入到MySQL容器的工作目录下
docker exec -it 3a0532e74496 bash

# 登录MySQL 
mysql -uroot -proot 

# 开启binlog模式 
SHOW VARIABLES LIKE '%log_bin%';
  • 如果不确定,可以对配置文件进行配置

通过我的摸索基本可以确定,MySQL 的核心配置文件为/etc/my.cnf,就算是没有配置任何的配置文件,它也不会是空的

查看该文件夹,可以看到!includedir /etc/mysql/conf.d/,这代表配置还会去这个文件夹下去找

复制代码
sh-4.4# cat my.cnf
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

# Remove leading # to revert to previous value for default_authentication_plugin,
# this will increase compatibility with older clients. For background, see:
# https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_authentication_plugin
# default-authentication-plugin=mysql_native_password
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql

pid-file=/var/run/mysqld/mysqld.pid
[client]
socket=/var/run/mysqld/mysqld.sock

!includedir /etc/mysql/conf.d/

conf.d****目录的作用

该目录用于存放 MySQL 的‌分片配置文件 ‌,通常以 .cnf 结尾(如 mysql.cnfmysqld.cnf)。这些文件会被主配置文件(如 /etc/mysql/mysql.conf.d/mysqld.cnf)通过 !includedir /etc/mysql/conf.d/ 指令动态加载‌。

进入/etc/mysql/conf.d/文件夹,看到自己在本机建立,然后映射到 docker 容器的文件

所以如果害怕没有害怕log_bin就可以在这建立一个xxx.cnf文件,并且进行配置,图中的my.cnf就是我后来添加的

复制代码
[mysqld]
log-bin=mysql-bin  # 开启 binlog,`mysql-bin` 为日志前缀(可自定义路径,如 `log-bin=/var/lib/mysql/mysql-bin`)
binlog-format=ROW  # 推荐 ROW 模式(保证主从复制一致性,减少误操作风险)
server-id=1       # 主从复制必需,需确保每台 MySQL 服务器 ID

【总结】mysql 的配置文件

  • 核心是 /etc/my.cnf
  • 其他会被加载的配置文件,/etc/mysql/conf.d/*.cnf

【创建账号并授权】

  • 创建 canal 用户,允许远程连接;
  • 授予 SELECT、REPLICATION SLAVE、REPLICATION CLIENT、SUPER 权限,使 Canal 能读取 binlog 并监控数据库变更;
  • 修改认证方式(针对 MySQL 8.0+ 兼容性);
  • 刷新权限,确保配置立即生效;

在刚才mysql容器内,依次执行下面的命令

复制代码
# 创建 canal 用户并设置密码
create user canal@'%' IDENTIFIED by 'canal';
# canal@'%':创建一个用户名为 canal,允许从 任意主机(% 表示所有IP) 连接 MySQL
# IDENTIFIED BY 'canal':设置该用户的密码为 canal

#  授予 canal 用户必要的权限
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT,SUPER ON *.* TO 'canal'@'%';
# SELECT:允许查询数据(Canal 需要读取 binlog,因此需要查询权限)
# REPLICATION SLAVE:允许作为从库读取主库的 binlog(Canal 模拟 MySQL 从库拉取变更日志)
# REPLICATION CLIENT:允许查看主库/从库状态(Canal 需要检查复制状态)
# SUPER:允许执行某些管理命令(如 SET GLOBAL,某些 MySQL 版本 Canal 需要此权限)
# ON *.*:对所有数据库(*.*)生效。

# 修改 canal 用户的认证方式(MySQL 8.0+ 需要)
ALTER USER 'canal'@'%' IDENTIFIED WITH mysql_native_password BY 'canal';
# mysql_native_password:使用 旧版密码认证(MySQL 8.0+ 默认使用 caching_sha2_password,但部分客户端(如 Canal)可能不支持,需切换回旧方式)
# BY 'canal':保持密码不变。

# 刷新权限,使更改立即生效
FLUSH PRIVILEGES;
MacOS 安装

这里 MySQL 使用 Docker 安装,但是 Canal 没有 苹果芯片架构的。

所以使用官网进行下载,这里是 1.1.6。

下载地址

下载完毕后,直接在本地打开到bin目录下, 可以看到startup.sh以后就要使用该脚本进行启动。但是这个文件是有问题的,它默认支持的是Java 8

所以如果本地是Java >= 17的,那么就会报出参数错误,可以丢给AI让它帮忙删除,人眼很难找到。

这里给一份修改后的:

复制代码
#!/bin/bash 

current_path=`pwd`
case "`uname`" in
    Linux)
		bin_abs_path=$(readlink -f $(dirname $0))
		;;
	*)
		bin_abs_path=`cd $(dirname $0); pwd`
		;;
esac
base=${bin_abs_path}/..
canal_conf=$base/conf/canal.properties
canal_local_conf=$base/conf/canal_local.properties
logback_configurationFile=$base/conf/logback.xml
export LANG=en_US.UTF-8
export BASE=$base

if [ -f $base/bin/canal.pid ] ; then
	echo "found canal.pid , Please run stop.sh first ,then startup.sh" 2>&2
    exit 1
fi

if [ ! -d $base/logs/canal ] ; then 
	mkdir -p $base/logs/canal
fi

## set java path
if [ -z "$JAVA" ] ; then
  JAVA=$(which java)
fi

ALIBABA_JAVA="/usr/alibaba/java/bin/java"
TAOBAO_JAVA="/opt/taobao/java/bin/java"
if [ -z "$JAVA" ]; then
  if [ -f $ALIBABA_JAVA ] ; then
  	JAVA=$ALIBABA_JAVA
  elif [ -f $TAOBAO_JAVA ] ; then
  	JAVA=$TAOBAO_JAVA
  else
  	echo "Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH." 2>&2
    exit 1
  fi
fi

case "$#" 
in
0 ) 
	;;
1 )	
	var=$*
	if [ "$var" = "local" ]; then
		canal_conf=$canal_local_conf
	else
		if [ -f $var ] ; then 
			canal_conf=$var
		else
			echo "THE PARAMETER IS NOT CORRECT.PLEASE CHECK AGAIN."
			exit
		fi
	fi;;
2 )	
	var=$1
	if [ "$var" = "local" ]; then
		canal_conf=$canal_local_conf
	else
		if [ -f $var ] ; then
			canal_conf=$var
		else 
			if [ "$1" = "debug" ]; then
				DEBUG_PORT=$2
				DEBUG_SUSPEND="n"
				JAVA_DEBUG_OPT="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND"
			fi
		fi
     fi;;
* )
	echo "THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN."
	exit;;
esac

JavaVersion=`$JAVA -version 2>&1 |awk 'NR==1{ gsub(/"/,""); print $3 }' | awk  -F '.' '{print $1}'`
str=`file -L $JAVA | grep 64-bit`
JAVA_OPTS="$JAVA_OPTS -Xss256k -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$base/logs"

if [ $JavaVersion -ge 11 ] ; then
  #JAVA_OPTS="$JAVA_OPTS -Xlog:gc*:$base_log/gc.log:time "
  JAVA_OPTS="$JAVA_OPTS"
else
  #JAVA_OPTS="$JAVA_OPTS -Xloggc:$base/logs/canal/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime"
  JAVA_OPTS="$JAVA_OPTS -XX:+UseFastAccessorMethods -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution"
fi

if [ -n "$str" ]; then
	# JAVA_OPTS="-server -Xms2048m -Xmx3072m -Xmn1024m -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC $JAVA_OPTS"
  # For G1
  JAVA_OPTS="-server -Xms2g -Xmx3g -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent $JAVA_OPTS"
else
	JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m $JAVA_OPTS"
fi

JAVA_OPTS=" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
CANAL_OPTS="-DappName=otter-canal -Dlogback.configurationFile=$logback_configurationFile -Dcanal.conf=$canal_conf"

if [ -e $canal_conf -a -e $logback_configurationFile ]
then 
	
	for i in $base/lib/*;
		do CLASSPATH=$i:"$CLASSPATH";
	done
 	CLASSPATH="$base/conf:$CLASSPATH";
 	
 	echo "cd to $bin_abs_path for workaround relative path"
  	cd $bin_abs_path
 	
	echo LOG CONFIGURATION : $logback_configurationFile
	echo canal conf : $canal_conf 
	echo CLASSPATH :$CLASSPATH
	$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.deployer.CanalLauncher 1>>$base/logs/canal/canal_stdout.log 2>&1 &
	echo $! > $base/bin/canal.pid 
	
	echo "cd to $current_path for continue"
  	cd $current_path
else 
	echo "canal conf("$canal_conf") OR log configration file($logback_configurationFile) is not exist,please create then first!"
fi

除此之外,canal.properties文件也是很重要的,在/canal/conf下。

我们除此使用的时候,很可能是监听 MySQL ,那么就需要配置canal.instance,该文件中有两行,是因为它默认canal.properties为主配置文件,然后进行创建其他实例,在/conf/实例名/实例名.properties中配置与对应的客户端进行通信(MQ、Kafka)。

但是对于小白,可能已经蒙了,所以附一份修改后的canal.properties,不需要关心其他实例了

需要修改属性,其他可以复制

复制代码
canal.destinations = mysql-master # docker 容器中 MySQL 实例名
canal.instance.master.address = 127.0.0.1:3307 # 更改ip和端口
canal.instance.defaultDatabaseName = tingshu_album # 指定数据库
# MySQL 连接用户名和密码 这两个,在上面mysql 设置已经创建了该用户
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal

# Canal Server 基本配置文件
# Canal Server 端口配置
canal.port = 11111
canal.metrics.pull.port = 11112

# Canal Server 模式配置 (tcp, kafka, rocketMQ, rabbitMQ)
canal.serverMode = tcp

# Canal destinations 配置,指定单个实例
canal.destinations = mysql-master

# Canal 实例配置目录
canal.conf.dir = ../conf
# Canal 日志目录
canal.log.dir = ../logs

# Canal 实例全局配置
# MySQL 主库地址
canal.instance.master.address = 127.0.0.1:3307
# MySQL 从库地址(可选)
canal.instance.standby.address = 

# MySQL 连接用户名和密码
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal

# 字符集配置
canal.instance.connectionCharset = UTF-8
canal.instance.defaultDatabaseName = tingshu_album

# binlog 解析配置
canal.instance.binlog.format = ROW
canal.instance.binlog.image = FULL

# position 记录配置
canal.instance.master.journal.name = 
canal.instance.master.position = 
canal.instance.master.timestamp = 
canal.instance.master.gtid = 

# 时间戳数据库配置
canal.instance.tsdb.enable = true
canal.instance.tsdb.dir = ${canal.file.data.dir:../data}/${canal.instance.destination:}
canal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;

# GTID 配置
canal.instance.gtidon = false

# 表过滤配置 - 只监听指定表的变更
# 格式:数据库名.表名,支持正则表达式
canal.instance.filter.regex = tingshu_album.album_info

# 黑名单配置(不监听的表)
canal.instance.filter.black.regex = 

# 心跳检查配置
canal.instance.detecting.enable = false
canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
canal.instance.detecting.interval.time = 3
canal.instance.detecting.retry.threshold = 3
canal.instance.detecting.heartbeatHaEnable = false

# 内存存储配置
canal.instance.memory.buffer.size = 16384
canal.instance.memory.buffer.memunit = 1024
canal.instance.memory.raw.mode = true

# binlog 解析并行度配置
canal.instance.parser.parallel = true
canal.instance.parser.parallelThreadSize = 60
canal.instance.parser.parallelBufferSize = 256

# binlog 接收缓冲区配置
canal.instance.network.receiveBufferSize = 16384
canal.instance.network.sendBufferSize = 16384
canal.instance.network.soTimeout = 30

# 批量获取配置
canal.instance.get.ddl.isolation = false
canal.instance.parser.isTableError = true

# 数据库连接池配置
canal.instance.connectionCharset = UTF-8
canal.instance.enableDruid = false


# 监控配置
canal.admin.manager = 
canal.admin.port = 11110
canal.admin.user = admin
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
canal.admin.register.auto = true
canal.admin.register.cluster = 
canal.admin.register.name = 

# 实例自动扫描配置 - 禁用自动扫描,只监听指定实例
canal.auto.scan = false
canal.auto.scan.interval = 5

# HA 配置
canal.zkServers = 
canal.zookeeper.flush.period = 1000
canal.withoutNetty = false

# TCP 配置
canal.tcp.no.delay = true
canal.tcp.keep.alive = true
canal.tcp.recv.buffer.size = 16384
canal.tcp.send.buffer.size = 16384

# 文件数据存储配置
canal.file.data.dir = ../data
canal.file.flush.period = 1000

# 实例配置重载
canal.instance.global.mode = spring
canal.instance.global.lazy = false
canal.instance.global.manager.address = 
canal.instance.global.spring.xml = classpath:spring/file-instance.xml

最后修改 SpringBoot中yaml文件

java 复制代码
# canal
canal:
  destination: mysql-master # 要监听的实例名称,这里是 mysql 实例名称
  server: 127.0.0.1:11111

【注意】本教程只适合,是监听 MySQL 数据变化,通过 JAVA API 接口监控MySQL数据变化的代码编写。

不是引入客户端,因为发现,我们从头到尾都没有在项目的pom.xml中引入 canal 客户端依赖。

通过这样的方式监控到数据变化,后续做删除缓存操作的。

java 复制代码
@Component
@CanalTable("album_info") // 监听变更表
@Slf4j
public class CdcEntityHandler implements EntryHandler<CdcEntity> {
    /**
     * 监听的表中有数据新增的时候,会回调该方法
     */
    @Override
    public void insert(CdcEntity cdcEntity) {
        log.info("Canal客户端监听到了album_info表中有数据的新增的id:{}", cdcEntity.getId());
    }

    /**
     * 监听的表中有数据变更的时候,会回调该方法
     * @param before 修改之前的老数据
     * @param after 修改后的新数据
     */
    @Override
    public void update(CdcEntity before, CdcEntity after) {
        log.info("Canal客户端监听到了album_info表中有数据的修改,修改之前的id:{}", before.getId());
        log.info("Canal客户端监听到了album_info表中有数据的修改,修改之后的id:{}", after.getId());

        // TODO 删除缓存
    }

    /**
     * 监听的表中有数据删除的时候,会回调该方法
     * @param cdcEntity 删除的对象
     */
    @Override
    public void delete(CdcEntity cdcEntity) {
        log.info("Canal客户端监听到了album_info表中有数据的删除,删除的数据的id:{}", cdcEntity.getId());
    }
}
相关推荐
开开心心loky1 小时前
[iOS] GCD - 线程与队列
macos·ios·objective-c·cocoa
小白银子1 小时前
零基础从头教学Linux(Day 60)
linux·数据库·mysql·oracle
憋问我,我也不会2 小时前
MYSQL 命令
数据库·mysql
计算机小手3 小时前
使用 llama.cpp 在本地高效运行大语言模型,支持 Docker 一键启动,兼容CPU与GPU
人工智能·经验分享·docker·语言模型·开源软件
无泡汽水3 小时前
MySQL入门练习50题
数据库·mysql
冷冷的菜哥3 小时前
21款m1 max升级到macOS 14——Sonoma
macos·苹果·sonoma·macos系统升级
laocaibulao3 小时前
mac电脑composer命令如何指定PHP版本
macos·php·composer
00后程序员张3 小时前
iOS 上架费用全解析 开发者账号、App 审核、工具使用与开心上架(Appuploader)免 Mac 成本优化指南
android·macos·ios·小程序·uni-app·cocoa·iphone
岚天start3 小时前
KubeSphere在线安装单节点K8S集群
docker·容器·kubernetes·k8s·kubesphere·kubekey
栗子~~3 小时前
shell-基于k8s/docker管理容器、监控模型训练所消耗的最大CPU与最大内存脚本
docker·容器·kubernetes