近期须要重构一个老系统,须要从几个服务中实时同步订单的修改到重构表里。
这里就面临两个选择,java
本次选择了binlog同步的方式。搭建的binlog服务也能够用在以后新系统的缓存更新和同步ES索引上,相对于埋点这种只有一次性做用的方式,性价比较高。mysql
要实现binlog同步服务,使用较多的开源方案是canal,运行比较稳定,并且功能也很丰富。git
可是在实际部署服务的时候,遇到了一些问题:github
canal采用了client-server的模式,至少须要部署两个集群。咱们的项目都是使用私有云部署,为了稳定运行,就有额外的资源和维护开销。redis
调研同时也发现了另外一个binlog同步工具,mysql-binlog-connector-java
。spring
这是一个开源的binlog同步工具,功能很简单,就是接收binlog信息。做为一个依赖jar能够很容易在springboot中使用。sql
可是没有对binlog的内容作格式化处理,使用很不方便。固然更没有保存信息和分布式部署功能。docker
基于这些问题,咱们须要一个具备如下特性的binlog同步工具:数据库
可使用springboot加载运行,具备较好的扩展性缓存
为了知足这些条件,经过对mysql-binlog-connector-java
封装后,实现了自研的工具binlogportal。
CREATE USER binlogportal IDENTIFIED BY '123456'; GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'binlogportal'@'%'; GRANT ALL PRIVILEGES ON *.* TO 'binlogportal'@'%'; FLUSH PRIVILEGES;
<dependency> <groupId>com.insistingon.binlogportal</groupId> <artifactId>binlogportal-spring-boot-starter</artifactId> <version>1.0.5</version> </dependency>
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启动
@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); } } }
<dependency> <groupId>com.insistingon.binlogportal</groupId> <artifactId>binlogportal</artifactId> <version>1.0.5</version> </dependency>
BinlogPortalConfig
和SyncConfig
,传入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(); } } }
项目中高可用实现是基于redis的分布式锁。
每一个实例都会加载所有数据库的配置,在建立binlog链接以前,先要获取redis锁,获取锁后会定时刷新锁的过时时间。全部实例会定时从新抢锁。
同一个mysql库的binlog文件和position会保存在redis里,若是一个实例宕机。新抢到锁的实例在初始化时,会使用上个实例已保存的binlog信息继续获取。
项目源码可在Git上查看。
项目的Git地址:https://github.com/dothetrick...
以上内容属我的学习总结,若有不当之处,欢迎在评论中指正