持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
本系列主要是《数据密集型应用系统设计》阅读笔记,本文记录时钟处理主题的笔记心得。
问题
时钟和计时非常重要。有许多应用程序各种方法依赖于时钟,例如:
- 某个请求是否超时了
- 某项服务的99%的响应时间是多少
- 在过去的5分钟内,服务平均每秒处理多少个查询?
- 用户在我们的网站上浏览了多少时间?
- 这篇文章什么时候发表?
- 在什么时候发提醒邮件?
- 这个缓存条目何时过期?
在分布式系统中,消息经过网络从一台机器到另一台机器总是需要花费时间。收到消息的时间应该晚于发送的时间,但由于网络的不确定延迟,精确测量面临着很多挑战。
网络上的机器都有自己的时钟硬件设备,通常是石英晶体振荡器。这些设备并非绝对准确,每台机器都可以维护自己本地的时间版本,可能比其他机器稍快或稍慢。为了同步分布式机器的时钟,一般采用NTP服务器来同步,时间服务器从精度更高的时间源(如GPS接收机)获取高精度时间。
时钟的分类
墙上时钟
例如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接收机等方式,通常也意味着大量资源、持续监控等。