问题描述

CREATE TABLE mysql_binlog (
    user_id STRING NOT NULL,
    test_timestamp TIMESTAMP,
    test_datetime TIMESTAMP,
    PRIMARY KEY (user_id) NOT ENFORCED
) WITH (
    'connector' = 'mysql-cdc',
    'hostname' = 'host',
    'port' = '3306',
    'username' = 'root',
    'password' = 'root',
    'database-name' = 'test',
    'scan.startup.mode' = 'initial',
    'table-name' = 'test_\d*'
)

使用flink-mysql-cdc读取mysql的binlog,发现mysql中的timestamp类型的字段的值与flink中该字段的值不一致:

在mysql中的值为:2022-08-01 20:56:16,flink-mysql-cdc读取出来的值为:2022-08-01 12:56:16.000,相差了8个小时。

同时,观察到mysql中datetime类型的字段并不会出现这个问题

问题排查

相差了8个小时,很明显是时区问题,于是查找官方文档,发现如下配置

OptionRequiredDefaultTypeDescription
server-time-zoneoptionalUTCStringThe session time zone in database server, e.g. “Asia/Shanghai”. It controls how the TIMESTAMP type in MYSQL converted to STRING. See more here.

我的flink没有添加这样的配置,所以flink采用了默认的UTC时区,于是导致了这个问题,添加该配置'server-time-zone' = 'Asia/Shanghai'后问题解决。

并且,观察到一个现象,由于我的配置'scan.startup.mode' = 'initial',cdc会有初始化阶段,初始化阶段并不会出现这个问题,原因是cdc的初始化逻辑并不是读binlog,而是直接执行SQL语句读取数据,这时候的时区会由数据库的时区配置决定,因此没有出现问题,而进入增量读取binlog阶段后,时区问题就出现了。

总结

mysql中datetime类型和timestamp类型是有所区别的(参考文档),对于timestamp类型的字段,mysql会从当前时区(根据数据库配置/会话设置等)转换为UTC进行存储,读取的时候会从UTC转换回当前时区,而datetime类型不会发生这种情况。

flink-mysql-cdc在读取binlog的时候与时区配置无关,而是直接读取到了timestamp类型字段在UTC时区的值,如果需要指定时区,则需要添加flink配置。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐