不可靠的时钟

还在用传统的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接收器或者原子钟 尽或许地削减差错,感兴趣能够了解一下。

不可靠的时钟

来都来了,点个赞再走吧彦祖,这对我来说非常重要!