暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OB 主机时间回退和夏令时问题测试

1167
OB 官方论坛上有个关于 OB 主机时间回退的问题 ,这个很有趣。于是我测试了一下,有兴趣的可以看看。

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/localtime
    lrwxrwxrwx 1 root root 36 Nov 2 03:05 etc/localtime -> usr/share/zoneinfo/America/New_York


    [root@server20 ]# date -R
    Thu, 02 Nov 2023 03:16:06 -0400
    [root@server20 ]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbase
    Welcome to the MariaDB monitor. Commands end with ; or \g.
    Your MySQL connection id is 5
    Server 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 -R
      Sun, 05 Nov 2023 01:59:02 -0400
      [root@server20 ]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbase
      Welcome to the MariaDB monitor. Commands end with ; or \g.
      Your MySQL connection id is 12
      Server 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 -R
        Sun, 05 Nov 2023 01:00:39 -0500
        [root@server20 ]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbase
        Welcome to the MariaDB monitor. Commands end with ; or \g.
        Your MySQL connection id is 13
        Server 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 -R
            Sun, 05 Nov 2023 03:13:38 -0500
            [root@server20 /]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbase
            Welcome to the MariaDB monitor. Commands end with ; or \g.
            Your MySQL connection id is 6
            Server 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 -R
              Sun, 05 Nov 2023 02:13:03 -0500
              [root@server20 /]# mysql -h127.1 -uroot@sys#obcedemo -P2883 -paaAA11__ -c -A oceanbase
              Welcome to the MariaDB monitor. Commands end with ; or \g.
              Your MySQL connection id is 7
              Server version: 5.6.25


              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%';
              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小时的偏差。

              理解不当的地方,欢迎点开 “阅读原文” 在论坛里讨论。

              文章转载自数据库技术闲谈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论