问题描述
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个小时,很明显是时区问题,于是查找官方文档,发现如下配置
Option | Required | Default | Type | Description |
---|---|---|---|---|
server-time-zone | optional | UTC | String | The 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配置。