使用systemctl启动java服务时,时区错误
问题:
使用start.sh脚本启动服务时(即java -jar)服务一切正常,但是把程序部署为系统服务(使用systemctl 启动)后,出现了时间格式化后与实际时间相差8小时的问题,那肯定是时区问题了。
先上结论:
-
使用
timedatectl
来确认时区,使用timedatectl set-timezone Asia/Shanghai
来修改时区。 -
date -R
以及其他命令、脚本会使用profile文件中定义的系统变量,但是systemctl
不会,这可能导致系统参数不一致。
排查过程:
$ date -R
Tue, 01 Aug 2022 18:04:33 +0800
看起来系统时区是正确的...于是陷入了沉思😔(实际这里不应该使用该命令确认时区)
由于问题只出现在systemctl模式下,其实基本可以排除java服务本身配置问题,但为了保险起见,还是确认一下。java服务开启了actuator端点监控,可以直接通过浏览器查看当前生效的参数:
http://10.0.24.125:9004/actuator/env/user.timezone
{
"property": {
"source": "systemProperties",
"value": "Etc/UTC"
},
"activeProfiles": [],
"propertySources": [
...
{
"name": "systemProperties",
"property": {
"value": "Etc/UTC"
}
},
...
]
}
可以看到,当前user.timezone
参数的值确实是错误的(Etc/UTC),参数配置来源于系统配置(systemProperties)。切换成脚本启动后,值就变成正确的"Asia/Shanghai"了。
看来配置没问题,问题还是出在系统上。
于是再查看一下profile文件
$ cat /etc/profile
...
export TZ='Asia/Shanghai'
...
发现这里有一个系统变量设置,但也没有感觉异常(实际这里就是罪魁祸首)
辗转查询资料,发现linux有一个新命令timedatectl
可以用于方便的设置时区,于是:
$ timedatectl
Local time: Tue 2022-08-01 18:13:33 CST
Universal time: Tue 2022-08-01 10:13:33 UTC
RTC time: Tue 2022-08-01 10:13:33
Time zone: UTC
System clock synchronized: yes
systemd-timesyncd.service active: yes
RTC in local TZ: no
该命令返回的时区是UTC,跟上面date -R
并不一致。🤯
实际上最准确的系统的时区应该这样看:
$ ls -lrt /etc/localtime
lrwxrwxrwx 1 root root 33 Aug 1 09:55 /etc/localtime -> /usr/share/zoneinfo/UTC
但是date
命令或者直接执行java -jar
等命令时,会读取profile文件中的系统变量,此时export TZ='Asia/Shanghai'
会生效,但是systemctl
不会读取profile文件内容,所以会取到系统实际时区(UTC),导致上述问题。
所以修改时区时,最好不要使用profile文件,而是将/etc/localtime软连接到/usr/share/zoneinfo下的一个时区,或者使用timedatectl set-timezone Asia/Shanghai
来修改更方便。