https://ask.oceanbase.com/t/topic/35605237/11
原问题是将 OB 主机时间回退了一个小时,一个表查询异常了。
这个是由于OB的在计算当前版本号跟时间戳有关。时间回退了一个小时,当前时间戳也回退了。读是MVCC读,有些表数据就不能正常读。此时 OB 也会有部分异常。
如果这个时间是必须回退的(目的是纠正此前错误的时间),那么此时最简单最稳妥的解决方案就是将这个 OB 集群停掉,静待时间的推进到之前的错误时间点。这个用户的 Case 就是等一个小时。然后再把 OB 集群拉起来,自然就恢复了。我们可能感觉过了一个小时,对于 OB 而言,可能就过去几秒而已。
紧接着有用户问,那美国夏令时怎么办。他指的是夏令时结束时,时间也会回退一个小时,那天就多了”一小时“。
答案肯定是 夏令时不影响 OB 。原因我们先测试看看。
设置时区为支持夏令时的时区
2023年夏令时结束时间是 2023-11-05 02:00:00 AM 。也快到了,不过测试等不及,直接调整测试服务器的时间,同时也更改主机时区。
修改结果如下:
[root@server20 ]# ll etc/localtimelrwxrwxrwx 1 root root 36 Nov 2 03:05 etc/localtime -> usr/share/zoneinfo/America/New_York[root@server20 ]# date -RThu, 02 Nov 2023 03:16:06 -0400[root@server20 ]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbaseWelcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 5Server version: 5.6.25 OceanBase_CE 4.2.0.0 (r100010022023081817-0bdf1c0c5674e88c5ae9a8d0ae4f8077465d7fae) (Built Aug 18 2023 17:32:49)MySQL [oceanbase]> set session time_zone='-04:00';Query OK, 0 rows affected (0.00 sec)MySQL [oceanbase]> select time_to_usec(current_timestamp),current_timestamp;+---------------------------------+---------------------+| time_to_usec(current_timestamp) | current_timestamp |+---------------------------------+---------------------+| 1698909382000000 | 2023-11-02 03:16:22 |+---------------------------------+---------------------+1 row in set (0.00 sec)
OB 4.2 会话还不支持设置时区为 ‘America/New_York’ ,只好换种方式设置('-04:00')。
推进时间到夏令时结束前的一分钟
将时间推进到夏令时结束前一分钟。
[root@server20 ]# date -s "2023-11-05 01:59:00"Sun Nov 5 01:59:00 EDT 2023[root@server20 ]# date -RSun, 05 Nov 2023 01:59:02 -0400[root@server20 ]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbaseWelcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 12Server version: 5.6.25 OceanBase_CE 4.2.0.0 (r100010022023081817-0bdf1c0c5674e88c5ae9a8d0ae4f8077465d7fae) (Built Aug 18 2023 17:32:49)MySQL [oceanbase]> select time_to_usec(current_timestamp),current_timestamp;+---------------------------------+---------------------+| time_to_usec(current_timestamp) | current_timestamp |+---------------------------------+---------------------+| 1699163947000000 | 2023-11-05 01:59:07 |+---------------------------------+---------------------+1 row in set (0.01 sec)MySQL [oceanbase]> show variables like '%time_zone%';+------------------+--------+| Variable_name | Value |+------------------+--------+| system_time_zone | +08:00 || time_zone | -04:00 |+------------------+--------+2 rows in set (0.00 sec)
等夏令时结束
静待1分钟,等夏令时结束。
[root@server20 ]# date -RSun, 05 Nov 2023 01:00:39 -0500[root@server20 ]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbaseWelcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 13Server version: 5.6.25 OceanBase_CE 4.2.0.0 (r100010022023081817-0bdf1c0c5674e88c5ae9a8d0ae4f8077465d7fae) (Built Aug 18 2023 17:32:49)Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.MySQL [oceanbase]> show variables like '%time_zone%';+------------------+--------+| Variable_name | Value |+------------------+--------+| system_time_zone | +08:00 || time_zone | -04:00 |+------------------+--------+2 rows in set (0.00 sec)MySQL [oceanbase]> select time_to_usec(current_timestamp),current_timestamp;+---------------------------------+---------------------+| time_to_usec(current_timestamp) | current_timestamp |+---------------------------------+---------------------+| 1699164048000000 | 2023-11-05 02:00:48 |+---------------------------------+---------------------+1 row in set (0.00 sec)
过了 01:59:59 后,时区 America/New_York 自动调整时间偏差为 '-05:00' 。此时时间展现值回退了一个小时。这个就是”时间回退1小时”的原理,即只是时区变了,导致时间的展示结果变了。
MySQL [oceanbase]> set session time_zone='-05:00';Query OK, 0 rows affected (0.00 sec)MySQL [oceanbase]> select time_to_usec(current_timestamp),current_timestamp;+---------------------------------+---------------------+| time_to_usec(current_timestamp) | current_timestamp |+---------------------------------+---------------------+| 1699164058000000 | 2023-11-05 01:00:58 |+---------------------------------+---------------------+1 row in set (0.00 sec)
不过,OB 实例由于时区不支持 'America/New_York' 那种设置方法,所以这里时区的时间偏差不会从 '-04:00'变为'-05:00' ,需要自己手动设置一下。
这个时候查一下时间戳和当前时间戳。时间展现值是回退了一个小时,但是时间戳的值(1699164058000000)依然是再增长(比 1699163947000000 大)。
所以,夏令时时区的切换引起时间展示结果的回退,并不会引起 OB 时间戳的变化,OB 的功能都是正常的。就是这个手动设置稍微麻烦一点,需要到点精准执行,否则会引起业务逻辑的不正常(业务取数据库时间错误)。
我们再看看手动将 OB 主机时间回退 1小时如何。
OB 主机时间回退
为了不在回退的时候再次回到夏令时将问题搞复杂了,我将时间再往前推进一下。
[root@server20 ]# date -s "2023-11-05 03:10:00"Sun Nov 5 03:10:00 EST 2023<....>[root@server20 /]# date -RSun, 05 Nov 2023 03:13:38 -0500[root@server20 /]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbaseWelcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 6Server version: 5.6.25 OceanBase_CE 4.2.0.0 (r100010022023081817-0bdf1c0c5674e88c5ae9a8d0ae4f8077465d7fae) (Built Aug 18 2023 17:32:49)Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.MySQL [oceanbase]> show variables like '%time_zone%';+------------------+--------+| Variable_name | Value |+------------------+--------+| system_time_zone | +08:00 || time_zone | -05:00 |+------------------+--------+2 rows in set (0.00 sec)MySQL [oceanbase]> select time_to_usec(current_timestamp),current_timestamp;+---------------------------------+---------------------+| time_to_usec(current_timestamp) | current_timestamp |+---------------------------------+---------------------+| 1699172022000000 | 2023-11-05 03:13:42 |+---------------------------------+---------------------+1 row in set (0.00 sec)
然后将时间再次回退 1 小时。
[root@server20 /]# date -s "2023-11-05 02:13:00"Sun Nov 5 02:13:00 EST 2023[root@server20 /]# date -RSun, 05 Nov 2023 02:13:03 -0500[root@server20 /]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbaseWelcome to the MariaDB monitor. Commands end with ; or \g.Your MySQL connection id is 7Server version: 5.6.25Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.MySQL [oceanbase]> show variables like '%time_zone%';ERROR 4012 (HY000): Timeout, query has reached the maximum query timeout: 10000000(us), maybe you can adjust the session variable ob_query_timeout or query_timeout hint, and try again.MySQL [oceanbase]> select time_to_usec(current_timestamp),current_timestamp;ERROR 4012 (HY000): Timeout, query has reached the maximum query timeout: 10000000(us), maybe you can adjust the session variable ob_query_timeout or query_timeout hint, and try again.MySQL [oceanbase]> select /*+ query_timeout(1000000000000000) */ time_to_usec(current_timestamp),current_timestamp;+---------------------------------+---------------------+| time_to_usec(current_timestamp) | current_timestamp |+---------------------------------+---------------------+| 1699168395000000 | 2023-11-05 02:13:15 |+---------------------------------+---------------------+1 row in set (0.00 sec)
看这个时间戳 1699168395000000 比前面的 时间戳 1699172022000000 要小了。此时 OB 查询报超时了,估计是内部在计算 sql 执行时间时候用的两个值,其中一个减数受时间回退影响了,导致结果超出正常的时间。用 HINT 规避一下展示出这个时间戳 结果是变小了。
所以,OB 主机时间如果因为调整时间值,回退很大幅度,OB 时间戳计算也会出现回退,这个就会引起 OB 内部异常。
总结
OB 主机时间如果被修改出现大幅回退,OB 时间戳值也会回退,这个会引起 OB 内部异常。如果是生产环境时间必须回退(修正此前错误的时间),一个解决办法就是停止OB集群,静待时间自然推进到之前的错误时间。如果这个时间回退的幅度很大,这个方法就无法接受。那只能现在错误时间里 OB集群正常的时候 逻辑导出 OB 数据,然后修正 OB 主机时间,重搭 OB 集群再导入业务时间。
这些都是事后补救的方案。最好的做法是在部署OB前,就严格按照官方文档要求,将操作系统的各项检查和配置都做好。其中就包括时间同步服务。
至于夏令时结束引起的时间回退只是因为时区的变化引起的表象,不会对 OB 的运行带来影响。不过 OB 租户目前对于非中国时区的支持还不完善,夏令时的结束还需要 OB 运维在那一刻准时调整租户的时区参数。否则,业务逻辑里涉及到时间的部分就会出现 1小时的偏差。
理解不当的地方,欢迎点开 “阅读原文” 在论坛里讨论。




