问题出现得很突然,日志倒是留得挺全。CentOS 7 上 timedatectl set-timezone Asia/Shanghai 之后 date 显示 CST,Java 服务日志却还是 UTC,差八小时,排查发现进程环境里 TZ=UTC。
排查方向其实有限,先把可能性排一排。unit 文件或 /etc/environment 里显式写了 TZ=UTC,优先级高于 /etc/localtime。还有一种是启动脚本里带了 -Duser.timezone=UTC,JVM 不读系统时区。
不容易想到的是,容器里的 TZ 从父进程继承,镜像里已经写死。
动手时先看进程实际的环境变量
tr '\0' '\n' < /proc/$(pgrep -f app.jar | head -1)/environ | grep '^TZ='
再往下把变量改成需要时区
在 unit 里写 Environment=TZ=Asia/Shanghai
JVM 显式指定时区
java -Duser.timezone=Asia/Shanghai -jar app.jar
从进程内部核对
jcmd $(pgrep -f app.jar | head -1) VM.system_properties | grep user.timezone
当时还开着另一个排查窗口,两边日志对照着看才定位到。
别只看报错消失,验证要多做一步。进程环境里 TZ 为 Asia/Shanghai,jcmd 输出的 user.timezone 一致,日志时间与 date 对齐,接口返回时间与本地时间差值归零。
系统时区、TZ 变量、JVM 参数三层都能决定时间,改一层没效果就看下一层;日志时间统一用带偏移的格式,事后才不会互相打架。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
