canal结构介绍和改造成可自行管理的服务

目录

背景

server的逻辑概览

需要解决的问题:

问题1

问题2

为解决问题需要做的:

解决问题1:canal发版固定信息处理

解决问题2:meta.dat备份与重用

方案风险点和短板


背景

server的逻辑概览

canal server启动逻辑

com.alibaba.otter.canal.deployer.CanalLauncher#main

图1、server启动概览和状态配置变更逻辑

对于server状态变更的操作(图1右上角部分),是admin向server发出的:

com.alibaba.otter.canal.admin.handler.SessionHandler#messageReceived

对于server配置的变更(图1左上角部分),是server轮询admin的:

com.alibaba.otter.canal.deployer.CanalLauncher#canalLaunch

canal server监听消息逻辑

初始化instance的各个组件:

com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded#start(java.lang.String)

图2、instance启动和事件获取生产

获取event:

com.alibaba.otter.canal.parse.inbound.mysql.dbsync.DirectLogFetcher#fetch

event解析(如果想要加业务日志,就可以在这里追溯):

com.alibaba.otter.canal.parse.inbound.mysql.dbsync.LogEventConvert#parse

event的竖式结构转换:

com.alibaba.otter.canal.connector.core.util.MessageUtil#convert

(整个项目中,对文件落盘,文件读取,数据库位点解析,信息组装和发送,全部都采用了监听者模式;互相隔离,能够做到功能解耦,对功能的增删改比较方便。

但是排查问题起来比较难,同一个接收方可能接受来自多个生产者的消息,一般是消费,但也可以堆积不消费。)

通过admin的配置,可以调整server的部分行为,

但有如下问题

需要解决的问题:

0、基于一个前提:目前canal已经接入了公司框架,可以使用框架内组件;讨论基于现在的发版逻辑

问题1

canal server重新发版,canal admin的条目会变更,需要重复配置,增加维护成本;

问题2

canal重新发版,不会保留meta.dat(记录上一次读取binlog的位置),导致漏掉变更信息。而且server管理着部分对外数据交互,不利于由外部(admin)对server的功能进行干预

为解决问题需要做的:

解决问题1:canal发版固定信息处理

0、canal当做不同的服务来开启

不能一个服务多实例,否则资源分配难均衡

不同服务在初始化的时候通过读取“公司发版中心配置的环境变量”来决定启动哪个服务

要用同一份代码,方便功能升级;

  • 在server与admin交互部分进行操作

1、定义几个canal 服务名字

canal-common

canal-shop

canal-product

2、发版的时候制定参数

例如需要启动common服务,则在发版中心配置 common 作为当前启动的环境变量,其余服务的启动类似;

则同一份代码可以根据配置的不同而启动不同的服务,并以此注册到canal admin中。

在admin中显示的名字是由canal.properties中

canal.admin.register.name

控制的,修改代码时可按照上述关键词搜索。

因为启动后,在canal admin中配置的admin相关值都不会再生效,因此需要在服务第一次启动的时候就制定好admin的相关参数

修改相应代码使之生效

同时admin需要做一定工作,要仅根据name来判断(而不是和ip联合判断)

目前admin对server的干预流程如下:

图3、admin对server的识别与干预概览

图3红框部分,则是需要改动的版块。

解决问题2:meta.dat备份与重用

0、meta.dat数据

meta.dat数据是记录着某个instance所配置的数据库连接信息,以及上一次记录变更的binlog文件与位点,为下一次读取mysql的变更设置了起点(offset)

目前canal server写死了clientId=1001,因此不会区分请求来源client,消费位点只会和destination(可以理解为配置到同一个instance的配置)有关,所有的消费者都是跟着destination走,即便是新进来的消费者,也不会从位置0开始读取。

存储json对应的java类:

com.alibaba.otter.canal.meta.FileMixedMetaManager.FileMetaInstanceData

监听和存入内存:

com.alibaba.otter.canal.server.embedded.CanalServerWithEmbedded#subscribe

com.alibaba.otter.canal.meta.MemoryMetaManager#subscribe

图4、meta.dat文件写入流程

图4中的embedded server可以理解为图2的组件,由server中不同的instance(worker)来刷写destinations。默认落盘速度是每1秒一次。

图5、meta.dat读取流程

读取的位点信息使用在:

com.alibaba.otter.canal.parse.inbound.mysql.MysqlEventParser#findStartPositionInternal

为数据库读取提供一个起始位点,如果没有位点信息,则从目前mysql到的位置读取。如果啥都没有,从连接建立的前60s读取。这个机制主要是防止删除meta.dat等读取不到存储的起始位点的情况

文件内容格式示例:

{"clientDatas":[{"clientIdentity":{"clientId":1001,"destination":"6shop2","filter":""},"cursor":{"identity":{"slaveId":-1,"sourceAddress":{"address":"shop.db.rj-info.com","port":3306}},"postion":{"gtid":"","included":false,"journalN
ame":"mysql-bin.000151","position":497978414,"serverId":10,"timestamp":1667375100000}}}],"destination":"6shop2"}

内容不多,

  • 最终的存储和读取都由java.io.File#File(java.lang.String)一个步骤控制,我们可以采用mysql来做为远端存储,来解决重新发版,本地文件丢失的问题。

1、mysql存储meta.dat表设计

CREATE TABLE `canal_manager`.`Untitled`  (
  `id` int(0) NOT NULL COMMENT 'id',
  `service_name` varchar(100) NOT NULL DEFAULT '' COMMENT '服务名称,用于检索',
  `meta_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '存储的binlog位点数据',
  `write_time` datetime(255) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '写入时间',
  `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '生成时间',
  `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE INDEX `idx_service_name`(`service_name`) USING BTREE
) ENGINE = InnoDB COMMENT = 'canal服务,binlog位点记录表';
  • id存在完全是因为公司不让去掉,实际无任何业务场景需要用到id

2、存储读取策略

  • 对meta管理器部分进行操作

(1)修改存储

com.alibaba.otter.canal.meta.FileMixedMetaManager#flushDataToFile(java.lang.String)

admin开启接口,将server中原本写到文件的逻辑,改为调用admin开启的接口,将数据发送到admin,并由admin去管理数据是存储文件或到数据库。

(2)修改读取

com.alibaba.otter.canal.meta.FileMixedMetaManager#loadClientIdentity

com.alibaba.otter.canal.meta.FileMixedMetaManager#getDataFile

admin开启接口,原本读取文件逻辑为server读取meta.dat文件数据。修改为调用admin接口获取上次保存的原本属于meta.dat数据

(3)定时存的代码:

com/alibaba/otter/canal/meta/FileMixedMetaManager.java:89

(可搜索“// 启动定时工作任务”)

此项目为辅助查找和检查逻辑缺漏。实际上上述(1)(2)已经可以涵盖meta.dat的操作

其他说明:

阻塞读取:从远端mysql获取位点数据和初始化

读取失败需要走初始化策略。相当于丢失数据(没法处理,因为没有存起来,用文件也一样有这个问题);

异步不阻塞,但顺序写入:写入远端mysql,刷新速度可为1s,因为无task时不会调用接口,因此无需担心高TPS。

方案风险点和短板

1、上述destinations(binlog信息的存储)、cursors(binlog位点的存储)、parser(binlog信息解析)等等具有多种策略,使用监听者模式,方法多且冗杂,在出现问题后排查需要花费较长时间。这个需要慢慢熟悉

2、暂时没有涉及到性能优化,可以留到下一版做。前提是需要了解解析binlog的原理。目前可通过设置parallel、parallelThreadSize、batchsize等参数来调整,加快解析时间或者传输批量更大;

3、具有一个中心,admin,于是有下述问题

(1)初次启动服务,需要在admin上对应服务进行配置,否则报错;

(2)需要单独在server开后门的开关接口来控制启动停止机器,防止admin宕机导致对server失去控制;

(3)admin管理除监听和解析binlog外所有server与外部的数据交换,如meta.dat数据的处理。admin宕机或失去连接,会导致数据写入失败,这个需要做额外异常处理否则报错。(可以一直使用缓存数据直到admin恢复)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值