(3)Canal高可用集群

1.前言

在最近项目开中,为了减少前台搜索对数据库访问压力,入库的物料都需要同步一份数据到ES,让前台搜索直接访问ES,不直接访问数据库获取数据。一开始做法是代码串行先保存到数据库,再同步到ES。但是会有一个坑,如果两者其一保存数据不成功,就会导致数据库跟ES数据不一致,而且这种方式是对站点代码是有侵入式的。搜索相关资料发现阿里的canal这个增量数据订阅&消费的中间件可以无侵入式地有效解决该问题,canal伪造从库拉取mysql库每次修改binary log对象解析后,再通过MQ同步数据到ES。同时考虑系统健壮性,稳定性,所以把canal部署成高可用集群。

2. canal架构

我特定查阅官网资料几遍,总体归纳canal架构如上几种(如有错误,请各位看官指正,谢谢)。而这次功能重构,鉴于目前公司现有技术栈,决定采用架构图③的架构进行重构。

2.1HA机制设计

canal的ha(双机集群)分为两部分,canal server和canal client分别有对应的ha实现:
●canal server:为了减少对mysql dump的请求,不同server上的实例(instance)要求同一时间只能有一个处于running,其他的处于standby状态。
●canal client:为了保证有序性,一份实例(instance)同一时间只能由一个canal client进行get/ack/rollback操作,否则客户端接收无法保证有序。
整个HA机制的控制主要是依赖了zookeeper的几个特性,watcher和EPHEMERAL节点(和session生命周期绑定),后续我会继续记录zookeeper学习过程。
Canal Server HA架构原理:

流程步骤:
2.1.1canal server要启动某个canal instance时都先向zookeeper进行一次尝试启动判断(实现:创建EPHEMERAL节点,谁创建成功就允许谁启动)。
2.1.2创建zookeeper节点成功后,对应的canal server就启动对应的canal instance,没有创建成功的canal instance就会处于standby状态。
2.1.3一旦zookeeper发现canal server A创建的节点消失后,立即通知其他的canal server再次进行步骤1的操作,重新选出一个canal server启动instance。
2.1.4canal client每次进行connect时,会首先向zookeeper询问当前是谁启动了canal instance,然后和其建立链接,一旦链接不可用,会重新尝试connect。
注:canal client的方式和canal server方式类似,也是利用zookeeper的抢占EPHEMERAL节点的方式进行控制。

3.前期准备

3.1安装zookeeper

可以参考我这篇“Zookeeper在linux环境中搭建集群”文章或者百度教程安装。集群部署如下:

服务名称IP/域名端口
zookeeper(slave)192.168.18.2002181
zookeeper(master)  192.168.18.2012181
zookeeper(slave) 192.168.18.2022181

3.2安装mysql

可以参考我这篇”MySQL进阶篇在linux环境下安装” 文章或者百度教程安装。MySQL我只部署单台:

服务名称IP/域名端口
mysql 8.135.110.120(阿里云)3306

用户名:canal,密码:qwer1234

3.3安装mq(因为我公司是使用RabbitMQ,所以安装的是RabbitMQ)

可以参考我这篇“RabbitMQ在Docker上安装”文章或者百度教程安装。RabbitMQ我只部署单台:

服务名称IP/域名端口
rabbitmq8.135.110.120(阿里云)5672

管理后台登录账号:admin,密码:qwer1234
再新建一个队列用作演示:
Virtual hosts:/
交换器(Exchanges):canal.direct.test
路由key(Routing key):canal.routingkey.test
队列(Queues):canal.queue.test

3.4安装canal.server

可以参考我这篇“Canal管理后台在linux上部署”(这篇文章采用就是架构图④的架构)或者百度教程安装。集群部署如下:

服务名称IP/域名端口
canal.server01192.168.18.20011110
canal.server02192.168.18.20111110
canal.server03192.168.18.20211110

两台canal.server实例我重新拷贝一份用作供应商报价业务,具体操作如下:

cp -r /home/deng/canal/canal.deployer/conf/example /home/deng/canal/canal.deployer/conf/quote_example

实例名称:quote_example

3.5其他依赖

JDK版本:java version "11.0.17"

4.启动canal集群

部署完canal.server两个服务后,集群想要生效,还需要同时修改两台服务的配置重新启动才可以,具体操作如下:
●编辑vi conf/ canal.properties文件
因为canal.server集群需要zookeeper,所以在“common argument”标题下找到canal.zkServers选项修改为zookeeper集群地址;然后把canal.serverMode选项修改为rabbitMQ类型:

canal.zkServers = 192.168.18.200:2181,192.168.18.201:2181,192.168.18.202:2181
canal.serverMode = rabbitMQ

同时canal需要MQ进行同步数据,所以在“RabbitMQ” 标题下找到rabbitmq配置进行修改:

rabbitmq.host = 8.135.110.120
rabbitmq.virtual.host = /
rabbitmq.exchange = canal.direct.test
rabbitmq.username = admin
rabbitmq.password = qwer1234
rabbitmq.deliveryMode =

HA模式是依赖于instance name进行管理,必须都选择default-instance.xml配置。在“destinations”标题下找到canal.instance.global.spring.xml选项进行启用(其他两个选项注释):

canal.instance.global.spring.xml = classpath:spring/default-instance.xml

注:canal是允许配置多个实例(instance),假设每个canal.server服务都有相同的两个实例(在conf目录下分别建两个实例文件夹:example1和example2,同时把默认实例example文件夹里的instance.properties文件拷贝一份过去),修改两个实例canal.properties配置就能使其生效,在“destinations”标题下找到canal.destinations选项修改如下:

canal.destinations = example1, example2

●编辑vi conf/example/instance.properties文件(如果是多实例,则每个实例目录下该文件都要修改配置,现在以canal.server01服务为例)

# mysql集群配置中的serverId概念,需要保证和当前mysql集群中id唯一
canal.instance.mysql.slaveId=129
# mysql数据库连接地址和端口
canal.instance.master.address=8.135.110.120:3306
# mysql数据库用户名和密码
canal.instance.dbUsername=canal
canal.instance.dbPassword=qwer1234
# mq配置(如果是没用到MQ,则修改为实例名称即可)
canal.mq.topic= example1

Or

# mq配置(如果是用到MQ,则修改为mq路由key)
canal.mq.topic=canal.routingkey.test

●启动canal.server服务

cd /home/deng/canal/canal.deployer
sh bin/startup.sh

●登录mysql增删改一条数据(创建一个供应商报价supplier_quote临时表)

INSERT ebs_material.supplier_quote (PN,Brand,StockQty) VALUES ('LM3585DT','TI',10000);
UPDATE ebs_material.supplier_quote SET Brand='TS1' WHERE Id=1;

在RabbitMQ管理后台队列上会看到这两条语句待消费消息:

下面再来验证下canal集群是否成功。
●验证canal集群是否成功
首先把canal.server01停止运行(也可以停止canal.server02运行,随便一个都可以):

sh bin/stop.sh

查看日志:

从上述截图可以看到201虚拟机canal.server02服务已经关闭了。现在在数据库再插入一条报价数据:

INSERT ebs_material.supplier_quote (PN,Brand,StockQty) VALUES ('BAV999','TI',10000);

再查看下RabbitMQ管理后台队列有没有新增一条待消费的消息:

由此可见,已经新增一条待消费的消息,证明canal集群部署成功!

5.小结

在部署集群过程中偶尔会发生canal集群没有推送MQ消费情况,需要重新启动canal.server服务才生效,不知道是因为canal内部集成对rabbitmq不友好还是怎么的,后续测试排查下问题。该章节主要介绍如何搭建canal高可用集群,后续我们会深入了解内部原理跟其他功能。

参考文献:
AdminGuide https://github.com/alibaba/canal/wiki/AdminGuide
简介 https://github.com/alibaba/canal/wiki/%E7%AE%80%E4%BB%8B

### Canal 集群配置与使用指南 Canal 是阿里巴巴开源的一个用于增量数据订阅和消费的组件,广泛用于数据库增量日志的解析和订阅场景。其核心原理是模拟 MySQL 的 Slave 协议,连接 MySQL 主库并读取其 binlog 日志,从而实现数据的增量订阅与消费。 在高可用(HA)集群模式下,Canal 依赖 Zookeeper 进行分布式协调和状态管理。通过 Zookeeper,Canal Server 和 Canal Adapter 能够实现故障转移和负载均衡,确保服务的高可用性[^1]。 #### 1. 环境准备 在搭建 Canal 集群之前,需要准备好以下环境和组件: - **MySQL 数据库**:确保 MySQL 已启用 binlog,并配置为 `ROW` 模式。此外,建议创建一个专门用于 Canal 的 MySQL 用户,并授予相应的权限: ```sql GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%' IDENTIFIED BY 'canal'; ``` - **Zookeeper 集群**:Canal 依赖 Zookeeper 实现 HA 高可用性,建议部署一个 Zookeeper 集群以确保可靠性。Zookeeper 的安装和配置可以参考相关文档。 - **JDK 环境**:Canal 需要 Java 环境支持,建议使用 JDK 1.7 或更高版本。 #### 2. Canal Admin 安装与配置 Canal Admin 是 Canal 的管理模块,用于管理 Canal Server 的实例配置、权限控制等。以下是安装步骤: - **下载并解压安装包**: ```bash wget https://github.com/alibaba/canal/releases/download/canal-1.1.5/canal.admin-1.1.5.tar.gz mkdir -p /software/canal-admin tar -xzvf canal.admin-1.1.5.tar.gz -C /software/canal-admin ``` - **初始化元数据库**:Canal Admin 需要一个数据库来存储元数据信息,建议使用 MySQL 数据库,并按照 Canal 的要求初始化表结构。 - **配置文件修改**:在 `application.properties` 文件中配置数据库连接信息、Zookeeper 地址等: ``` canal.zkServers=10.20.144.51:2181 canal.instance.global.spring.xml = classpath:spring/default-instance.xml ``` #### 3. Canal Server 配置 Canal Server 是 Canal 的核心组件,负责与 MySQL 进行交互,解析 binlog 日志。配置步骤如下: - **修改 `canal.properties` 文件**:配置 Zookeeper 地址、实例名称、日志级别等参数。 ``` canal.zkServers=10.20.144.51:2181 canal.instance.example.master.address=127.0.0.1:3306 canal.instance.example.dbUsername=canal canal.instance.example.dbPassword=canal ``` - **配置实例文件**:每个 Canal 实例对应一个 MySQL 数据库实例,实例的配置文件通常位于 `conf/example/` 目录下。可以根据实际需求修改 `instance.properties` 文件中的参数。 #### 4. 启动与验证 - **启动 Canal Admin**:进入 `/software/canal-admin/bin` 目录,执行启动脚本: ```bash ./startup.sh ``` - **启动 Canal Server**:进入 Canal Server 的安装目录,执行启动脚本: ```bash ./bin/startup.sh ``` - **验证 Canal 服务**:通过访问 Canal Admin 的 Web 界面,查看 Canal Server 的状态是否正常。同时,可以通过编写简单的 Canal Client 程序来订阅和消费 binlog 数据。 #### 5. Canal Client 使用 Canal Client 是 Canal 的消费者,负责订阅并消费 Canal Server 推送的 binlog 数据。以下是一个简单的 Canal Client 示例代码: ```java import com.alibaba.otter.canal.client.CanalConnector; import com.alibaba.otter.canal.client.CanalConnectors; import com.alibaba.otter.canal.protocol.CanalEntry; import com.alibaba.otter.canal.protocol.Message; public class SimpleCanalClient { public static void main(String[] args) { // 创建连接器 CanalConnector connector = CanalConnectors.newSingleConnector("127.0.0.1", 11111, "", ""); try { // 连接 Canal Server connector.connect(); // 订阅所有表 connector.subscribe(".*\\..*"); while (true) { // 获取消息 Message message = connector.getWithoutAck(100); long batchId = message.getId(); if (batchId == -1 || message.getEntries().size() == 0) { continue; } // 处理消息 for (CanalEntry.Entry entry : message.getEntries()) { if (entry.getEntryType() == CanalEntry.EntryType.ROWDATA) { CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue()); System.out.println(rowChange); } } // 确认消息 connector.ack(batchId); } } finally { // 关闭连接 connector.disconnect(); } } } ``` #### 6. 高可用性配置 在 HA 集群模式下,Canal Server 和 Canal Adapter 依赖 Zookeeper 实现高可用性。通过 Zookeeper,多个 Canal Server 实例可以共同工作,确保在某个节点故障时,其他节点能够接管任务,保证服务的连续性。[^1] 此外,Canal 支持将解析后的数据推送到多种消息中间件,如 Kafka、RocketMQ 和 RabbitMQ,进一步增强了系统的可扩展性和可靠性。[^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值