轻量级mysql binlog同步工具包binlogportal

使用binlog的原因

近期需要重构一个老系统,需要从几个服务中实时同步订单的修改到重构表里。
这里就面临两个选择,

  1. 在每个服务的mysql操作前埋点,发送修改信息到队列或服务上。这种方案需要修改多个服务的代码并且测试对原系统的影响,有额外开发和测试成本。
  2. 同步mysql的binlog,根据表的insert和update更新新表。但是需要维护一个binlog同步的服务

本次选择了binlog同步的方式。搭建的binlog服务也可以用在之后新系统的缓存更新和同步ES索引上,相对于埋点这种只有一次性作用的方式,性价比较高。

工具调研:canal和mysql-binlog-connector-java

1.canal

要实现binlog同步服务,使用较多的开源方案是canal,运行比较稳定,而且功能也很丰富。

但是在实际部署服务的时候,遇到了一些问题:

  • canal采用了client-server的模式,至少需要部署两个集群。我们的项目都是使用私有云部署,为了稳定运行,就有额外的资源和维护开销。
    • 后来发现canal server可以投递信息到kafka。但是我们的消息队列是自研的,只能尝试去改源码。
  • canal的server是完整独立的包,无法直接用springboot嵌套。而我们的基础组件都依赖于springboot,比如监控,配置中心等。
  • canal的HA部署使用的是zookeeper,很可惜我们并没有可用的zookeper集群,也没有资源重新部署一个。
  • 单机部署的时候,已经处理的binlog postion是保存在文件里面的,我们用的私有云docker,重启后全丢失。

2.mysql-binlog-connector-java

调研同时也发现了另一个binlog同步工具,mysql-binlog-connector-java

这是一个开源的binlog同步工具,功能很简单,就是接收binlog信息。作为一个依赖jar可以很容易在springboot中使用。

但是没有对binlog的内容做格式化处理,使用很不方便。当然更没有保存信息和分布式部署功能。

自研工具包binlogportal

基于这些问题,我们需要一个具有以下特性的binlog同步工具:

  • 可以使用springboot加载运行,具有较好的扩展性
    • 说白了就是作为一个jar包,开放出接口可以自定义处理binlog信息的方式
  • 可以使用redis实现binlog position的保存和分布式部署

为了满足这些条件,通过对mysql-binlog-connector-java封装后,实现了自研的工具binlogportal。

  • 提供了binlogportal-spring-boot-starter包,可使用spring boot快速部署
  • 使用redis保存binlog position信息,重启后可从上次position位置开始
  • 当前支持insert和update的结构化
  • 提供默认的http事件处理器。可通过实现IEventHandler接口,自定义事件处理器
  • 使用redis作为分布式协调器,可多机部署实现高可用

使用说明

Mysql配置

  • Mysql需要开启binlog并设置为row模式
  • 同步binlog使用的mysql账号,需要添加REPLICATION权限,示例如下:
CREATE USER binlogportal IDENTIFIED BY '123456';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'binlogportal'@'%';
GRANT ALL PRIVILEGES ON *.* TO 'binlogportal'@'%';
FLUSH PRIVILEGES;

通过spring boot构建项目

  • 直接依赖binlogportal-spring-boot-starter
<dependency>
  <groupId>com.insistingon.binlogportal</groupId>
  <artifactId>binlogportal-spring-boot-starter</artifactId>
  <version>1.0.5</version>
</dependency>
  • 通过spring boot的application.yml配置启动器
binlogportal:
  enable: true # 是否启用autoconfig
  distributed-enable: true # 是否启用分布式部署
  distributed-redis: # distributed-enable为true时,要提供一个redis作为分布式协调器
    host: 127.0.0.1
    port: 6379
    auth:
  position-redis: # 保存binlog position的redis,必须配置
    host: 127.0.0.1
    port: 6379
    auth:
  db-config: # 数据库配置,可以有多个,key自定义即可
    d1:
      host: 0.0.0.0
      port: 3306
      user-name: binlogportal
      password: 123456
      handler-list: [logEventHandler] # 该数据库使用的事件处理器,名称为spring的bean name
  http-handler: # 启用自带的http事件处理器,可发送请求
    url-list: [http://127.0.0.1:8988/testit] # 要发送的url列表,http参数为统一的格式
    result-callback: httpCallBack # 配置自定义的结果处理器,需要实现IHttpCallback接口,值为bean name
  • Starter启动
    • spring boot autoconfig启动成功后,会把BinlogPortalStarter的实例注入到IOC中
    • 项目中通过注入的方式获取binlogPortalStarter使用
    • binlogPortalStarter.start()会为每个mysql库创建一个线程处理binlog
    • 下面是使用CommandLineRunner启动starter的一个例子
@Slf4j
@Component
public class BinlogSync implements CommandLineRunner {
    @Resource
    BinlogPortalStarter binlogPortalStarter;

    public void run(String... args) throws Exception {
        try {
            binlogPortalStarter.start();
        } catch (BinlogPortalException e) {
            log.error(e.getMessage(), e);
        }
    }
}

非spring boot项目

  • 非spring boot项目,可以使用基础包
<dependency>
  <groupId>com.insistingon.binlogportal</groupId>
  <artifactId>binlogportal</artifactId>
  <version>1.0.5</version>
</dependency>
  • 依赖后实现配置类BinlogPortalConfigSyncConfig,传入Starter中运行即可
public class TestClass{
 public static void main(String[] args) {
        SyncConfig syncConfig = new SyncConfig();
        syncConfig.setHost("0.0.0.0");
        syncConfig.setPort(3306);
        syncConfig.setUserName("binlogportal");
        syncConfig.setPassword("123456");

        BinlogPortalConfig binlogPortalConfig = new BinlogPortalConfig();
        binlogPortalConfig.addSyncConfig(syncConfig);

        RedisConfig redisConfig = new RedisConfig("127.0.0.1", 6379);
        RedisPositionHandler redisPositionHandler = new RedisPositionHandler(redisConfig);
        binlogPortalConfig.setPositionHandler(redisPositionHandler);

        binlogPortalConfig.setDistributedHandler(new RedisDistributedHandler(redisConfig));

        BinlogPortalStarter binlogPortalStarter = new BinlogPortalStarter();
        binlogPortalStarter.setBinlogPortalConfig(binlogPortalConfig);
        try {
            binlogPortalStarter.start();
        } catch (BinlogPortalException e) {
            e.printStackTrace();
        }
    }
}

2.分布式部署实现

项目中高可用实现是基于redis的分布式锁。

每个实例都会加载全部数据库的配置,在创建binlog连接之前,先要获取redis锁,获取锁后会定时刷新锁的过期时间。所有实例会定时重新抢锁。

同一个mysql库的binlog文件和position会保存在redis里,如果一个实例宕机。新抢到锁的实例在初始化时,会使用上个实例已保存的binlog信息继续获取。

项目源码可在Git上查看。
项目的Git地址:https://github.com/dothetrick/binlogportal

以上内容属个人学习总结,如有不当之处,欢迎在评论中指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335