PHP基于Canal实现数据库字段监控并同步方案

流氓凡 技术分享 2021-05-15 357 0

需求

现有两个程序A、B,将A程序中的用户表中的余额字段同步到B任意表中的余额字段。

我们常见实现方案在A程序的余额变动从直接请求B程序的一个接口进行数据发送,那么在来个C、D、E的集群形式呢?

接下来,我们要借助阿里巴巴开发的canal工具,监听bin文件来进行转发同步。

准备工作

Linux服务器并安装Canal

MySQL5.6 、5.7

PHP 7.2

JAVA SDK1.8

以上工作我这边使用服务器直接搭建一个宝塔面板进行环境一键部署

Canal的强大之处

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

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

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

  • 数据库镜像

  • 数据库实时备份

  • 索引构建和实时维护(拆分异构索引、倒排索引等)

  • 业务 cache 刷新

  • 带业务逻辑的增量数据处理

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

工作原理

MySQL主备复制原理


  • 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 流)

安装并启动Canal

参考:https://github.com/alibaba/canal/wiki/QuickStart

这里面文档写的非常详细,直接按步骤安装即可,需要注意的是1.1.5版本就要用到java sdk1.8 低于此版本会启动失败

安装并启动Canal客户端

这里我使用的是canal-php,参考:https://github.com/xingwenge/canal-php

当然官方支持java、go、python等客户端,可根据自身业务需要进行配置。

需要注意的是服务器安全组端口开放。

建立Canal连接并进行业务处理

try {
    $client = CanalConnectorFactory::createClient(CanalClient::TYPE_SOCKET_CLUE);
    # $client = CanalConnectorFactory::createClient(CanalClient::TYPE_SWOOLE);

    $client->connect("127.0.0.1", 11111);
    $client->checkValid();
    $client->subscribe("1001", "example", ".*\\..*");
    # $client->subscribe("1001", "example", "db_name.tb_name"); # 设置过滤

    while (true) {
        $message = $client->get(100);
        if ($entries = $message->getEntries()) {
            foreach ($entries as $entry) {
                Fmt::println($entry); // 这里可查到每次的数据表变化返回的数据,自行根据自己业务处理
            }
        }
        sleep(1);
    }

    $client->disConnect();
} catch (\Exception $e) {
    echo $e->getMessage(), PHP_EOL;
}

关于这里Fmt返回的打印值有个eventType可以进行判断

类型说明
eventType1新增(insert)
eventType2更新(update)
eventType3删除(delete)

其他建议

所有要操作的数据库最好要在同一服务器下或者同一个内网下,否则将毫无意义!



评论