在网络世界中, 各个计算机之间要想协同工作, 时间同步是一个十分重要的基础. 在计算机内部是有自己的时间的, 这个时间通过内部的晶体振荡器差生的固定频率, 来模拟时间流逝进行计算. 虽然频率十分稳定, 但也是有误差的, 虽然现在的工艺水平误差已经十分小了. (关于震荡的具体原理, 在此不表)

既然本地时间会产生误差, 那么就会造成两台服务器的时间不一致. 要消除不一致, 就需要有一个统一的时间标准, 然后大家都以这个标准为基准时间并对自己的本地时间进行校准, 既协调国际时(UTC), 关于这个时间是怎么来的, 不是本文讨论的重点.

好了, 现在, 在另一个地方, 有一个标准时间, 如何将这个标准时间通过网络同步到你的本地计算机呢? 如何在同步的过程中, 尽量消除网络延迟带来的影响呢?

HOW

如果直接进行网络请求, 然后拿到一个返回时间戳并修改本地时间可不可以呢? 显然不行. 别忘了, 包在网络中传输也是需要时间的, 这个请求从对方发出, 至到达本地计算机, 经过了多久你并不知道, 这中间的延迟会严重影响时间校准的结果.

OK, 现在遇到的问题就是网络延时了, 如果能够消除网络延迟, 就可以精准同步了, 但以现在的技术水平是做不到的. 既然延时无法消除, 如果我们能够知道这个延时的时间, 也可以通过计算消除延迟的影响.

包在网络中的传输大致如图:

计算机是如何进行时间同步的

其中各值如下:

  • C1: 客户端发出请求的本地时间
  • C2: 客户端接收到返回的本地时间
  • S1: 时间服务器接收到请求的服务器时间
  • S2: 时间服务器发出响应的服务器时间
  • SC1: 客户端发出请求时的服务器时间
  • SC2: 客户端接收到返回的服务器时间
  • CS1: 时间服务器收到请求时的本地时间
  • CS2: 时间服务器发出响应时的本地时间

我们现在的目的看起来很简单, 就是在接受到返回的时候, 将本地时间C2 校准为SC2. 首先要明确的是, C2SC2是不想等的, 否则二者时间相同就不需要校准了嘛.

首先, 我们本地知道的信息有: C1, C2, 可以令服务器在返回结果中, 告诉我们S1, S2. 并且, 我们假定网络中的延时是基本固定的, 既S1-C1=C2-S2.

好了, 现在已经成功的将其转换成了一道数学题. 是不是突然发现简单了许多? 步骤如下:

  • da = (C2 - C1) - (S2 - S1) # 总延时时长
  • d = da / 2 # 单次延时时长
  • SC1 = S1 - d
  • SC2 = SC1 + (C2 - C1)

如何? 很巧妙的将网络延时消除了.

以上, 就是时间同步ntp协议的内容了. 不过, 如此同步的时间也是有误差的, 首先上面就假设了往返的网络延时相同, 如果延时不对称, 则同步结果就会不准确, 而且, 协议跑在应用层, 从物理层到应用层之间的时延也会影响最终结果.

应用

我们在实际实际编程中, 经常会写入类似这样的代码:

$t1 = time();
// do someting...
$t2 = time();

如果, 在获取$t1变量后, 正巧进行了时间同步, 那么$t2有可能小于$t1, 岂不是很诡异. 不过还好, 有不同的同步方式供我们选择, 以下在Ubuntu系统上进行了测试.

  • ntp: 时间平滑过度, 保证本地时间递增, 一点点减少本地与远端的时间差.
  • ntpdate: 立即进行同步, 这种功能情况就可能出现上面$t2小于$t1的场景

不过, 在我的服务器Ubuntu 18上, 已经默认不再使用ntp工具了, 转而使用timedatectl, 其内部协议是一样的, 有关timedatectl的详细内容可以参考一下官网的说明: https://ubuntu.com/server/docs/network-ntp

计算机是如何进行时间同步的

原文连接: https://hujingnb.com/archives/631

相关文章:

  • 2021-10-27
  • 2022-12-23
  • 2022-12-23
  • 2021-10-23
  • 2022-12-23
  • 2021-12-15
  • 2022-12-23
  • 2021-11-20
猜你喜欢
  • 2022-01-25
  • 2021-08-27
  • 2022-01-27
  • 2021-12-05
  • 2021-10-09
  • 2021-09-09
相关资源
相似解决方案