书接上文,《实现MySQL大表定时同步到Doris的Shell脚本》上回讲到MySql数据同步到Doris,使用shell脚本实现。
这次开发同事又反馈了一个棘手的问题:mysql数据源在遥远的印尼,与中国时区相差1小时。flink cdc读取binlog解析出问题了。
报错信息如下:
The MySQL server has a timezone offset (25200 seconds ahead of UTC)
which does not match the configured timezone Asia/Shanghai.
Specify the right server-time-zone to avoid inconsistencies for time-related fields.
本着遇事先不慌原则,不懂问AI。很快我们就获得了一个靠谱的答案:
这个警告信息非常关键,它明确指出了 Flink CDC 与 MySQL 服务器之间存在时区配置不一致的问题,必须解决,否则会导致时间相关字段(TIMESTAMP, DATETIME)的数据不一致甚至错误。
警告信息解读
- The MySQL server has a timezone offset (25200 seconds ahead of UTC):
- Flink CDC 在连接 MySQL 服务器时,探测到服务器报告的时区偏移量是 +25200 秒。
- 25200 秒 = 7 小时。这表明 MySQL 服务器当前运行在 UTC+7 时区(例如:Asia/Jakarta - 印尼雅加达时间)。
- which does not match the configured timezone Asia/Shanghai:
- 你在 Flink CDC 的配置中,通过 serverTimeZone("Asia/Shanghai") 参数,告诉 Flink CDC 你认为 MySQL 服务器运行在 UTC+8 时区(中国标准时间)。
- Specify the right server-time-zone to avoid inconsistencies...:
- Flink CDC 发现了这个矛盾,因此发出警告,提醒你配置了错误的 serverTimeZone,这会导致时间字段处理不一致。
问题根源
Flink CDC 需要准确知道 MySQL 服务器的时区,才能正确解析 binlog 中的时间信息,尤其是 TIMESTAMP 类型:
- TIMESTAMP 存储:MySQL 内部将 TIMESTAMP 值转换为 UTC 时间戳存储。
- TIMESTAMP 检索:当从数据库读取 TIMESTAMP 时,MySQL 会根据服务器的 time_zone 设置,将 UTC 时间戳转换回本地时间。
- Flink CDC 解析:Flink CDC 读取 binlog 时,看到的是经过 MySQL 服务器时区转换后的“本地时间”值。它需要利用 serverTimeZone 配置,将这个“本地时间”逆向转换回正确的 UTC 时间戳或标准时间,然后传递给 Flink 流。
- 错误配置的后果:
- 你配置了 serverTimeZone("Asia/Shanghai") (UTC+8),但实际服务器是 UTC+7。
- Flink CDC 会错误地认为 binlog 中的时间是 UTC+8 的本地时间。
- 当它进行“逆向转换”时,会减去 8 小时,而实际上应该减去 7 小时。
- 结果:解析出的时间值会比正确值早 1 小时!例如,MySQL 中存储的 2023-10-01 10:00:00 (UTC+7) 会被 Flink 解析为 2023-10-01 09:00:00 (UTC) 或 2023-10-01 17:00:00 (UTC+8),造成严重错误。
解决方案
必须将 Flink CDC 配置中的 serverTimeZone 修改为与 MySQL 服务器实际时区一致的值。
步骤 1: 确认 MySQL 服务器的实际时区
在 MySQL 服务器上执行:
-- 查看全局时区设置
SELECT @@global.time_zone;
-- 查看当前会话时区设置
SELECT @@session.time_zone;
-- 查看系统时区(可能受操作系统影响)
SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP());步骤 2: 修正 Flink CDC 配置
将代码中 serverTimeZone("Asia/Shanghai") 修改为正确的时区。
方法一:使用时区名称 (推荐)
MySqlSource.builder()
.hostname("your-mysql-host")
.port(3306)
.databaseList("your_db")
.tableList("your_db.your_table")
.username("user")
.password("password")
// ✅ 修正:使用 MySQL 服务器实际的时区名称
.serverTimeZone("Asia/Jakarta") // 适用于印尼 (UTC+7)
// 如果是其他 UTC+7 时区,使用对应名称,如 "Asia/Bangkok" (泰国)
// ... 其他配置
.build(); 方法二:使用偏移量 (UTC+7)
// ✅ 修正:使用正确的偏移量 .serverTimeZone("+07:00")步骤 3: 重启 Flink 作业
修改配置后,需要重启 Flink CDC 作业,使新的 serverTimeZone 配置生效。
为什么不能忽略这个警告?
- 数据错误:如上所述,会导致 TIMESTAMP 字段的时间值错误(通常偏差1小时)。
- DATETIME 字段的间接影响:虽然 DATETIME 存储的是字面量,但如果数据是通过 NOW() 函数插入的,那么存入的 DATETIME 值本身就代表了服务器本地时间。Flink CDC 需要知道这个“本地时间”的时区含义,才能正确理解其语义。虽然 CDC 会原样同步这个字面量,但下游应用(如 Doris)可能需要知道这个时间的时区背景。
- 未来风险:如果表结构未来增加了 TIMESTAMP 字段,问题会立刻暴露。
- 最佳实践:保持配置与实际环境一致是稳定运行的基础。
总结
这个警告是 Flink CDC 在保护你!它发现了配置错误。不要忽略它。
立即行动:
- 登录 MySQL 服务器,确认其 time_zone 设置。
- 将 Flink CDC 代码中的 .serverTimeZone("Asia/Shanghai") 修改为 .serverTimeZone("Asia/Jakarta") 或 .serverTimeZone("+07:00")。
- 重启 Flink 作业。
完成这些步骤后,警告将消失,时间字段的同步也将变得准确可靠。
你是不是以为到此就结束了?事情远没有这么简单,我们的开发同事看了这个方案,想了想,又要改配置,那就必须升级重启服务,那还得走一波流程。有没有躺着就能赢的?

so... 接下来,我得重新找回来刚在doris服务器删除的脚本。但是这次开发提了一个更高的要求:

30秒一次,显然之前的crontab是不行了,有同学可能要问:
❌ 为什么 crontab 不支持每秒?
crontab 的时间粒度最小是 分钟(minute)。它的格式是:
* * * * * command
│ │ │ │ │
│ │ │ │ └── 星期几 (0-7, 0 or 7 = Sunday)
│ │ │ └──── 月份 (1-12)
│ │ └────── 日期 (1-31)
│ └──────── 小时 (0-23)
└────────── 分钟 (0-59)
它没有“秒”这一列,所以无法直接实现“每30秒运行一次”。
既然此路不通,那我们就换一条路走呗:
✅ 如何实现“每30秒执行一次”?
虽然 crontab 本身不支持,但可以通过以下几种方式间接实现:
✅ 方法 1:使用 sleep 在脚本内部循环
创建一个脚本,每秒执行一次某个命令:
#!/bin/bash
# save as /path/to/your/secondly_script.sh
while true; do
# 在这里放你每30秒要执行的命令
echo "执行任务 $(date)" >> /tmp/secondly.log
# 等待 30 秒
sleep 30
done然后在 crontab 中每分钟启动一次这个脚本(如果它还没在运行):
* * * * * /usr/bin/pgrep -f secondly_script.sh > /dev/null || /path/to/your/secondly_script.sh &
✅ 优点:简单、可靠、资源占用低。 ⚠️ 注意:确保脚本能正确处理重启、日志轮转、避免多个实例冲突。
✅ 方法 2:使用 systemd 定时器(更现代的方式)
systemd 支持秒级精度。
- 创建服务文件 /etc/systemd/system/my-secondly-task.service:
[Unit]
Description=My Secondly Task
[Service]
Type=oneshot
ExecStart=/path/to/your/command.sh- 创建定时器文件 /etc/systemd/system/my-secondly-task.timer:
[Unit]
Description=Run my task every 30 second
[Timer]
OnUnitInactiveSec=30
AccuracySec=1s
Persistent=true
# 可选:启动时延迟多久开始第一次触发(避免系统启动风暴)
OnBootSec=10s
# 可选:系统启动后多久开始触发(从系统启动算起)
OnStartupSec=15s
[Install]
WantedBy=timers.target- 启用并启动:
sudo systemctl daemon-reload
sudo systemctl enable my-secondly-task.timer
sudo systemctl start my-secondly-task.timer
✅ 优点:系统级支持,日志、重启、依赖管理完善。 📌 推荐用于现代 Linux 系统。




