应用binlog的起因
近期须要重构一个老零碎,须要从几个服务中实时同步订单的批改到重构表里。
这里就面临两个抉择,
- 在每个服务的mysql操作前埋点,发送批改信息到队列或服务上。这种计划须要批改多个服务的代码并且测试对原零碎的影响,有额定开发和测试老本。
- 同步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@Componentpublic 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>
- 依赖后实现配置类
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(); } }}
2.分布式部署实现
我的项目中高可用实现是基于redis的分布式锁。
每个实例都会加载全副数据库的配置,在创立binlog连贯之前,先要获取redis锁,获取锁后会定时刷新锁的过期工夫。所有实例会定时从新抢锁。
同一个mysql库的binlog文件和position会保留在redis里,如果一个实例宕机。新抢到锁的实例在初始化时,会应用上个实例已保留的binlog信息持续获取。
我的项目源码可在Git上查看。
我的项目的Git地址:https://github.com/dothetrick...
以上内容属集体学习总结,如有不当之处,欢送在评论中斧正