【FLINKCDC】运行时经常server-id冲突报错?一招实现自动化!

前言

最近大批量flink-cdc任务运行遇到一个报错,加班的罪恶源头~server-id异常报错
server-id异常报错

Caused by: io.debezium.DebeziumException: 
    A slave with the same server_uuid/server_id as this slave has connected to the master; 
    the first event 'binlog.000002' at 1136, the last event read from './binlog.000002' at 1431, the last byte read from './binlog.000002' at 1431. 
    Error code: 1236; SQLSTATE: HY000.  at io.debezium.connector.mysql.MySqlStreamingChangeEventSource.wrap(MySqlStreamingChangeEventSource.java:1146)  
    ... 5 more
Caused by: com.github.shyiko.mysql.binlog.network.ServerException: 
    A slave with the same server_uuid/server_id as this slave has connected to the master; 
    the first event 'binlog.000002' at 1136, the last event read from './binlog.000002' at 1431, 
    the last byte read from './binlog.000002' at 1431.  
    at com.github.shyiko.mysql.binlog.BinaryLogClient.listenForEventPackets(BinaryLogClient.java:937)  
    ... 3 more

报错原因

该报错是同一个库(相同实例)同步多个表时,启动了多个flink-cdc任务时出现的。
经排查造成的原因是:
在这里插入图片描述

来自:阿里云开发者社区 chengfengpolang

一开始看到这个解释还是一脸懵的,配置mysql binlog的时候有印象确实设置过server-id = 1,难道是启动两个相同的mysql实例的flink-cdc任务时如果都用相同的server id会导致这类冲突报错?带着这个疑问我寻找了一些资料…

自从flink cdc贡献到apache后,有些资料在旧官网已经看不到了,不过在新官网中找到了server-id的一些相关配置。
在这里插入图片描述

深入细节

于是打开flink-cdc-connector源码一探究竟

MysqlSource createReader -> MysqlSourceConfigFactory

在这里插入图片描述

在源码注释里面也是很清晰说明了:这个server-id如果不设置的话默认是从5400-6400中随机分配一个数字,建议用户设置一个具体的值;同时也说了如果没开启参数scan.incremental.snapshot.enabled,则只用指定一个值,如果开启了该参数,则需要指定一个范围并且不能小于source的并行度。

这里可以对这个参数做一些解释,在flink-cdc 2.x版本引入了一个重要特性之一:增量快照读取机制。

这种全选的读取方式支持并发读取,原理是根据表的主键将所有加载到的数据根据scan.incremental.snapshot.chunk.size(默认值是8096)进行切分,例如100w数据就是切分成 100w ÷ size 个chuck,然后这些chuck根据程序分配的并行度读取器并行读取,这样能做到snapshot阶段的多并行,且可以以chunk为粒度进行checkpoint

在这里插入图片描述

debezium官方文档

Debezium是flink-cdc的底层采集工具,其官方文档也是建议MySqlConnector实例的进程中server id唯一且需设置在范围1——232-1之内。

根据获取到的信息,我手动给他根据给这两个相同实例的任务设置不同的server id,程序1并行度是10,我将server id设置成1-11,程序2并行度是16,我将server id设置成12-28,程序果然能长时间正常运行,没有再出现结束snapshot阶段进入binlogReader阶段时报错server-id冲突。

事情到这里就结束了吗,并没有!!!
如果这个实例只是一两个任务,那手动设置server id还可以,如果这个实例有需求上百上千个任务,或者我想把它集成到数据集成平台中呢,我一个一个任务启动时还需要去代码中配置server-id,那大量的开发时间就会浪费掉!

一了百了

有没有自动化的方法呢?of course 这里我尝试了2个方法:

  • 当前时间timestamp,范围(timestamp ~ timestamp + parallelism)
  • 查询数据库里面的使用到的server-id,根据查询到的server-id进行排序,取每次查询到的max(server-id)取该值~max(server-id) + parallelism

果不其然,第一个方案很快就成功了。

System.currentTimeMillis() / 1000

但是有个弊端,由于毫秒超出server-id最大值范围,需要保证任务不是一次性批量启动的,要保证并行度的秒数内不同时启动才可以,比如第一个任务启动的是20并行度,第二个任务需要20秒后启动;

在尝试开启plan B的时候,遇到了比较多的问题,当我执行这个sql语句去查询数据库server-id时。

show variables like 'server_id'

查询出来的结果一直都是1(mysql binlog中设置的my.ini文件里的server-id值),无论程序中运行的server-id改成什么都记录不了,所以直接pass掉方案二。

如果还有什么其他比较好用的方法欢迎交流,创作不易,欢迎转发点赞支持~

### 使用Flink CDC连接SQL Server进行数据变更捕获 为了实现使用Apache FlinkCDC功能来捕捉来自SQL Server的数据变更,可以采用官方支持的方式之一——通过Debezium SQL Server Connector。此方法允许实监控数据库中的更改并将其流式传输到下游处理系统。 #### 配置环境准备 确保安装了必要的组件和服务: - Apache Flink集群已部署完毕。 - 已经配置好Kafka作为消息队列服务用于传递增量更新事件。 - 安装并启用了Debezium SQL Server Connector插件于Kafka Connect环境中[^1]。 #### 创建SQL Server表结构 假设有一个名为`flink_cdc_example`的数据库以及一张记录用户信息的表格`users`: ```sql CREATE DATABASE flink_cdc_example; USE flink_cdc_example; CREATE TABLE users ( id INT IDENTITY(1,1), name VARCHAR(50) NOT NULL, email VARCHAR(255) UNIQUE NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id) ); ``` #### 启用SQL Server的日志读取器代理作业 对于SQL Server来说,在启用CDC之前需要先启动日志读取器代理作业以跟踪事务日志的变化情况。这一步骤可以通过执行以下命令完成: ```sql EXEC sys.sp_CDC_enable_db_flumes; -- 替换为实际库名 GO EXEC sys.sp_cdc_add_job @job_type = N'log reader'; GO ``` 接着针对特定表开启CDC特性: ```sql EXEC sys.sp_cdc_enable_table @source_schema = 'dbo', @source_name = 'users', @role_name = null, @supports_net_changes = 1 ; GO ``` #### 设置Debezium Source Connector 创建一个新的Debezium Source Connector实例指向上述SQL Server实例,并指定要监听的目标模式和表列表。以下是JSON格式化的配置示例: ```json { "name": "sqlserver-flink-cdc", "config": { "connector.class": "io.debezium.connector.sqlserver.SqlServerConnector", "database.hostname": "<your_sql_server_host>", "database.port": "1433", "database.user": "<db_user>", "database.password": "<db_password>", "database.dbname": "flink_cdc_example", "table.whitelist": "dbo.users", "database.server.name": "flinkcdc", "database.history.kafka.bootstrap.servers": "localhost:9092", "database.history.kafka.topic": "schema-changes.flinkcdc" } } ``` 当以上设置完成后,任何发生在`users`表上的增删改操作都会被自动转换成相应的Change Event并通过Kafka主题传播出去[^2]。 #### 编写Flink应用程序消费变更事件 最后编写一段简单的Flink程序订阅这些由Debezium产生的变更事件,并对其进行进一步加工或存储至其他目标位置。这里给出Python版本的例子(注意实际生产环境下推荐Java/Scala): ```python from pyflink.datastream import StreamExecutionEnvironment from pyflink.table import StreamTableEnvironment, EnvironmentSettings import json env = StreamExecutionEnvironment.get_execution_environment() settings = EnvironmentSettings.new_instance().in_streaming_mode().use_blink_planner().build() t_env = StreamTableEnvironment.create(env, environment_settings=settings) # 注册Kafka源表 t_env.execute_sql(""" CREATE TABLE kafka_source ( `id` BIGINT, `before` ROW<`name` STRING, `email` STRING>, `after` ROW<`name` STRING, `email` STRING>, `op` STRING, `ts_ms` BIGINT ) WITH ( 'connector' = 'kafka', 'topic' = 'flinkcdc.dbo.users', -- Kafka topic名称遵循固定格式:<服务器名>.<架构名>.<表名> 'properties.bootstrap.servers' = 'localhost:9092', 'format' = 'json' ) """) result = t_env.from_path('kafka_source').select('*') print(json.dumps(result.to_pandas().to_dict(), indent=2)) ``` 这段脚本会持续不断地拉取消息并将它们打印出来供调试查看之用;当然也可以根据业务需求修改逻辑来进行更复杂的ETL流程设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值