分两层:JVM 系统时区(日志时间、进程时区) + Flink SQL 业务时区(CDC 时间解析)
主要场景:MySQL CDC 同步,推荐两个都配置成
Asia/Shanghai
方式 1:修改 flink-conf.yaml(全局永久生效,推荐,standalone 集群)
文件路径:flink-2.2.1/conf/flink-conf.yaml
# ========== JVM时区(控制日志打印时间、JVM默认时区,解决log里面时间是UTC) ==========
env.java.opts.jobmanager: -Duser.timezone=Asia/Shanghai
env.java.opts.taskmanager: -Duser.timezone=Asia/Shanghai
# ========== Flink SQL Table API 业务时区(CDC、TIMESTAMP_LTZ、时间函数) ==========
table.local-time-zone: Asia/Shanghai
修改后重启整个 Flink 集群(JM+TM) 才生效。
方式 2:提交任务时动态传参(只对当前 job 生效,不用改配置文件)
flink run -yD env.java.opts.taskmanager="-Duser.timezone=Asia/Shanghai" \
-yD table.local-time-zone=Asia/Shanghai \
your-jar.jar
SQL-Client 方式(会话级别):
SET 'table.local-time-zone' = 'Asia/Shanghai';
方式 3:直接修改 Linux 服务器系统时区(治本,所有进程默认继承)
# 查看当前时区
date -R
# 修改为上海时区
timedatectl set-timezone Asia/Shanghai
# 老系统兼容写法
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo "Asia/Shanghai" > /etc/timezone
⚠️ 注意:容器部署 Flink,容器内部时区独立,要进容器修改时区或者镜像内置时区。
✅ 针对【MySQL CDC 额外必加参数】(非常关键,时间差 8 小时高频坑)
在 MySQL CDC source 的 WITH 配置里增加:
WITH (
'connector' = 'mysql-cdc',
'hostname' = 'xxx',
'port' = '3306',
'username' = 'xxx',
'password' = 'xxx',
'database-name' = 'xxx',
'table-name' = 'xxx',
'server-time-zone' = 'Asia/Shanghai' -- 告诉debezium MySQL库的时区!
);
server-time-zone是 Debezium 解析 binlog 时间的时区,和 flink JVM 时区分开控制,漏配极易出现 datetime/timestamp 相差 8 小时。
验证是否生效
看日志:
flink-root-taskexecutor-*.log打印的日志时间是否变成 + 8 北京时间SQL 里校验:
SET 'table.local-time-zone' = 'Asia/Shanghai';
SELECT PROCTIME(), CURRENT_TIMESTAMP;
JVM 时区校验(在 TM 机器执行)
java -Duser.timezone=Asia/Shanghai -XshowSettings:properties -version 2>&1 | grep user.timezone
区分两个容易混淆的时区(重点)
-Duser.timezone=Asia/Shanghai→ JVM 时区:控制日志打印、Java 底层时间 APItable.local-time-zone→ Flink SQL 引擎时区:控制TIMESTAMP_LTZ、时间函数、窗口、watermarkserver-time-zone(cdc source)→ MySQL 数据库时区:binlog 里 datetime/timestamp 解析规则
你的现象:日志时间是 UTC,优先配置
env.java.opts.taskmanager;如果同步出来的字段时间差 8 小时,优先检查 CDC 的server-time-zone。
补充避坑
不要写 GMT+8,优先标准 Asia/Shanghai;GMT+8 在 Java 里部分版本会识别成 CST(美国中部时间,负 5 区),踩经典时区 bug。