python3数据库同步_python进行mysql数据实时同步的正确姿势(使用canal)

简介

最近项目组有一个需求,需要让异地的两个数据库中的某几个配置表实时同步,本想自己写个服务利用binlog2sql工具解析出sql语句进行同步,考虑到需要实时监控binlog并解析,且binlog2sql解析较慢,决定利用canal进行部署。

首先介绍一下canal,它是阿里的一个mysql增量订阅&消费工具,附github主页:https://github.com/alibaba/canal

canal的框架比较简单,分为服务端和客户端,以一种比较易懂的方式解释就是:

服务端可以理解为一个mysql服务端(即高可用架构中的从节点),为了让canal服务端生效,我们需要进行一些简单的配置,让canal服务端向真正的mysql服务端发送获取binlog请求,并且将binlog解析以后存在本地的数据结构中。这样在canal服务端运行以后,我们可以按照官方的规范去连接服务端获取数据;

客户端可以理解为某种意义上的数据库客户端,通过一些简单的编码,我们可以获取存在canal服务端的已被解析的binlog数据(增量数据),获取数据以后,即可进行定制化的处理

部署

服务端

在实际配置时,有一些信息我觉得可以备注一下:

## mysql serverId

# 目前最新的服务端版本已不需要配置serverId参数

canal.instance.mysql.slaveId = 1234

#position info,需要改成自己的数据库信息

canal.instance.master.address = 127.0.0.1:3306

canal.instance.master.journal.name =

canal.instance.master.position =

canal.instance.master.timestamp =

#canal.instance.standby.address =

#canal.instance.standby.journal.name =

#canal.instance.standby.position =

#canal.instance.standby.timestamp =

#username/password,需要改成自己的数据库信息

canal.instance.dbUsername = canal

canal.instance.dbPassword = canal

canal.instance.defaultDatabaseName =

canal.instance.connectionCharset = UTF-8

# table regex

# binlog解析的过滤规则,采用正则表达式

canal.instance.filter.regex = .\*\\\\..\*

客户端

在按照官方说明配置完成后,测试主页上的demo时发现了一个小问题,首先来看默认demo(自己加了一些注释方便理解):

import time

from canal.client import Client

from canal.protocol import EntryProtocol_pb2

from canal.protocol import CanalProtocol_pb2

# 建立与canal服务端的连接

client = Client()

client.connect(host='127.0.0.1', port=11111) # canal服务端部署的主机IP与端口

client.check_valid(username=b'', password=b'') # 自行填写配置的数据库账户密码

# destination是canal服务端的服务名称, filter即获取数据的过滤规则,采用正则表达式

client.subscribe(client_id=b'1001', destination=b'example', filter=b'.*\\..*')

while True:

message = client.get(100)

# entries是每个循环周期内获取到数据集

entries = message['entries']

for entry in entries:

entry_type = entry.entryType

if entry_type in [EntryProtocol_pb2.EntryType.TRANSACTIONBEGIN, EntryProtocol_pb2.EntryType.TRANSACTIONEND]:

continue

row_change = EntryProtocol_pb2.RowChange()

row_change.MergeFromString(entry.storeValue)

event_type = row_change.eventType

header = entry.header

# 数据库名

database = header.schemaName

# 表名

table = header.tableName

event_type = header.eventType

# row是binlog解析出来的行变化记录,一般有三种格式,对应增删改

for row in row_change.rowDatas:

format_data = dict()

# 根据增删改的其中一种情况进行数据处理

if event_type == EntryProtocol_pb2.EventType.DELETE:

format_data['before'] = dict()

for column in row.beforeColumns:

#format_data = {

# column.name: column.value

#}

#此处注释为原demo,有误,下面是正确写法

format_data['before'][column.name] = column.value

elif event_type == EntryProtocol_pb2.EventType.INSERT:

format_data['after'] = dict()

for column in row.afterColumns:

#format_data = {

# column.name: column.value

#}

#此处注释为原demo,有误,下面是正确写法

format_data['after'][column.name] = column.value

else:

# format_data['before'] = format_data['after'] = dict() 采用下面的写法应该更好

format_data['before'] = dict()

format_data['after'] = dict()

for column in row.beforeColumns:

format_data['before'][column.name] = column.value

for column in row.afterColumns:

format_data['after'][column.name] = column.value

# data即最后获取的数据,包含库名,表明,事务类型,改动数据

data = dict(

db=database,

table=table,

event_type=event_type,

data=format_data,

)

print(data)

time.sleep(1)

client.disconnect()

使用数据

这个demo间隔一秒获取一次服务端的增量数据,并作相应的解析,代码中我已经做了简单的注释帮助理解,最后获取的data就是某个sql语句改动某一行的完整记录,通常有三种情况:

# 设库test中有表test1,分别有id(int)和name(varchar)字段

# insert操作:insert into test.test1 values (1,'a')

# 此时data中应是如下情况

data = {'db':'test', 'table':'test1', 'event_type':1, 'data':{'after':{'id':'1', 'name':'a'}}}

# update操作:update test.test1 set id=2, name='b' where id=1

# 此时的data

data = {'db':'test', 'table':'test1', 'event_type':2, 'data':{'before':{'id':'1', 'name':'a'}, 'after':{'id':'2', 'name':'b'}}}

# delete操作:delete from test.test1 where id=2

# 此时的data

data = {'db':'test', 'table':'test1', 'event_type':3, 'data':{'before':{'id':'2', 'name':'b'}}}

如上,可根据生成的data做进一步处理,有较大的自由度,而此处我需要的是直接插入到另一台主机上的同样的库表中,因此我需要将data再解析为sql语句:

def data_to_sql(data: dict) -> str:

db = data['db']

table = data['db']

sql = ''

# insert

if data['event_type'] == 1:

dic_data = data['data']['after']

insert_value = ""

for key in dic_data.keys():

insert_value = insert_value + f"'{dic_data[key]}'" + ','

insert_value = insert_value[:-1]

sql = f"insert into{db}.{table}values ({insert_value});"

return sql

# update

elif data['event_type'] == 2:

before_data = data['before']

after_data = data['after']

update_value = ""

update_condition = ""

for key in before_data.keys():

update_condition = update_condition + f"'{before_data[key]}' and "

update_condition = update_condition[:-5]

for key in after_data.keys():

update_value = update_value + key + f"='{after_data[key]}',"

update_value = update_value[:-1]

sql = f"update{db}.{table}set{update_value}where{update_condition};"

# delete

else:

dic_data = data['data']['before']

delete_condition = ""

for key in dic_data.keys():

delete_condition = delete_condition + f"'{dic_data[key]}' and "

delete_condition = delete_condition[:-5]

sql = f"delete from{db}.{table}where{delete_condition};"

return sql

注意点:

1、由于我使用的是内网pypi不是最新,无法获取canal-python,将主页上源码下载后放在python环境目录下的site-package目录下即可;

2、在使用canal-python时需要安装一些依赖包,可能存在指定版本不存在的情况,在requirements.txt文件中删除包后面指定的版本号即可;

3、通过上面的代码可以看出无论原始数据是int还是varchar,解析出来的数据都是字符串类型;

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现MySQL数据实时同步到Elasticsearch可以使用Canal工具。 Canal是阿里巴巴开源的一套基于数据库增量日志解析的数据同步和逆向解析工具,可以实时获取数据库的变更日志,然后将这些变更日志解析成数据并发送到指定的目的地。在实现MySQL数据实时同步到Elasticsearch中,可以使用Canal来实现以下步骤: 1. 安装配置Canal:首先,需要下载并安装Canal,并配置Canal的参数,如MySQL的地址、端口、用户名、密码等。 2. 创建Canal实例:根据实际需求,可以创建一个或多个Canal实例来监控和同步MySQL的变更日志。 3. 配置Elasticsearch目的地:配置Canal将变更日志发送到Elasticsearch作为同步的目的地。 4. 启动Canal实例:通过命令行或脚本启动Canal实例,让Canal开始监控MySQL的变更日志。 5. 解析并同步数据:Canal实时监控MySQL的变更日志,一旦有变更,就会解析并发送到Elasticsearch。在Elasticsearch中,可以根据业务需求进行相应的处理,比如数据转换、数据筛选、数据拆分等,并将处理后的数据存储到Elasticsearch中。 通过以上步骤,就可以实现MySQL数据实时同步到Elasticsearch中。Canal工具可以很好地解析MySQL的增量日志并将数据发送到Elasticsearch,保证数据实时性和一致性。同时,Canal还支持分布式部署和高可用性,可以满足大规模数据同步的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值