阿里开源数据同步组件Canal

最开始听说canal是从mysql与redis双写一致性解决方案,当时并没有太在意,最近由于需要实时同步数据,如果在代码对insert/update/delete做拦截也可以实现,但对代码侵入性太大了,并且后期更改时容易有遗漏,风险太高,这时就又想到了canal,canal的好处在于对业务代码没有侵入,因为是基于监听binlog日志去进行同步数据,这个真的是太爽爽爽了。并且实时性也能做到准实时,这也是canal为什么这么流行,因为确实很多企业会用来做数据同步的方案。

阿里开源数据同步组件Canal

image

简介

阿里canal主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

基于日志增量订阅和消费的业务包括

数据库镜像
数据库实时备份
索引构建和实时维护(拆分异构索引、倒排索引等)
业务 cache 刷新
带业务逻辑的增量数据处理

当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x

MySQL主备复制原理

image

MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据
canal 工作原理
canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
canal 解析 binary log 对象(原始为 byte 流)
MySQL配置

我们提前得有一台MySQL数据库,本文基于mysql 5.7,参考安装装程:window mysql 5.7安装教程
在安装Canal之前,我们需要做2件事:
1). 修改MySQL配置支持binlog,
2). 创建canal用户

修改MySQL配置支持binlog

修改my.ini,在[mysqld]下配置以下4项:

[mysqld]
# 打开binlog
log-bin=mysql-bin
# 选择ROW(行)模式
binlog-format=ROW
# 配置MySQL replaction需要定义,不要和canal的slaveId重复
server_id=1
# 要监控的数据库名称
binlog-do-db=my-test

image

创建canal用户
1. 使用命令登录:mysql -u root -p
2. 创建用户 用户名:canal 密码:canal@123456
create user 'canal'@'%' identified by 'canal@123456';
3. 授权 *.*表示所有库
grant SELECT, REPLICATION SLAVE, REPLICATION CLIENT on *.* to 'canal'@'%' identified by 'canal@123456';
4.重启mysql
5.查看是否打开binlog模式:show variables like 'log_bin';
6.查看binlog日志文件列表:show binary logs;
7.查看当前正在写入的binlog文件:show master status;
下载安装canal

官网下载:https://github.com/alibaba/canal/releases

image

配置与mysql信息

打开配置文件conf/example/instance.properties,主要配置数据库地址和用户:

# mysql数据库地址
canal.instance.master.address=127.0.0.1:3306
# username/password
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal@123456
启动canal

转到bin目录,cmd运行startup.bat
注意需要有java环境

image

Python客户端

下载官方提供的python客户端demo
image

改造example.py,新增一下两个方法即可

解析拼接sql
def data_to_sql(data):
    db = data['db']
    table = data['table']
    sql = ''
    # insert
    if data['event_type'] == 1:
        dic_data = data['data']['after']
        insert_value = []
        for key in dic_data.keys():  
            insert_value.append(f"'{dic_data[key]}'") 
        insert_value = ','.join(insert_value)
        sql = f"insert into {db}.{table} values ({insert_value});"
        return sql
    # update
    elif data['event_type'] == 2:
        before_data = data['data']['before']
        after_data = data['data']['after']
        update_value = []
        update_condition = []
        for key in before_data.keys():
            update_condition.append(key + f"='{before_data[key]}'") 
        update_condition = ' and '.join(update_condition)

        for key in after_data.keys():
            update_value.append(key + f"='{after_data[key]}'") 
        update_value = ','.join(update_value)

        sql = f"update {db}.{table} set {update_value} \
            where {update_condition};"   
        return sql  
    # delete
    else:
        dic_data = data['data']['before']
        delete_condition = []
        for key in dic_data.keys():
            delete_condition.append(key + f"='{dic_data[key]}'") 
        delete_condition = ' and '.join(delete_condition)
        sql = f"delete from {db}.{table} where {delete_condition};"
        return sql
执行sql
def exec_sql(sql):
    db = pymysql.connect(
        host="127.0.0.1", 
        user="root", 
        password="root", 
        database="testcanal", 
        charset="utf8",
        port=3306
    )
    cursor = db.cursor()  # 使用cursor()方法获取游标
    cursor.execute(sql)  # 执行sql查询语句
    db.commit()
    cursor.close()  # 关闭游标
    db.close()  # 关闭数据库连接
    print('exec ok')
执行py文件

image

上一篇:php项目中调用python脚本使用pdf和image之间相互转换 下一篇:PHP 导出 Excel 的三种常用方法

评论

评论(0)

暂无评论