Pergunta

I am looking for a solution for an issue on my cloud-hosted server where the result returned from microtime(true); is very accurate between calls within a few minutes of each other, but drifts by nearly a second over the course of a day or two. I'm using this result to synchronize between asynchronously connected clients and I need the precision to be accurate to NIST by within <~10ms or so if at all possible.

I know this could be considered off-topic, but the current best option I can think of is to regularly poll some external service and obtain the current NIST time in milliseconds. Unfortunately I can't seem to find anyone offering this service. If I need to I'll just set up a second server with reliable time response myself and ping that, but it seems like there has to be someone out there addressing this simple need. Anybody know of something?

Foi útil?

Solução

I found the following service:

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

Just keep in mind for anyone looking for a similar solution that network latency and general unpredictable factors will definitely skew the returned value away from the true time. You must factor these effects into whatever you're using it for!


Update:

After utilizing the above service for a couple of days, it was clear that I needed a little bit more reliability than was possible through the connection it's currently being hosted on. My solution was to build a PHP-based client, implemented via a direct socket connection to a nearby NTP server. I've been getting round-trip times ranging from roughly 7 to 15 ms on a typical call.

Your results may vary, depending on your own server as well as your choice of NTP provider. You can find stratum 2 servers here, as well as using the general pool. As mentioned in these other posts, do NOT continuously poll these providers, but throttle your calls and adjust according to call time.

Here's my code for the 'client':

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
}

Which can be called like this:

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

You'll get more accurate trip times by tweaking the modifier for $Trip based on ongoing checks to determine the actual values for the out and back times for each call. (I actually track mine in detail but wanted to post this in a modular way and leave the choice of tracking mechanisms open to the implementer.) You'll improve reliability by honing in on a NTP provider in close proximity to your server, but if utilizing the pool you may also want to 'round-robin' your calls to the pool servers by prepending the #'s 0-4 to the host url and cycling for each request.

Also keep in mind that this should be seen as a last-resort kind of solution. The NTP framework has been carefully designed to be a robust and comprehensive system for maintaining very accurate system time. It is a low-level, self-correcting mechanism that will do a much better job than a home-brewed hack like this. I resort to the method used here due to my specific circumstances; there is likely a better alternative available to you in the system clock, auto-adjusted via nptd.

Outras dicas

If you install NTP on your server you might get precision to within 10ms on your server. It depends on the network distance between your server and your reference and the network load on that route. If you make an HTTP request of some service you'll be lucky to get the time within 200ms. If you want your clients to have accurate time to within 10ms of reference they'll need NTP installed and then they might achieve your target. A local GPS reference will be the only reliable way for that accuracy.

High-precision clock synchronization is going to be problematic, especially in a virtualized environment. This is the exact case for the recommendation of not running Kerberos/Windows domain controllers in a virtual environment given their tendency to high clock drift.

That said, the correct answer is certainly not to spam NIST in any form as they provide NTP services as a courtesy and will most certainly block you for excessive queries.

What you should do is ask your ISP if they have an NTP server that you can use to aggressively sync your clocks, ideally a stratum 1 or 2 server, and point all of your machines at that. If not, set up your own stratum 2 server [preferably on metal, not virtual] and use that.

Once you have a suitable NTP server then it's just a matter of configuring ntpd to update your clock frequently enough from that one server that you don't end up drifting more than you 10ms limit.

But really, I can't shake the feeling that requiring these disparate clocks to be so closely in sync is a symptom of a poor design choice. Can you not simply send these 'asynchronous clients' their scheduling info as 'X microseconds from now' rather than a full timestamp in the future?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top