Flink SQL CDC

Flink1.11中的CDC Connectors操作实践 汇总

7月,Flink 1.11 新版发布,在生态及易用性上有大幅提升,其中 Table & SQL 开始支持 Change Data Capture(CDC)。CDC 被广泛使用在复制数据、更新缓存、微服务间同步数据、审计日志等场景,本文由社区由曾庆东同学分享,主要介绍 Flink SQL CDC 在生产环境的落地实践以及总结的实战经验,文章分为以下几部分:项目背景
解决方案
项目运行环境与现状
具体实现
踩过的坑和学到的经验
总结

Tips:点击下方链接可查看社区直播的 Flink SQL CDC 相关视频~
https://flink-learning.org.cn/developers/flink-training-course3/

注意点:

  1. https://ci.apache.org/projects/flink/flink-docs-release-1.11/dev/table/connectors/elasticsearch.html#document-type
    Elasticsearch6 版本中需要设置 document-type 信息
Flink SQL> CREATE TABLE enriched_orders(
>   order_id INT,
>   order_date TIMESTAMP(0),
>   customer_name STRING,
>   price DECIMAL(10, 5),
>   product_id INT,
>   order_status BOOLEAN,
>   product_name STRING,
>   product_description STRING,
>   PRIMARY KEY (order_id) NOT ENFORCED
> )WITH(
>     'connector' = 'elasticsearch-6',
>     'document-type' = 'enriched_orders',
>     'hosts' = 'http://localhost:9200',
>     'index' = 'enriched_orders'
> );
  1. Elasticsearch 不支持直接select 查询,直接查询查询http:ip:9200 数据即可
Flink SQL> select * from enriched_orders;
[ERROR] Could not execute SQL statement. Reason:
org.apache.flink.table.api.ValidationException: Could not find any factory for identifier 'elasticsearch-6' that implements 'org.apache.flink.table.factories.DynamicTableSourceFactory' in the classpath.

Available factory identifiers are:

datagen
jdbc
kafka
mysql-cdc
  1. 其他

05 踩过的坑和学到的经验 (引自:Flink SQL CDC 上线!我们总结了 13 条生产实践经验

  1. Flink 作业原来运行在 standalone session 模式下,提交多个 Flink 作业会导致作业失败报错。
    原因:因为 standalone session 模式下启动多个作业会导致多个作业的 Task 共享一个 JVM,可能会导致一些不稳定的问题。并且排查问题时,多个作业的日志混在一个 TaskManager 中,增加了排查的难度。
    解决方法:采用 YARN 的 per-job 模式启动多个作业,能有更好的隔离性。

  2. SELECT elasticsearch table 报以下错误:
    原因:Elasticsearch connector 目前只支持了 sink,不支持 source 。所以不能 SELECT elasticsearch table。

  3. 在 flink-conf.yaml 里修改默认并行度,但是在 Web UI 看到作业的并行度还是 1,并行度修改不生效。
    解决办法:在使用 SQL Client 时 sql-client-defaults.yaml 中的并行度配置的优先级更高。在 sql-client-defaults.yaml 中修改并行度,或者删除 sql-client-defaults.yaml 中的并行度配置。更建议采用后者。

  4. Flink 作业在扫描 MySQL 全量数据时,checkpoint 超时,出现作业 failover,如下图:
    原因:Flink CDC 在 scan 全表数据(我们的实收表有千万级数据)需要小时级的时间(受下游聚合反压影响),而在 scan 全表过程中是没有 offset 可以记录的(意味着没法做 checkpoint),但是 Flink 框架任何时候都会按照固定间隔时间做 checkpoint,所以此处 mysql-cdc source 做了比较取巧的方式,即在 scan 全表的过程中,会让执行中的 checkpoint 一直等待甚至超时。超时的 checkpoint 会被仍未认为是 failed checkpoint,默认配置下,这会触发 Flink 的 failover 机制,而默认的 failover 机制是不重启。所以会造成上面的现象。
    解决办法:在 flink-conf.yaml 配置 failed checkpoint 容忍次数,以及失败重启策略,如下:
    execution.checkpointing.interval: 10min # checkpoint间隔时间
    execution.checkpointing.tolerable-failed-checkpoints: 100 # checkpoint 失败容忍次数
    restart-strategy: fixed-delay # 重试策略
    restart-strategy.fixed-delay.attempts: 2147483647 # 重试次数
    目前 Flink 社区也有一个 issue(FLINK-18578)来支持 source 主动拒绝 checkpoint 的机制,将来基于该机制,能比较优雅地解决这个问题。

  5. Flink 怎么样开启 YARN 的 per-job 模式?

  6. 解决方法:在 flink-conf.yaml 中配置 execution.target: yarn-per-job。7. 进入 SQL Client 创建 table 后,在另外一个节点进入 SQL Client 查询不到 table。
    原因:因为 SQL Client 默认的 Catalog 是在 in-memory 的,不是持久化 Catalog,所以这属于正常现象,每次启动 Catalog 里面都是空的。

  7. 作业在运行时 Elasticsearch 报如下错误:
    Caused by: org.apache.Flink.elasticsearch7.shaded.org.elasticsearch.ElasticsearchException: Elasticsearch exception [type=illegal_argument_exception, reason=mapper [amt] cannot be changed from type [long] to [float]]
    原因:数据库表的字段 amt 的类型是 decimal,DDL 创建输出到 es 的 amt 字段的类型也是 decimal,因为输出到 es 的第一条数据的amt如果是整数,比如是 10,输出到 es 的类型是 long 类型的,es client 会自动创建 es 的索引并且设置 amt 字段为 long 类型的格式,那么如果下一次输出到 es 的 amt 是非整数 10.1,那么输出到 es 的时候就会出现类型不匹配的错误。
    解决方法:手动生成 es 索引和 mapping 的信息,指定好 decimal 类型的数据格式是 saclefloat,但是在 DDL 处仍然可以保留该字段类型是 decimal。

  8. 作业在运行时 mysql cdc source 报如下错误:
    原因:因为数据库中别的表做了字段修改,CDC source 同步到了 ALTER DDL 语句,但是解析失败抛出的异常。
    解决方法:在 flink-cdc-connectors 最新版本中已经修复该问题(跳过了无法解析的 DDL)。升级 connector jar 包到最新版本 1.1.0:flink-sql-connector-mysql-cdc-1.1.0.jar,替换 flink/lib 下的旧包。

  9. 扫描全表阶段慢,在 Web UI 出现如下现象:
    原因:扫描全表阶段慢不一定是 cdc source 的问题,可能是下游节点处理太慢反压了。
    解决方法:通过 Web UI 的反压工具排查发现,瓶颈主要在聚合节点上。通过在 sql-client-defaults.yaml 文件配上 MiniBatch 相关参数和开启 distinct 优化(我们的聚合中有 count distinct),作业的 scan 效率得到了很大的提升,从原先的 10 小时,提升到了 1 小时。关于性能调优的参数可以参阅:https://ci.apache.org/projects/flink/flink-docs-release-1.11/zh/dev/table/tuning/streaming_aggregation_optimization.html。
    configuration:
    table.exec.mini-batch.enabled: true
    table.exec.mini-batch.allow-latency: 2s
    table.exec.mini-batch.size: 5000
    table.optimizer.distinct-agg.split.enabled: true

  10. CDC source 扫描 MySQL 表期间,发现无法往该表 insert 数据。原因:由于使用的 MySQL 用户未授权 RELOAD 权限,导致无法获取全局读锁(FLUSH TABLES WITH READ LOCK), CDC source 就会退化成表级读锁,而使用表级读锁需要等到全表 scan 完,才能释放锁,所以会发现持锁时间过长的现象,影响其他业务写入数据。
    解决方法:给使用的 MySQL 用户授予 RELOAD 权限即可。所需的权限列表详见文档:https://github.com/ververica/flink-cdc-connectors/wiki/mysql-cdc-connector#setup-mysql-server。如果出于某些原因无法授予 RELOAD 权限,也可以显式配上 ‘debezium.snapshot.locking.mode’ = 'none’来避免所有锁的获取,但要注意只有当快照期间表的 schema 不会变更才安全。

  11. 多个作业共用同一张 source table 时,没有修改 server id 导致读取出来的数据有丢失。原因:MySQL binlog 数据同步的原理是,CDC source 会伪装成 MySQL 集群的一个 slave(使用指定的 server id 作为唯一 id),然后从 MySQL 拉取 binlog 数据。如果一个 MySQL 集群中有多个 slave 有同样的 id,就会导致拉取数据错乱的问题。
    解决方法:默认会随机生成一个 server id,容易有碰撞的风险。所以建议使用动态参数(table hint)在 query 中覆盖 server id。如下所示:
    SELECT *
    FROM bill_info /*+ OPTIONS(‘server-id’=‘123456’) */ ;

  12. 在启动作业时,YARN 接收了任务,但作业一直未启动:
    原因:Queue Resource Limit for AM 超过了限制资源限制。默认的最大内存是 30G (集群内存) * 0.1 = 3G,而每个 JM 申请 2G 内存,当提交第二个任务时,资源就不够了。
    解决方法:调大 AM 的 resource limit,在 capacity-scheduler.xml 配置 yarn.scheduler.capacity.maximum-am-resource-percent,代表AM的占总资源的百分比,默认为0.1,改成0.3(根据服务器的性能灵活配置)。

  13. AM 进程起不来,一直被 kill 掉。
    原因:386.9 MB of 1 GB physical memory used; 2.1 GB of 2.1 GB virtual memory use。默认物理内存是 1GB,动态申请到了 1GB,其中使用了386.9 MB。物理内存 x 2.1=虚拟内存,1GBx2.1≈2.1GB ,2.1GB 虚拟内存已经耗尽,当虚拟内存不够时候,AM 的 container 就会自杀。
    解决方法:两个解决方案,或调整 yarn.nodemanager.vmem-pmem-ratio 值大点,或 yarn.nodemanager.vmem-check-enabled=false,关闭虚拟内存检查。参考:https://blog.csdn.net/lzxlfly/article/details/89175452。

以上操作注意flink 和 各个connector 以及 MySQL CDC 版本的对应
可以下载源码自行打包 https://github.com/apache/flink

相关资料:
Flink1.11中的CDC Connectors操作实践
Flink SQL CDC 上线!我们总结了 13 条生产实践经验
用Flink SQL实现数据流式导入Elasticsearch
Flink1.11中的CDC Connectors操作实践
Apache Flink 1.11.1 发布
flink-cdc-connectors中文教程

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以得知问题出现在将数据库操作代码放入`addSink`方法中时会报错。因此,我们需要将数据库操作代码放入`addSink`方法中,并使用`JdbcSinkFunction`类进行入库操作。以下是连接GaussDB并使用Flink SQL CDC进行数据同步的步骤: 1.首先,需要在Flink中添加GaussDB的JDBC驱动程序。可以将驱动程序jar包放入Flink的lib目录中,或者在启动Flink Job时使用`--classpath`参数指定驱动程序jar包的路径。 2.在Flink SQL Client中创建一个表,用于存储CDC数据。例如,可以使用以下命令创建一个名为`my_table`的表: ```sql CREATE TABLE my_table ( id INT, name STRING, age INT ) WITH ( 'connector' = 'jdbc', 'url' = 'jdbc:postgresql://localhost:5432/mydb', 'table-name' = 'my_table', 'username' = 'myuser', 'password' = 'mypassword', 'sink.buffer-flush.max-rows' = '5000' ) ``` 其中,`connector`参数指定使用JDBC连接器,`url`参数指定GaussDB的连接URL,`table-name`参数指定表名,`username`和`password`参数指定连接数据库的用户名和密码,`sink.buffer-flush.max-rows`参数指定缓冲区大小。 3.在Flink SQL Client中创建一个CDC源表,用于捕获GaussDB中的变更数据。例如,可以使用以下命令创建一个名为`my_source`的CDC源表: ```sql CREATE TABLE my_source ( id INT, name STRING, age INT, ts TIMESTAMP(3), watermark FOR ts AS ts - INTERVAL '5' SECOND ) WITH ( 'connector' = 'postgresql-cdc', 'hostname' = 'localhost', 'port' = '5432', 'username' = 'myuser', 'password' = 'mypassword', 'database-name' = 'mydb', 'schema-name' = 'public', 'table-name' = 'my_table' ) ``` 其中,`connector`参数指定使用PostgreSQL CDC连接器,`hostname`和`port`参数指定GaussDB的主机名和端口号,`username`和`password`参数指定连接数据库的用户名和密码,`database-name`参数指定数据库名,`schema-name`参数指定模式名,`table-name`参数指定表名。 4.在Flink SQL Client中创建一个查询,用于将CDC源表中的数据写入目标表。例如,可以使用以下命令创建一个查询: ```sql INSERT INTO my_table SELECT id, name, age FROM my_source ``` 5.在Flink中编写一个Job,将上述查询转换为Flink Job。例如,可以使用以下代码编写一个Job: ```java StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); StreamTableEnvironment tEnv = StreamTableEnvironment.create(env); tEnv.executeSql("CREATE TABLE my_table (id INT, name STRING, age INT) WITH (...)"); tEnv.executeSql("CREATE TABLE my_source (id INT, name STRING, age INT, ts TIMESTAMP(3), watermark FOR ts AS ts - INTERVAL '5' SECOND) WITH (...)"); tEnv.executeSql("INSERT INTO my_table SELECT id, name, age FROM my_source"); env.execute(); ``` 其中,`StreamExecutionEnvironment`和`StreamTableEnvironment`分别用于创建Flink执行环境和Flink Table环境,`executeSql`方法用于执行SQL语句,`env.execute()`方法用于启动Flink Job。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值