On Date/Timestamp Value in A Distributed System

来源:互联网 发布:扫描网络摄像头ip 编辑:程序博客网 时间:2024/06/16 02:41

关于分布式系统中日期或时间戳类型

最近,在TDH上使用Inceptor查询Date或Timestamp类型的字段,多次遇到返回值不稳定或者错误的问题。主要有两种问题表象:

  • 某些特殊Date类型的日期,会多出时分秒,且都是“01:00:00”
  • Date/Timestamp类型字段经存储过程,输出结果错误并且不稳定
    下面将逐一讲解。

开启DST,JVM会给DST开始日零点往前拨一小时

经过多次范围缩小,最终锁定整个数据集中只有某几个日期会多出时分秒,而且都是多了一小时。如:

...1988-04-10 --> 1988-04-10 01:00:001991-04-14 --> 1991-04-14 01:00:00...

查找了相关资料后,发现了DST(Daylight Saving Time)。

1986年至1991年,中华人民共和国在全国范围实行了六年夏时制。

经过zdump检查,确实操作系统开启了DST:

hadooptest4: # zdump -v /etc/localtime | grep 1988/etc/localtime Sat Apr 9 15:59:59 1988 UT = Sat Apr 9 23:59:59 1988 CST isdst=0 gmtoff=28800/etc/localtime Sat Apr 9 16:00:00 1988 UT = Sun Apr 10 01:00:00 1988 CDT isdst=1 gmtoff=32400/etc/localtime Sat Sep 10 14:59:59 1988 UT = Sat Sep 10 23:59:59 1988 CDT isdst=1 gmtoff=32400/etc/localtime Sat Sep 10 15:00:00 1988 UT = Sat Sep 10 23:00:00 1988 CST isdst=0 gmtoff=28800

这表明,1988年4月10日零点来临之时,由于实施夏时制,即DST,时钟会自动往前拨一小时,这才导致了Date类型值多出时分秒的错误。

但是,设置关闭DST时,遇到了另一个打破常识的说法:Etc/GMT-8等价于平时说的UTC+8或GMT+8。参考tz database

In the “Etc” area, zones west of GMT have a positive sign and those east have a negative sign in their name (e.g “Etc/GMT-14” is 14 hours ahead/east of GMT.)

所以最终的解法就是关闭所有JVM程序,设置不带DST的时区,再重启程序:

# cp /etc/localtime /etc/localtime.bk# ln /usr/share/zoneinfo/Etc/GMT-8 -sf /etc/localtime

各节点时区设置不一致,Date/Timestamp值不稳定

在分布式系统中,需要尽量保证各节点的配置相同,不然容易引发一些匪夷所思的问题。时区设置就是一点,纵使设置成中国不同的城市,也会有细微的不同。这个问题来自于一个很平常的日期:

unstable1
以20170918为过滤条件,出现大量20170917

unstable2
并且同一句SQL,返回值是不一样的,20170917也有多有少。

首先排除了DST的原因:

  • 2017年已经不实行夏时制
  • 即使有夏时制,9月18日也不属于开始日(零时往前拨一个小时),结束日(一时往回拨到零时

经过代码检查,发现各节点的时区大不相同:

import java.util.TimeZone;System.out.println("TimeZone: " + TimeZone.getDefault());

Different Timezone

从上图可以看出,节点间存在相差16个小时的问题,这也是之前不了解Etc的特点,用Etc/GMT+8关闭DST留下的问题。

值得注意的是,统一修改成Etc/GMT+8和ntp同步时间后发现时间不对,又修改回PRC(UTC+8/中国标准时区CST),但此后通过上述代码检查,仍旧出现时区不一致的问题。暂时无法解释此现象
但是重新修改系统的/etc/localtime,并保证/etc/sysconfig/clock内容一致能解决这个问题。

最后,附上修改过程:

echo 'show current system time'dateecho 'rm /etc/localtime'rm -rf /etc/localtimeecho 'show current UTC time'dateecho 'link localtime to Etc/GMT-8'ln /usr/share/zoneinfo/Etc/GMT-8 -sf /etc/localtimeecho 'sync time from NTP server'sntp -r 88.3.224.1echo 'show current system time'dateecho 'check timezone'java -cp /root/test-date-1.0.0.jar io.transwarp.test.TestDateecho 'adjust and unify /etc/sysconfig/clock'echo 'set HWCLOCK to "--localtime"'sed -i 's/HWCLOCK=.*/HWCLOCK="--localtime"/g' /etc/sysconfig/clockecho 'set SYSTOHC to "yes"'sed -i 's/SYSTOHC=.*/SYSTOHC="yes"/g' /etc/sysconfig/clockecho 'set TIMEZONE and DEFAULT_TIMEZONE to "Asia/Beijing"'sed -i 's/TIMEZONE=.*/TIMEZONE="Asia\/Beijing"/g' /etc/sysconfig/clockecho 'set system time back to hardware clock'hwclock -wecho 'show hwclock and hwclock --localtime'hwclock && hwclock --localtimeecho 'check timezone'java -cp /root/test-date-1.0.0.jar io.transwarp.test.TestDate

参考文章:

  • Disable Daylight Saving Time (DST) Changes in Linux
  • Daylight saving time and time zone best practices
  • SUSE Linux时间服务器及客户端同步配置
  • Linux时钟介绍和修改系统时间
  • linux系统时间和硬件时钟问题(date和hwclock)
阅读全文
0 0
原创粉丝点击