不可靠的时钟

435 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

本系列主要是《数据密集型应用系统设计》阅读笔记,本文记录时钟处理主题的笔记心得。

问题

时钟和计时非常重要。有许多应用程序各种方法依赖于时钟,例如:

  1. 某个请求是否超时了
  2. 某项服务的99%的响应时间是多少
  3. 在过去的5分钟内,服务平均每秒处理多少个查询?
  4. 用户在我们的网站上浏览了多少时间?
  5. 这篇文章什么时候发表?
  6. 在什么时候发提醒邮件?
  7. 这个缓存条目何时过期?

在分布式系统中,消息经过网络从一台机器到另一台机器总是需要花费时间。收到消息的时间应该晚于发送的时间,但由于网络的不确定延迟,精确测量面临着很多挑战。

网络上的机器都有自己的时钟硬件设备,通常是石英晶体振荡器。这些设备并非绝对准确,每台机器都可以维护自己本地的时间版本,可能比其他机器稍快或稍慢。为了同步分布式机器的时钟,一般采用NTP服务器来同步,时间服务器从精度更高的时间源(如GPS接收机)获取高精度时间。

时钟的分类

clock.png

墙上时钟

例如Linux的clock_gettime(CLOCK_REALTIME)和java的System.currentTimeMillis()会返回自1970年1月1日以来的秒数和毫秒。

墙上时钟可以和NTP同步。但是如果本地实际远远快于NTP服务器,强行同步后则会跳回先前的某个时间点。这种跳跃可能会引起奇怪的问题。

比如我实际遇到的一个,这种异常让sleep的行为出现了异常,结果sleep 10s一直没醒来。

单调时钟

单调时钟更适合测量持续时间段,例如超时和服务的响应时间,Linux的clock_gettime(CLOCK_MONOTONIC)和java的System.nanoTime()返回的即是单调时钟,单调时钟保证总是向前的。

单调时钟只能计算两个时间点之间的差值,本身的值没有意义。

本身的值可能是电脑启动经历的纳秒数

如果服务器有多路CPU,则每个CPU可能有单独的计数器,由于应用程序的线程可能会调度到不同的CPU上,此时,操作系统可能会补偿多个计时器之间的偏差。

为了稳妥起见,应用程序最后绑定CPU来支持精确的单调时钟计时。

时钟同步和准确性

硬件时钟和NTP 可能会出现一些莫名其妙的现象。

  • 计算机中的石英钟不够准确,存在偏移现象(运行速度会加快或减慢)
    • 时钟偏移主要取决于机器的温度
    • Google假设其服务器的时钟偏移为200ppm(百万分之一),假设每30s和NTP服务器同步一次,则可能出现的最大偏差为6ms;如果每天同步一次,则可能出现的最大偏差为17s.
    • 即使没有其他的异常,偏移问题是在所难免的。

其他的异常:

  • 墙上时钟可以和NTP同步,但是如果本地实际远远快于NTP服务器,强行同步后则会跳回到先前的某个时间点。这种跳跃可能会引起奇怪的问题。
  • 墙上时钟和NTP同步时,如果网络异常,可能很长时间没有留意到,从而同步失败
  • 和NTP的网络延迟可能长达平均约35ms的偏差,最坏时可能超过1s。
  • NTP服务器也可能出现故障或者配置错误,报告的时间可能出现数小时的偏差
  • 闰秒会产生一分钟59或61s的情况,可能会使得没有防范的系统出现混乱

    闰秒名词释义 1972年,国际计量大会决定,当“世界时”与“原子时” 之间时刻相差超过0.9时,就在“协调世界时”上加上或减去1,以尽量接近“世界时”,这就是闰秒

  • 虚拟机的时间也是被虚拟化的
  • 客户端时间(比如移动设备和嵌入式设备)是不能完全相信的。

投入大量资源,也是可以达到非常高的时钟精度。比如金融机构要求高频交易基金必须在UTC 100微妙内同步时钟,以便调试‘崩盘’等市场异常并检测市场操纵等违规行为。

高精度的时钟可以采用GPS接收机等方式,通常也意味着大量资源、持续监控等。