还在用传统的System.currentTimeMillis来核算代码运转时刻嘛? – () 上一篇文章简略地讲到了墙上时钟和单调时钟,本篇将从分布式架构的角度下,谈谈为什么咱们称时钟为不可靠的时钟。
时钟同步与准确性
分布式架构下,每个节点的时刻很难保持一致,
石英晶体振荡器
机器的时钟是依托硬件 石英晶体振荡器 来完成的可是石英振荡器会受到温度的影响。
虚拟化切换
即使时在 虚拟机环境 下,CPU核会切换虚拟机,然后导致正在运转的操作系统会忽然时刻短暂停几十毫秒。
那为什么咱们现在的电脑时钟并没有差许多呢。
NTP(network time protocol)
由于咱们运用 NTP
进行同步时钟。NTP 供给了时刻校准的功用,能够让机器上的时钟相对来说差错更小,可是没办法完成全部一致。
其次这里会同步是需求走 网络 的,可是网络跟时钟都是 不可靠的 要素,比方 网路堵塞,进程暂停 导致超时等。
影响时钟的还有天然要素。
闰秒
正常情况下,一分钟是60秒。但由于地球的自转不均衡和潮汐的问题(具体感兴趣能够自己百度),或许会出现一分钟只有59秒或是61秒。
依靠同步的时钟
网络毛病很简单被发现,可是时钟同步出现毛病一般都是潜在毛病,难以发现。
网络毛病,会出现大量的超时恳求。这个是能够轻易地被监控到的。当应用程序监控到了之后,能够采纳相对应的fail-over
办法。
- 节点下线处理。
- leader选取等。
可是关于时钟毛病
就很难马上让应用程序反响出来。
时钟不一致导致的毛病
比方:时刻往后跳了1秒、2秒对日常功用或许不会引起大问题。可是关于依靠时钟的服务,比方:
- 限时购买
- 守时推送
- 租约(分布式锁)
- ….
出现的问题或许便是:
- 尽管现已到点了,我这个节点上的恳求还能够继续购买。
-
实际国际中,我是抢到了榜首,可是在程序里,由于我节点的时刻比他人慢,或许他人便是榜首了。(
事情次序性
)
- 客户端A写入
x = 1
成功后,开端进行节点数据同步。 - 客户端B写入
x = x + 1
成功后,开端进行节点数据同步。尽管客户端B是在A之后写入的,尽管客户端A同步开端得比客户端B要早,可是最后客户端B的恳求同步比客户端A的要早。
先动身的未必先到达。
那么在节点2的视角来看,由于时刻戳,会判别客户端B的恳求先于客户端的恳求,他的视角来看是,x+=1 -> x = 1。这样就会导致客户端B的恳求被掩盖了。
这种处理抵触的方法便是LWW
(最后写入获胜 Last-Writer-Win)。这个战略是依靠写入时刻,也便是依靠时钟的。这是他无法处理的缺陷。
版本号技能
时钟(时刻戳)大量用于版本号的生成。
其次关于 事情产生的因果次序 ,一般咱们都会采纳 版本号 的技能,由于 天然数是一个全序关系 能够进行比较。这样咱们就能够判别事情A是产生在事情B之前仍是之后。
关于 版本号 的生成方法有许多选型:
- 假如选用
wall-clock time
(墙上时钟) 生成的时刻戳,在单机情况下是没有问题的,可是在多节点的情况下,极小概率会出现问题,有或许实际国际中产生的次序,在程序中是不一样的。 - 假如选用
monotonous time
(单调时钟),就能够处理墙上时钟的问题,可是又引入了别的一个问题,这个单调时钟该怎么生成,由主节点生成吗?那么他会有单点毛病的风险吗?
所以说在讨论一项技能的时候,咱们需求了解他的 优势 以及 代价。再根据咱们的场景进行取舍。
总结
分布式集群情况下,各个节点难以保持相同的时钟,影响时钟不可靠的要素有许多:
- 硬件自身的问题(石英晶体受问题影响,时钟飘逸、时钟回拨等问题)
- 虚拟化切换的问题
- 不可靠的网络(NTP同步受到网络的约束)
- …
常见的 版本号 技能选用时刻戳来进行完成,相同会面临 不可靠的时钟 问题,在跨节点的环境下,过分依靠时钟是一个比较风险的操作。
大局快照的同步时钟 现在业界都没有一个很好的落地计划。
Google Spanner
选用的是一个 置信区间 的机制来完成高精度的时钟(尽或许缩小差错区间),相同他 Google
还部署了高精度的时钟仪器比方 GPS接收器或者原子钟 尽或许地削减差错,感兴趣能够了解一下。
来都来了,点个赞再走吧彦祖,这对我来说非常重要!