近期須要重構一個老系統,須要從幾個服務中實時同步訂單的修改到重構表裏。
這裏就面臨兩個選擇,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...
以上內容屬我的學習總結,若有不當之處,歡迎在評論中指正