1 什么是canal
canal是用java开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件。目前,canal主要支持了MySQL的binlog解析,解析完成后才利用canal client 用来处理获得的相关数据。(数据库同步需要阿里的otter中间件,基于canal)
2 canal使用场景
(1)阿里otter(阿里用于进行异地数据库之间的同步框架)中间件的一部分,这是原始场景
(2)更新缓存:如果有大量的请求发送到mysql的话,mysql查询速度慢,QPS上不去,光查mysql可能会瘫痪,那就可以在前面加个缓存,这个缓存有2个主要的问题。一是缓存没有怎么办,二是数据不一致怎么办。对于第一个问题查缓存没有就差mysql,mysql再往缓存中写一份。对于第二个问题,如果数据库修改了,那就采用异步的方式进行修改,启动一个canal服务,监控mysql,只要一有变化就同步缓存,这样mysql和缓存就能达到最终的一致性。
(3)抓取业务数据新增变化表,用于制作拉链表:做拉链表是需要有增加时间和修改时间的,需要数据今天新增和变化的数据,如果时间不全就没办法知道哪些是修改的。可以通过canal把变化的抽到自己的表里,以后数据就从这个表出。
(4)取业务表的新增变化数据,用于制作实时统计
3 canal工作原理
首先了解一下mysql主备复制原理:
(1)master主库将改变记录,发送到二进制文件(binary log)中
(2)slave从库向mysql Master发送dump协议,将master主库的binary log events拷贝到它的中继日志(relay log)
(3)slave从库读取并重做中继日志中的事件,将改变的数据同步到自己的数据库
canal的工作原理:把自己伪装成slave,从master复制数据。读取binlog是需要master授权的,因为binlog是加密的,授权分用户名密码才能读。master授权后不知道读他的binlog的是从机还是canal,他的所有传输协议都符合从机的标准,所以master一直以为是从机读的。
4 mysql的binlog
4.1 二进制日志
mysql的二进制日志记录了所有的DDL和DML(除了数据查询语句),以事件的形式进行记录,包含语句执行消耗的时间,mysql的二进制日志是事务安全型的。
开启二进制日志大概会有1%的性能损坏。二进制日志有2个主要的使用场景:①mysql的主备复制②数据恢复,通过使用mysqlbinlog工具来恢复数据(用这个做恢复是备选方案,主方案还是定期快照,定期执行脚本导数据,其实就是把当前所有数据导成insert,这个量少)
二进制日志包括2类文件:①二进制日志索引文件(后缀为.index)用于记录所有的二进制文件②二进制日志文件(后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句)
4.2 开启binlog
修改mysql的配置文件my.cnf。
#
vim /etc/my.cnfgG
在[mysqld] 区块 添加
log-bin=mysql-bin
mysql-bin表示binlog日志的前缀,以后生成的的日志文件就是 mysql-bin.000001 的文件后面的数字按顺序生成。当mysql重启或到达单个文件大小的阈值时,新生一个文件,按顺序编号。
4.3 binlog分类
binlog的格式有三种:STATEMENT,MIXED,ROW对比如下
格式描述优点
STATEMENT | 语句级别,记录每一次执行写操作的语句,相对于ROW模式节省了空间,但是可能产生数据不一致如update tt set create_date=now(),由于执行时间不同产生饿得数据就不同 | 节省空间 | 可能造成数据不一致 |
ROW | 行级,记录每次操作后每行记录的变化。假如一个update的sql执行结果是1万行statement只存一条,如果是row的话会把这个1000行的结果存这。 | 持数据的绝对一致性。因为不管sql是什么,引用了什么函数,他只记录执行后的效果 | 占用较大空间 |
MIXED | 是对statement的升级,如当函数中包含 UUID() 时,包含 AUTO_INCREMENT 字段的表被更新时,执行 INSERT DELAYED 语句时,用 UDF 时,会按照 ROW的方式进行处理 | 节省空间,同时兼顾了一定的一致性 | 还有些极个别情况依旧会造成不一致,另外statement和mixed对于需要对binlog的监控的情况都不方便 |
4.4 binlog格式选择
如果只考虑主从复制的话可以用mixed,一般情况下使用statement,遇到几种特殊情况使用row,同步的话有SQL就行,因为手里有数据,前提是有数据才能执行这个SQL。在大数据场景下我们抽取数据是用于统计分析,分析的数据,如果用statement抽了SQL手里也没数据,不知道执行修改哪些,因为没有数据,所以没办法分析,所以适合用row,清清楚楚的表明了每一行是什么样。
4.5 修改配置文件
修改my.cnf文件,在[mysqld]模块下添加如下内容
server-id= 1 log-bin=mysql-bin binlog_format=row binlog-do-db=bigdata
binlog-do-db用于指定库,缩小监控的范围,server-id不能和mysql集群的其他节点重复
4.6 重启mysql
#
service mysqld restart Redirecting to /bin/systemctl restart mysqld.service
到数据目录下查询是否生成binlog文件,这里我把数据目录自定义为了/data/mysql/
# cd /data/mysql/
# ll
total 188500
-rw-r----- 1 mysql mysql 56 Jul 1 2020 auto.cnf
-rw------- 1 mysql mysql 1676 Jul 1 2020 ca-key.pem
-rw-r--r-- 1 mysql mysql 1112 Jul 1 2020 ca.pem
-rw-r--r-- 1 mysql mysql 1112 Jul 1 2020 client-cert.pem
-rw------- 1 mysql mysql 1676 Jul 1 2020 client-key.pem
drwxr-x--- 2 mysql mysql 4096 Jul 1 2020 dataxweb
-rw-r----- 1 mysql mysql 526 Jan 14 11:03 ib_buffer_pool
-rw-r----- 1 mysql mysql 79691776 Jan 14 11:04 ibdata1
-rw-r----- 1 mysql mysql 50331648 Jan 14 11:04 ib_logfile0
-rw-r----- 1 mysql mysql 50331648 Aug 5 06:20 ib_logfile1
-rw-r----- 1 mysql mysql 12582912 Jan 14 11:04 ibtmp1
drwxr-x--- 2 mysql mysql 116 Jul 1 2020 iot
drwxr-x--- 2 mysql mysql 4096 Jul 1 2020 mysql
-rw-r----- 1 mysql mysql 154 Jan 14 11:03 mysql-bin.000001
-rw-r----- 1 mysql mysql 19 Jan 14 11:03 mysql-bin.index
srwxrwxrwx 1 mysql mysql 0 Jan 14 11:03 mysql.sock
-rw------- 1 mysql mysql 6 Jan 14 11:03 mysql.sock.lock
drwxr-x--- 2 mysql mysql 8192 Jul 1 2020 performance_schema
-rw------- 1 mysql mysql 1680 Jul 1 2020 private_key.pem
-rw-r--r-- 1 mysql mysql 452 Jul 1 2020 public_key.pem
-rw-r--r-- 1 mysql mysql 1112 Jul 1 2020 server-cert.pem
-rw------- 1 mysql mysql 1676 Jul 1 2020 server-key.pem
drwxr-x--- 2 mysql mysql 8192 Jul 1 2020 sys
可以发现,这二进制日志索引文件和日志文件生成了。只要重启mysql,mysql-bin后面的序号就会往上涨,他的切分规则就是重启或者到一个大小的阈值,就会切一个
mysql-bin.000001
mysql-bin.index
5 安装canal
5.1 下载地址
https://github.com/alibaba/canal/releases
5.2 mysql为canal配置权限
在mysql中给canal单独建一个用户,给全库全表的读,拷贝,复制的权限
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%' IDENTIFIED BY 'canal' ;
报错:ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
原因是因为密码设置的过于简单会报错,MySQL有密码设置的规范,具体是与validate_password_policy的值有关,下图表明该值规则
查看MySQL完整的初始密码规则,登陆后执行以下命令
mysql> SHOW VARIABLES LIKE 'validate_password%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| validate_password_check_user_name | OFF |
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+--------------------------------------+--------+
密码的长度是由validate_password_length决定的,但是可以通过以下命令修改
set global validate_password_length=4;
validate_password_policy决定密码的验证策略,默认等级为MEDIUM(中等),可通过以下命令修改为LOW(低)
set global validate_password_policy=0;
重新执行
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%' IDENTIFIED BY 'canal' ;
5.3 解压及配置
$ tar -zxvf canal.deployer-1.1.4.tar.gz
配置说明:canal server的conf下有几个配置文件
conf/
├── canal_local.properties
├── canal.properties
├── example
│ ├── h2.mv.db
│ ├── instance.properties
│ └── meta.dat
├── logback.xml
├── metrics
│ └── Canal_instances_tmpl.json
└── spring
├── base-instance.xml
├── default-instance.xml
├── file-instance.xml
├── group-instance.xml
├── memory-instance.xml
└── tsdb
├── h2-tsdb.xml
├── mysql-tsdb.xml
├── sql
│ └── create_table.sql
└── sql-map
├── sqlmap-config.xml
├── sqlmap_history.xml
└── sqlmap_snapshot.xml
canal.properties的common属性前四个配置项:
canal.id= 1 #canal的编号