Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Canal高可用架构部署

Canal高可用架构部署

作者头像
陶陶技术笔记
发布于 2021-03-24 02:30:58
发布于 2021-03-24 02:30:58
4.3K20
代码可运行
举报
文章被收录于专栏:陶陶技术笔记陶陶技术笔记
运行总次数:0
代码可运行

一、前言

canal 是阿里的一款开源项目,纯 Java 开发。基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了 MySQL(也支持 mariaDB)。

  1. canal 模拟 mysql slave 的交互协议,伪装自己为 mysql slave,向 mysql master发送 dump 协议;
  2. mysql master 收到 dump 请求,开始推送binary log给 slave(也就是canal)
  3. canal 解析 binary log对象(原始为byte流)。

「总体架构」

二、部署准备

「下载地址」:https://github.com/alibaba/canal/releases

分别下载:canal.admin、canal.deployer、canal.adapter

「PS」:只有1.1.5以上版本才支持es7.x

「其他依赖」

  1. JDK1.8
  2. MySQL:用于canal-admin存储配置和节点等相关数据
  3. Zookeeper

三、HA机制

整个 HA 机制的控制主要是依赖了zookeeper的两个特性:watcher、EPHEMERAL节点。canal的 HA 机制实现分为两部分,canal server 和 canal client分别有对应的实现。

「canal server实现流程如下:」

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

「PS」: 为了减少对mysql dump的请求,不同server上的instance要求同一时间只能有一个处于running,其他的处于standby状态。

「canal client实现流程」

  1. canal client 的方式和 canal server 方式类似,也是利用 zookeeper 的抢占EPHEMERAL 节点的方式进行控制
  2. 为了保证有序性,一份 instance 同一时间只能由一个 canal client 进行get/ack/rollback操作,否则客户端接收无法保证有序。

四、集群部署

4.1. MySQL准备

4.1.1. 开启binlog

MySQL的 my.cnf 中配置如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复

「注意」:如果订阅的是mysql的从库,需求增加配置让从库日志也写到binlog里面

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
log_slave_updates=1

可以通过在 mysql 终端中执行以下命令判断配置是否生效:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
show variables like 'log_bin';
show variables like 'binlog_format';
4.1.2. 授权账号权限

授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

4.2. 部署canal-admin

4.2.1. 作用
  1. 通过图形化界面管理配置参数。
  2. 动态启停 ServerInstance
  3. 查看日志信息
4.2.2. 执行数据库脚本

执行 conf 目录下载的 canal_manager.sql 脚步,初始化所需的库表。

初始化SQL脚本里会默认创建canal_manager的数据库,建议使用root等有超级权限的账号进行初始化

4.2.3. 配置修改

执行 vim conf/application.yml

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server:
  port: 8089
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

spring.datasource:
  address: 127.0.0.1:3306
  database: canal_manager
  username: canal
  password: canal
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  hikari:
    maximum-pool-size: 30
    minimum-idle: 1

canal:
  adminUser: admin
  adminPasswd: admin

修改 addressdatabaseusernamepassword 四个参数

4.2.4. 启停命令

启动

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sh bin/startup.sh

停止

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sh bin/stop.sh
4.2.5. 使用

通过 http://127.0.0.1:8089/ 访问,默认密码:admin/123456

4.2.5.1. 创建集群

配置 「集群名称」「ZK地址」

配置 「主配置」,该配置为集群内的所有Server实例共享的

主要修改以下配置:

  • 「canal.zkServers」 配置zookeeper集群地址
  • 「canal.instance.global.spring.xml」 改为classpath:spring/default-instance.xml
4.2.5.2. 创建Server

配置项:

  • 所属集群,可以选择为单机 或者 集群。一般单机Server的模式主要用于一次性的任务或者测试任务
  • Server名称,唯一即可,方便自己记忆
  • Server Ip,机器ip
  • admin端口,canal 1.1.4版本新增的能力,会在canal-server上提供远程管理操作,默认值11110
  • tcp端口,canal提供netty数据订阅服务的端口
  • metric端口, promethues的exporter监控数据端口 (未来会对接监控)

多台Server关联同一个集群即可形成主备HA架构

4.2.5.3. 创建Instance

每个 Instance 关联一个同步的数据源,如果有多个数据源需要同步则需要创建多个 「实例」

  1. 先填写实例名
  2. 选择刚刚创建的集群
  3. 载入模板配置

主要修改以下配置:

  • 「canal.instance.master.address」 配置要同步的数据库地址
  • 「canal.instance.dbUsername」 数据库用户名(需同步权限)
  • 「canal.instance.dbPassword」 数据库密码
  • 「canal.instance.filter.regex」 mysql 数据解析关注的表,Perl正则表达式.多个正则之间以逗号(,)分隔,转义符需要双斜杠(\)

canal.instance.filter.regex常见例子:

  1. 所有表:.* or .\..
  2. canal schema下所有表:canal\..*
  3. canal下的以canal打头的表:canal\.canal.*
  4. canal schema下的一张表:canal.test1
  5. 多个规则组合使用:canal\..*,mysql.test1,mysql.test2 (逗号分隔) 注意:此过滤条件只针对row模式的数据有效(ps. mixed/statement因为不解析sql,所以无法准确提取tableName进行过滤)

4.3. 部署canal-deployer

4.3.1. 作用
  1. 伪装成 MySQL 的从库,同步主库的binlog日志。
  2. 解析并结构化 binary log 对象。
4.3.2. 修改配置

执行 vim conf/canal_local.properties 修改配置项 canal.admin.manager 为canal-admin的地址

4.3.3. 启停命令

使用 「local」 配置启动

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bin/startup.sh local

停止

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bin/stop.sh

4.4. 部署canal-adapter

4.4.1. 作用
  1. 对接上游消息,包括kafka、rocketmq、canal-server
  2. 实现mysql数据的增量同步
  3. 实现mysql数据的全量同步
  4. 下游写入支持mysql、es、hbase等
4.4.2. 修改配置

「注意」:目前 adapter 是支持动态配置的,也就是说修改配置文件后无需重启,任务会自动刷新配置!

「(1) 修改application.yml」

执行 vim conf/application.yml 修改consumerProperties、srcDataSources、canalAdapters的配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
canal.conf:
  mode: tcp # kafka rocketMQ                # canal client的模式: tcp kafka rocketMQ
  flatMessage: true                         # 扁平message开关, 是否以json字符串形式投递数据, 仅在kafka/rocketMQ模式下有效
  syncBatchSize: 1000                       # 每次同步的批数量
  retries: 0                                # 重试次数, -1为无限重试
  timeout:                                  # 同步超时时间, 单位毫秒
  consumerProperties:
    canal.tcp.server.host:                  # 对应单机模式下的canal
    canal.tcp.zookeeper.hosts: 127.0.0.1:2181 # 对应集群模式下的zk地址, 如果配置了canal.tcp.server.host, 则以canal.tcp.server.host为准
    canal.tcp.batch.size: 500               # tcp每次拉取消息的数量
  srcDataSources:                           # 源数据库
    defaultDS:                              # 自定义名称
      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true   # jdbc url 
      username: root                                            # jdbc 账号
      password: 121212                                          # jdbc 密码
  canalAdapters:                            # 适配器列表
  - instance: example                       # canal 实例名或者 MQ topic 名
    groups:                                 # 分组列表
    - groupId: g1                           # 分组id, 如果是MQ模式将用到该值
      outerAdapters:                        # 分组内适配器列表
      - name: es7                           # es7适配器
        mode: rest                          # transport or rest
        hosts: 127.0.0.1:9200               # es地址
        security.auth: test:123456          # 访问es的认证信息,如没有则不需要填
        cluster.name: my-es                 # 集群名称,transport模式必需配置
......           

  1. 一份数据可以被多个group同时消费, 多个group之间会是一个并行执行, 一个group内部是一个串行执行多个outerAdapters, 比如例子中logger和hbase
  2. 目前client adapter数据订阅的方式支持两种,直连canal server 或者 订阅kafka/RocketMQ的消息

「(2) conf/es7目录下新增映射配置文件」

adapter将会自动加载 conf/es7 下的所有 .yml 结尾的配置文件

新增表映射的配置文件,如 sys_user.yml 内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dataSourceKey: defaultDS
destination: example
groupId: g1
esMapping:
  _index: sys_user
  _id: id
  upsert: true
  sql: "select id, username, 
        , case when sex = 0 then '男' else '女' end sex
        , case when is_del = 0 then '否' else '是' end isdel
      from sys_user"
  etlCondition: "where update_time>={}"
  commitBatch: 3000
  • 「dataSourceKey」 配置 application.ymlsrcDataSources 的值
  • 「destination」 配置 canal.deployerInstance
  • 「groupId」 配置 application.ymlcanalAdapters.groups 的值
  • 「_index」 配置索引名
  • 「_id」 配置主键对应的字段
  • 「upsert」 是否更新
  • 「sql」 映射sql
  • 「etlCondition」 etl 的条件参数,全量同步时可以使用
  • 「commitBatch」 提交批大小

sql映射支持多表关联自由组合, 但是有一定的限制:

  1. 主表不能为子查询语句
  2. 只能使用left outer join即最左表一定要是主表
  3. 关联从表如果是子查询不能有多张表
  4. 主sql中不能有where查询条件(从表子查询中可以有where条件但是不推荐, 可能会造成数据同步的不一致, 比如修改了where条件中的字段内容)
  5. 关联条件只允许主外键的'='操作不能出现其他常量判断比如: on a.role_id=b.id and b.statues=1
  6. 关联条件必须要有一个字段出现在主查询语句中比如: on a.role_id=b.id 其中的 a.role_id 或者 b.id 必须出现在主select语句中

Elastic Search的mapping 属性与sql的查询值将一一对应(不支持 select *), 比如: select a.id as _id, a.name, a.email as _email from user, 其中name将映射到es mapping的name field, _email将 映射到mapping的_email field, 这里以别名(如果有别名)作为最终的映射字段. 这里的_id可以填写到配置文件的 _id: _id映射

4.4.3. 启停命令

启动

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bin/startup.sh

关闭

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
bin/stop.sh

4.5. 遗留问题

目前使用的 1.1.5-SNAPSHOT 版本由于还不是发布版,发现 canal-adapter 的集群部署有个bug,配置 zookeeper 地址后启动会出现以下异常:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
java.lang.LinkageError: loader constraint violation: when resolving method "com.alibaba.otter.canal.common.zookeeper.ZkClientx.create(Ljava/lang/String;Ljava/lang/Object;Lorg/apache/zookeeper/CreateMode;)Ljava/lang/String;" the class loader (instance of com/alibaba/otter/canal/connector/core/spi/URLClassExtensionLoader) of the current class, com/alibaba/otter/canal/client/impl/running/ClientRunningMonitor, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, org/I0Itec/zkclient/ZkClient, have different Class objects for the type org/apache/zookeeper/CreateMode used in the signature
 at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.initRunning(ClientRunningMonitor.java:122) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
 at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.start(ClientRunningMonitor.java:93) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
 at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.connect(SimpleCanalConnector.java:108) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
 at com.alibaba.otter.canal.client.impl.ClusterCanalConnector.connect(ClusterCanalConnector.java:64) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
 at com.alibaba.otter.canal.connector.tcp.consumer.CanalTCPConsumer.connect(CanalTCPConsumer.java:59) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]

有以下3个解决思路:

  1. adapter暂时使用单实例模式,等待官方解决问题。
  2. 自行修复bug
  3. 使用 MQ 模式(adapter则无需注册到zookeeper了)

「BUG」 已修复:https://github.com/zlt2000/canal

五、监控

canal 默认已通过 11112 端口暴露同步相关的 metrics 信息,只需通过集成 prometheusgrafana 即可实现实时监控同步情况,效果图如下:

file

指标

简述

Basic

Canal instance 基本信息。

Network bandwith

网络带宽。包含inbound(canal server读取binlog的网络带宽)和outbound(canal server返回给canal client的网络带宽)。

Delay

Canal server与master延时;store 的put, get, ack操作对应的延时。

Blocking

sink线程blocking占比;dump线程blocking占比(仅parallel mode)。

TPS(events)

Canal instance消费所有binlog事件的TPS, 以MySQL binlog events为单位计算。

TPS(transaction)

Canal instance 处理binlog的TPS,以MySQL transaction为单位计算。

TPS(tableRows)

分别对应store的put, get, ack操作针对数据表变更行的TPS。

Client requests

Canal client请求server的请求数统计,结果按请求类型分类(比如get/ack/sub/rollback等)。

Client QPS

client发送请求的QPS,按GET与CLIENTACK分类统计。

Empty packets

Canal client请求server返回空结果的统计。

Response time

Canal client请求server的响应时间统计。

Store remain events

Canal instance ringbuffer中堆积的events数量。

Store remain mem

Canal instance ringbuffer中堆积的events内存使用量。

六、总结

  1. 准备MySQL
    • 开启binlog(row模式)
    • 准备同步权限的用户
    • 创建canal-admin的库表
  2. 准备zookeeper
  3. 部署canal-admin
    • 创建集群
    • 创建server:关联集群
    • 创建Instance:关联集群,并配置源库信息
  4. 启动canal-deployer
    • 关联canal-admin
  5. 启动canal-adapter
    • 关联zookeeper
    • 配置源库信息
    • 关联Instance
    • 配置目标库信息(es)
    • 新增映射配置文件
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陶陶技术笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
2 条评论
热度
最新
根据文章中贴的配置文件,貌似是在 k8s 中部署的,可否分享一下 Yaml 文件啊。
根据文章中贴的配置文件,貌似是在 k8s 中部署的,可否分享一下 Yaml 文件啊。
11点赞举报
你好,文章内容没有任何与k8s相关的配置
你好,文章内容没有任何与k8s相关的配置
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
超详细canal入门,看这篇就够了
我们都知道一个系统最重要的是数据,数据是保存在数据库里。但是很多时候不单止要保存在数据库中,还要同步保存到Elastic Search、HBase、Redis等等。
java技术爱好者
2020/09/22
3.8K0
【Canal】数据同步的终极解决方案,阿里巴巴开源的Canal框架当之无愧!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
1.4K0
【Canal】数据同步的终极解决方案,阿里巴巴开源的Canal框架当之无愧!!
MySQL如何实时同步数据到ES?试试这款阿里开源的神器!
canal主要用途是对MySQL数据库增量日志进行解析,提供增量数据的订阅和消费,简单说就是可以对MySQL的增量数据进行实时同步,支持同步到MySQL、Elasticsearch、HBase等数据存储中去。
用户4172423
2020/11/11
3.5K1
MySQL如何实时同步数据到ES?试试这款阿里开源的神器!
基于canal的client-adapter数据同步必读指南
本文将介绍canal项目中client-adapter的使用,以及落地生产中需要考虑的可靠性、高可用与监控报警。(基于canal 1.1.4版本)
全栈程序员站长
2021/04/07
7.3K0
基于canal的client-adapter数据同步必读指南
Canal相关
canal项目位于官方主页,是阿里开源的mysql binlog操作中间件,其介绍在主页都有.
郑小超.
2022/09/23
8360
Canal数据同步工具
​ Canal就是一个很好的数据库同步工具。canal是阿里巴巴旗下的一款开源项目,纯Java开发。基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL。
OY
2022/03/18
1.7K0
Canal数据同步工具
Canal报错总结
网上都说是需要改yml里面的SQL,表要设置别名,然而我试了,没有效果。。。 没办法,debug源码看看,这边能看到,是别名不匹配导致的
程序员朱永胜
2023/08/17
1.7K0
Canal报错总结
基于Canal和Kafka实现MySQL的Binlog近实时同步
近段时间,业务系统架构基本完备,数据层面的建设比较薄弱,因为笔者目前工作重心在于搭建一个小型的数据平台。优先级比较高的一个任务就是需要近实时同步业务系统的数据(包括保存、更新或者软删除)到一个另一个数据源,持久化之前需要清洗数据并且构建一个相对合理的便于后续业务数据统计、标签系统构建等扩展功能的数据模型。基于当前团队的资源和能力,优先调研了Alibaba开源中间件Canal的使用。
王知无-import_bigdata
2020/03/19
2.1K0
基于Canal和Kafka实现MySQL的Binlog近实时同步
基于Canal与Flink实现数据实时增量同步(一)
canal是阿里巴巴旗下的一款开源项目,纯Java开发。基于数据库增量日志解析,提供增量数据订阅&消费,目前主要支持了MySQL(也支持mariaDB)。
Spark学习技巧
2020/09/08
2.5K0
拉取 binlog,自动数据同步,老板要给涨工资....
1、同步双写:字面意思,同步+双写。比如老库模型重构,数据迁移到新库,迁移过程中,如果有数据变更,既要写到老库,也要写到新库,两边同步更新。
微观技术
2022/02/10
5330
拉取 binlog,自动数据同步,老板要给涨工资....
Canal原理及其使用
  canal是用java开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件。目前,canal主要支持了MySQL的binlog解析,解析完成后才利用canal client 用来处理获得的相关数据。(数据库同步需要阿里的otter中间件,基于canal)
用户4283147
2022/10/27
1.6K0
Canal原理及其使用
使用canal增量订阅MySQL binlog
【转载请注明出处】:https://cloud.tencent.com/developer/article/1634327
后端老鸟
2020/05/28
3K0
使用canal增量订阅MySQL binlog
canal-adapter消费Kafka中MySQL的binlog数据,却没有同步更新Elastic search
在同步的时候发现canal-adapter中canal-adapter/conf/es7/product.yml 配置文件中sql 语句连表查询的时候会出现无法更新Elasticsearch 中数据的情况,而且日志没有提示异常(idea启动的时候有错误日志),令人百思不得其解。
iiopsd
2022/12/23
1.8K0
canal-adapter消费Kafka中MySQL的binlog数据,却没有同步更新Elastic search
SpringBoot系列之canal和kafka实现异步实时更新
canal是阿里开源的, 对数据库增量日志解析,提供增量数据订阅和消费的组件。引用官网的图片,canal的工作原理主要是模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave,向master发送dump 协议,获取到数据后,解析 binary log 对象数据。
SmileNicky
2022/01/04
2K1
SpringBoot系列之canal和kafka实现异步实时更新
手摸手实现Canal如何接入MySQL实现数据写操作监听
🍁 作者:知识浅谈,CSDN签约讲师,CSDN原力作者,后端领域优质创作者,热爱分享创作 💒 公众号:知识浅谈 📌 擅长领域:全栈工程师、爬虫、ACM算法 Canal的使用分为两部分: 上部分为canal接入Mysql数据库进行操作监听。 下部分为Canal如何接入消息队列、Redis、Canal的高可用HA。 这次拿上部分来做正菜🛴🛴🛴 环境:linux 数据库主机(192.168.31.230) Canal server主机(192.168.31.231) 🎈安装MySQL
知识浅谈
2022/11/13
1.2K0
手摸手实现Canal如何接入MySQL实现数据写操作监听
18 张图手把手教你使用 Canal Adapter 同步 MySQL 数据到 ES8,建议收藏!
2.初始化 Canal 数据库,并且增加对应的数据库账号和开启 slave 权限;
Java极客技术
2024/04/25
2.4K2
18 张图手把手教你使用 Canal Adapter 同步 MySQL 数据到 ES8,建议收藏!
数据异构重器之 Canal 初探
提到 Canal,大家应该都能想到这是一个用于解析 MySQL binlog 日志的工具,并将 MySQL 数据库中数据同步到其他存储介质中,例如 Elasticsearch。
丁威
2020/06/16
1.4K0
数据异构重器之 Canal 初探
2 监听mysql表内容变化,使用canal
mysql本身是支持主从的(master slave),原理就是master产生的binlog日志记录了所有的增删改语句,将binlog发送到slave节点进行执行即可完成数据的同步。
天涯泪小武
2019/01/17
6.9K0
Redis应用—7.大Value处理方案
步骤一:首先需要配置一个crontab定时调度shell脚本,然后该脚本每天凌晨会通过rdbtools⼯具解析Redis的RDB⽂件,接着对解析出的内容进行过滤,把RDB⽂件中的⼤key导出到CSV⽂件。
东阳马生架构
2025/03/07
1040
k8s 安装canal 注意事项
编写 mer_index.yml (注意:sql 语句中每张表的主键都要出现在查询中)
iiopsd
2022/12/23
7620
相关推荐
超详细canal入门,看这篇就够了
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档