【问题标题】:PHP microtime() drift, External NTP servicePHP microtime() 漂移,外部 NTP 服务
【发布时间】:2014-03-14 12:18:12
【问题描述】:

我正在为我的云托管服务器上的问题寻找解决方案,结果从 microtime(true) 返回;在几分钟内的通话之间非常准确,但在一两天内会漂移近一秒。我正在使用此结果在异步连接的客户端之间进行同步,如果可能的话,我需要在

我知道这可能被认为是题外话,但我能想到的当前最佳选择是定期轮询一些外部服务并以毫秒为单位获取当前 NIST 时间。不幸的是,我似乎找不到任何人提供这项服务。如果需要,我将自己设置具有可靠时间响应的第二台服务器并对其执行 ping 操作,但似乎必须有人在那里解决这个简单的需求。有人知道吗?

【问题讨论】:

    标签: php web-services time ntp


    【解决方案1】:

    我找到了以下服务:

    http://currentmillis.com/api/millis-since-unix-epoch.php

    请记住,对于任何寻求类似解决方案的人来说,网络延迟和一般不可预测的因素肯定会使返回值偏离真实时间。您必须将这些影响因素考虑在内!


    更新:

    在使用上述服务几天后,很明显我需要比当前托管的连接更高的可靠性。我的解决方案是构建一个基于 PHP 的客户端,通过与附近 NTP 服务器的直接套接字连接来实现。在典型的通话中,我的往返时间大约为 7 到 15 毫秒。

    您的结果可能会有所不同,具体取决于您自己的服务器以及您选择的 NTP 提供商。您可以找到第 2 层服务器 here,以及使用 general pool。正如这些其他帖子中提到的,不要不断地轮询这些提供商,而是限制您的呼叫并根据呼叫时间进行调整。

    这是我的“客户”代码:

    function RemoteNTP($Host) {
        $Sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);  // Create socket
        socket_connect($Sock, $Host, 123);  // Connect over port 123 for NTP
        $Str = "\010" . str_repeat("\0", 47);  // Create string for binary transmission
        $Trip -= round(microtime(true)*1000);  // Grab time of call
        socket_send($Sock, $Str, strlen($Str), 0);  // Send transmission
        socket_recv($Sock, $Response, 48, MSG_WAITALL);  // Receive formatted response
        $Trip += round(microtime(true)*1000);  // Adjust call time variable
        socket_close($Sock);  // Close socket
        $Data = unpack('N12', $Response);  // Format as an array we can work from
        $Secs = $Data[11]-2208988800;  // Convert to secs since 1970, from 1900 for NTP
        $Frac = $Data[12]/4294967296;  // Fraction of sec, out of 2^32 (32 bits)
        $Time = ($Secs*1000)+round($Frac*1000);  // Combine for full ms value
        $Time += round($Trip/2);  // Measure and adjust this for better accuracy
        return $Time;  // Returns number of milliseconds passed since 1970-01-01
    }
    

    可以这样调用:

    $Ntp = GetRemoteNTP('0.pool.ntp.org');
    

    您将根据持续检查来调整 $Trip 的修饰符,从而确定每次通话的往返时间的实际值,从而获得更准确的行程时间。 (我实际上详细跟踪了我的,但想以模块化的方式发布它,并将跟踪机制的选择留给实施者。)您将通过磨练靠近您的服务器的 NTP 提供程序来提高可靠性,但是如果利用池,您可能还希望通过将 # 的 0-4 附加到主机 url 并为每个请求循环来“循环”您对池服务器的调用。

    另外请记住,这应该被视为最后的解决方案。 NTP 框架经过精心设计,成为一个强大而全面的系统,用于维护非常准确的系统时间。这是一种低级的、自我纠正的机制,它比像这样的自制 hack 做得更好。由于我的具体情况,我采用了这里使用的方法;系统时钟中可能有更好的替代方案可供您使用,通过 nptd 自动调整。

    【讨论】:

    • 为了获得更好的结果,您需要选择一个 ntp 服务器,而不是使用随机池服务器。我不敢相信您实际上获得了 +/- 10 毫秒。您多久轮询一次主机?
    • 你当然是对的。正如我上面提到的,我实际上是在轮询一个与我的服务器物理距离相对较近的单个 NTP 服务器。我只是不想在示例中发布特定的 URI。我确实提供了一个链接,以便人们可以为自己找到特定的第 2 层服务器。信不信由你;在我当前的设置中,$Trip 的典型响应时间实际上是 6 毫秒,与代码中的测量完全一致。我每小时轮询一次,以纠正我正在使用的主机上的时间漂移​​。
    【解决方案2】:

    如果您在服务器上安装 NTP,您的服务器上的精度可能会在 10 毫秒以内。这取决于您的服务器和您的参考之间的网络距离以及该路由上的网络负载。如果您对某些服务发出 HTTP 请求,您将很幸运能够在 200 毫秒内获得时间。如果您希望您的客户在 10 毫秒内获得准确的参考时间,他们将需要安装 NTP,然后他们可能实现您的目标。本地 GPS 参考将是获得该精度的唯一可靠方法。

    【讨论】:

    • 谢谢迈克。我意识到网络延迟会产生很大的影响,但我发现对服务器的调用通常会因一致的相似值而关闭,因此我将这些差异纳入我的计算中。我已经对其进行了磨练,因此结果在调用本身的几毫秒内检查出来,却发现服务器时间本身正在漂移。如果我能找到响应时间相当一致的服务,它应该满足我的需求,因为我也在测量往返时间。
    【解决方案3】:

    高精度时钟同步会出现问题,尤其是在虚拟化环境中。这正是建议不要在虚拟环境中运行 Kerberos/Windows 域控制器的确切情况,因为它们倾向于高时钟漂移。

    也就是说,正确的答案当然是不要以任何形式向 NIST 发送垃圾邮件,因为他们提供 NTP 服务出于礼貌,并且肯定会阻止您进行过多的查询。

    应该做的是询问您的 ISP 是否有 NTP 服务器,您可以使用它来主动同步您的时钟,理想情况下是第 1 层或第 2 层服务器,并将您的所有机器都指向该服务器.如果没有,请设置您自己的第 2 层服务器 [最好在金属上,而不是虚拟上] 并使用它。

    一旦您拥有合适的 NTP 服务器,只需配置 ntpd 以从该服务器上足够频繁地更新您的时钟,这样您最终不会漂移超过 10 毫秒的限制。

    但实际上,我无法摆脱这样一种感觉,即要求这些不同的时钟如此紧密地同步是设计选择不佳的表现。您能不能简单地将这些“异步客户端”的调度信息发送为“从现在开始 X 微秒”而不是将来的完整时间戳?

    【讨论】:

    • 您对我的设计选择以及驱动它们的环境做出了错误的假设。我不打算向 NIST 或其他任何人发送垃圾邮件,而只是设置一个 cron 作业以每小时左右对它们进行 ping 操作,并相应地调整我的计算。实际上,我已经按照您的建议向我的主机请求了本地 NTP 访问权限,并且只是想在等待回复时在这里问,因为这似乎是一个可能对其他人也有帮助的问题。不过感谢您的意见,我同意如果他们无法提供解决方案,最好为这项工作设置我自己的机器。
    猜你喜欢
    • 2019-10-18
    • 1970-01-01
    • 2016-10-07
    • 2011-08-12
    • 1970-01-01
    • 2020-05-26
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多