canal数据库同步
canal源码(需要根据自己配置修改参数)
准备 0:binlog文件
0.1:binlog文件包含两种类型:
- 索引文件(文件名后缀为.index)用于记录哪些日志文件正在被使用
- 日志文件(文件名后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句)语句事件。
- 索引文件大小:我们可以通过 max_binlog_size 参数设置binlog文件的大小。Binlog最大值,最大和默认值是1GB,该设置并不能严格控制Binlog的大小,尤其是Binlog比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性,不可能做切换日志的动作,只能将该事务的所有SQL都记录进当前日志,直到事务结束
- 索引文件删除:binlog的删除可以手工删除或自动删除。通过设置 expire_logs_days 实现自动删除
- 手动删除需登录mysql后执行如下命令:
mysql> reset master; //删除master的binlog,即手动删除所有的binlog日志
mysql> reset slave; //删除slave的中继日志
mysql> purge master logs before '2019-07-07 17:20:00'; //删除指定日期以前的日志索引中binlog日志文件
mysql> purge master logs to 'binlog.000003'; //删除指定日志文件的日志索引中binlog日志文件
0.2:binlog一共有三种格式:
格式 |
定义 |
优点 |
缺点 |
statement |
记录的是修改SQL语句 |
日志文件小,节约IO,提高性能 |
准确性差,对一些系统函数不能准确复制或不能复制,如now()、uuid()、limit(由于mysql是自选索引,有可能master同salve选择的索引不同,导致更新的内容也不同)等 在某些情况下会导致master-slave中的数据不一致(如sleep()函数, last_insert_id(),以及user-defined functions(udf)等会出现问题) |
row |
记录的是每行实际数据的变更 |
准确性强,能准确复制数据的变更 |
日志文件大,较大的网络IO和磁盘IO |
mixed |
statement和row模式的混合 |
准确性强,文件大小适中 |
当binlog format 设置为mixed时,普通复制不会有问题,但是级联复制在特殊情况下会binlog丢失。 |
mysql8.0中默认使用row模式,默认开启,不需要手动设置。
一些查看binlog命令(mysql8.0不用设置也可以)
登录mysql 查看binlog是否开启:show variables like 'log_bin';
修改binlog格式:SET GLOBAL BINLOG_FORMAT = 'STATEMENT';
查看写入的binlog文件:show master status;
查看记录的内容:show binlog events in 'binlogs.000003';/*日志文件名*/
开始1:canal介绍
- 名称:canal [kə’næl]
- 译意: 水道/管道/沟渠
- 语言: 纯java开发
- 定位: 基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了mysql
- 关键词: mysql binlog parser / real-time / queue&topic
1.1:mysql主备工作原理
- master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
- slave将master的binary log events拷贝到它的中继日志(relay log);
- slave重做中继日志中的事件,将改变反映它自己的数据。
1.2:canal工作原理
- canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
- mysql master收到dump请求,开始推送binary log给slave(也就是canal)
- canal解析binary log对象(原始为byte流)
1.3:安装canal前准备
- 对于自建 MySQL , 需要先开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式,my.cnf 中配置如下
[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
ps:msyql8.0默认已开启,可跳过。
- 授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant
开启一个有远程权限账号(ps:可用root)
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;
1.4canal安装教程
- 下载 canal, 访问 release 页面 , 选择需要的包下载, 如以 1.1.5 版本为例
https://github.com/alibaba/canal/releases/download/canal-1.1.5-alpha-2/canal.deployer-1.1.5-SNAPSHOT.tar.gz
- 解压缩
mkdir /tmp/canal # 可自己指定目录
tar zxvf canal.deployer-$version.tar.gz -C /tmp/canal
- 配置修改(ps:根据需要修改)
vim conf/example/instance.properties
#ps:此文件可默认,连接时打开端口11111即可。
vim conf/canal.properties
sh bin/startup.sh
# 启动
sh bin/stop.sh
# 关闭
# 查看 logs日志 canal无报错即可
# 查看 server 日志
vim logs/canal/canal.log
# 查看 instance 的日志
vim logs/example/example.log
#(ps:注意内存太少可能启动失败,我得至少0.5G内存才启动成功)
2:注意事项
- 服务器端口号注意开启11111端口号(ps:默认,可修改)
ps:canal get数据超时时间修改
3:java代码
commons-dbutils
commons-dbutils
1.7
com.alibaba.otter
canal.client
1.1.4
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 com.google.protobuf.InvalidProtocolBufferException;
import com.wisdom.canal.config.CommonUtil;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.net.InetSocketAddress;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* @date: 2020/9/2 10:31
* @author: LJP
* @description: canal客户端类
*/
@Component
public class CanalClient {
Logger logger = LoggerFactory.getLogger(CanalClient.class);
/*sql队列*/
private Queue
/*启动master数据库监听*/
@SpringBootApplication
public class CanalApplication implements CommandLineRunner {
@Resource
private CanalClient canalClient;
public static void main(String[] args) {
SpringApplication.run(CanalApplication.class, args);
}
@Override
public void run(String... strings) throws Exception {
/*启动canal客户端监听*/
canalClient.run();
}
}