canal怎样监听多个数据库

本文介绍了Canal如何配置以监听多个数据库,并对接更多业务系统。重点讲解了canal.properties中的配置项,如canal.destinations及其实例配置,同时探讨了Instance的生成和启动流程。

前言

  1. 前一些天已经发了一个版本,但只监听一个业务系统的数据库。今天领导找我谈,说能不能多监听几个数据库,对接更多的业务系统。下面我们就围绕这个主题进行学习展开
  2. 稍微跟了一下源码,最终发现在canal.destinations配置中配置多个实例(用逗号分隔),然后在对应配置名目录下增加对应Instance.properties
    在这里插入图片描述

canal整体架构分析

在这里插入图片描述

  1. 看上面的架构图,感觉每监听一个数据库就对应一个Instance

  2. 通过分析下方的生成Instance过程分析总结:
    2.1 根据canal.properties初始化instance全局配置
    (1)关于实例全局配置项:canal.instance.global.mode、canal.instance.global.spring.xml
    2.2 读取canal.destinations配置,如果有多个实例用逗号分隔,遍历初始化instance配置
    (1)如果想覆盖全局配置,则配置指定实例的配置:canal.instance.<实例名>.mode、canal.instance.<实例名>.spring.xml
    2.3 通过SpringCanalInstanceGenerator#generate生成实例

  3. 下方Instance启动分析总结:
    3.1 一个instance对应一个spring容器,spring配置文件为:spring/file-instance.xml
    3.2 instance启动入口为CanalInstanceWithSpring,启动实例的各个组件:metaManager、alarmHandler、eventStore、eventSink、eventParser(各个组件运行分析待分析)

生成Instance过程分析

  1. 初始化全局instance配置(入口:CanalController#initGlobalConfig)

    private InstanceConfig initGlobalConfig(Properties properties) {
    	InstanceConfig globalConfig = new InstanceConfig();
    	// 读取canal.instance.global.mode配置 -> spring
    	String modeStr = getProperty(properties, CanalConstants.getInstanceModeKey(CanalConstants.GLOBAL_NAME));
    	if (StringUtils.isNotEmpty(modeStr)) {
            globalConfig.setMode(InstanceMode.valueOf(StringUtils.upperCase(modeStr)));
        }
        // 读取canal.instance.global.spring.xml配置 -> classpath:spring/file-instance.xml
        String springXml = getProperty(properties, CanalConstants.getInstancSpringXmlKey(CanalConstants.GLOBAL_NAME));
        if (StringUtils.isNotEmpty(springXml)) {
            globalConfig.setSpringXml(springXml);
        }
    }
    
  2. 在启动server时,会初始化instance配置(入口:CanalController#initInstanceConfig)

    private void initInstanceConfig(Properties properties) {
    	// 从canal.properties中读取canal.destinations配置
    	String destinationStr = getProperty(properties, CanalConstants.CANAL_DESTINATIONS);
    	// 多个实例instance用逗号分隔
    	String[] destinations = StringUtils.split(destinationStr, CanalConstants.CANAL_DESTINATION_SPLIT);
    	for (String destination : destinations) {
              InstanceConfig config = parseInstanceConfig(properties, destination);
              InstanceConfig oldConfig = instanceConfigs.put(destination, config);
              if (oldConfig != null) {
                  logger.warn("destination:{} old config:{} has replace by new config:{}", destination, oldConfig, config);
              }
         }
    }
    

    1.1 解析实例配置:CanalController#parseInstanceConfig

    private InstanceConfig parseInstanceConfig(Properties properties, String destination) {
    	InstanceConfig config = new InstanceConfig(globalInstanceConfig);
    	// 实例配置mode的key:canal.instance.express(destination名).mode
    	String modeStr = getProperty(properties, CanalConstants.getInstanceModeKey(destination));
    	if (StringUtils.isNotEmpty(modeStr)) { // 如果存在,则覆盖全局实例配置
    		config.setMode(InstanceMode.valueOf(StringUtils.upperCase(modeStr)));
    	}
    	// 读取实例的xml文件:canal.instance.express.spring.xml
    	String springXml = getProperty(properties, CanalConstants.getInstancSpringXmlKey(destination));
    	if (StringUtils.isNotEmpty(springXml)) {
            config.setSpringXml(springXml);
        }
        return config;
    }
    
  3. 根据配置生成instance入口:CanalController#initGlobalConfig

    private InstanceConfig initGlobalConfig(Properties properties) {
    	instanceGenerator = destination -> {
    		InstanceConfig config = instanceConfigs.get(destination);
    		if (config.getMode().isSpring()) {
                SpringCanalInstanceGenerator instanceGenerator = new SpringCanalInstanceGenerator();
                instanceGenerator.setSpringXml(config.getSpringXml());
                return instanceGenerator.generate(destination);
            } 
    	}
    }
    

Instance启动分析

  1. 生成Instance入口:SpringCanalInstanceGenerator#generate
    1.1 观察下面代码发现,一个instance对应一个spring容器
    1.2 instance对应的实现类为CanalInstanceWithSpring
    public CanalInstance generate(String destination) {
    	synchronized (CanalEventParser.class) {
    		// 加载classpath:spring/file-instance.xml的spring容器
    		this.beanFactory = getBeanFactory(springXml);
    		 String beanName = destination;
    		 // 在file-instance.xml没有对应实例名的bean,只有默认的instance的beanName
    		 if (!beanFactory.containsBean(beanName)) {
                    beanName = defaultName;
              }
              return (CanalInstance) beanFactory.getBean(beanName);
    	}
    }
    
  2. 启动instance入口:CanalInstanceWithSpring#start
    2.1 启动各个组件
    public void start() {
        super.start();
        if (!metaManager.isStart()) {
            metaManager.start();
        }
    
        if (!alarmHandler.isStart()) {
            alarmHandler.start();
        }
    
        if (!eventStore.isStart()) {
            eventStore.start();
        }
    
        if (!eventSink.isStart()) {
            eventSink.start();
        }
    
        if (!eventParser.isStart()) {
            beforeStartEventParser(eventParser);
            eventParser.start();
            afterStartEventParser(eventParser);
        }
        logger.info("start successful....");
    }
    
<think> 我们正在处理一个关于Canal配置的问题。用户询问如何配置Canal监听特定的数据库和表。 根据引用[1]和引用[2],我们知道Canal是基于MySQL的binlog进行增量数据同步的。因此,配置Canal监听特定的数据库和表,通常是在Canal的配置文件中进行设置。 具体步骤: 1. 修改Canal的配置文件(通常是instance.properties),在其中指定需要监听数据库和表。 2. 配置过滤规则,通过设置`canal.instance.filter.regex`和`canal.instance.filter.black.regex`来实现。 例如,如果我们只想监听`testdb`数据库中的`user`表,我们可以这样配置: canal.instance.filter.regex = testdb\\.user 注意:在正则表达式中,点(.)需要转义,所以写成`\\.`。 另外,引用[3]提到Flink CDC也有类似功能,但用户问的是Canal,所以我们专注于Canal的配置。 因此,回答如下: </think> ### Canal监听指定数据库和表的配置方法 要配置Canal监听特定数据库和表,需修改Canal实例的配置文件(通常是`instance.properties`),关键步骤如下: 1. **配置数据库白名单** 在配置文件中添加过滤规则,使用正则表达式指定目标数据库和表: ```properties # 监听testdb数据库的所有表 canal.instance.filter.regex = testdb\\..* # 仅监听testdb.user表(精确匹配) canal.instance.filter.regex = testdb\\.user ``` **注意**: - 点号`.`需转义为`\\.`(例:`testdb\\.user`) - 支持正则表达式(例:`testdb\\.user_.*`匹配所有`user_`前缀的表)[^1] 2. **重启Canal实例** 修改后需重启实例使配置生效: ```bash ./bin/stop.sh ./bin/start.sh ``` 3. **验证配置** 检查日志文件确认监听范围: ```log 2023-01-01 12:00:00 INFO - Subscribe filter: testdb\\.user ``` ### 配置示例 ```properties # 基础配置 canal.instance.master.address=127.0.0.1:3306 canal.instance.dbUsername=canal canal.instance.dbPassword=canal # 指定监听testdb数据库的user表 canal.instance.filter.regex=testdb\\.user # 忽略其他库(可选) canal.instance.filter.black.regex=.*\\..* ``` ### 注意事项 1. **MySQL权限要求** 账号需具备`REPLICATION SLAVE`和`REPLICATION CLIENT`权限[^2] 2. **Binlog格式** 确保MySQL开启binlog且格式为`ROW`模式: ```sql SHOW VARIABLES LIKE 'binlog_format'; -- 需返回ROW ``` 3. **多表配置** 监听多个表用逗号分隔: ```properties canal.instance.filter.regex=testdb\\.user,testdb\\.order ``` > 配置生效后,Canal仅同步指定表的binlog事件,其他数据变更将被忽略。如需动态调整监听表,可通过Canal开放的[管理接口](https://github.com/alibaba/canal/wiki/AdminGuide)操作[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值