前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[云顾问-混沌] 时间变了,A U OK?

[云顾问-混沌] 时间变了,A U OK?

原创
作者头像
冷淡然
修改2024-03-20 11:47:50
1130
修改2024-03-20 11:47:50
举报

时间在分布式系统中是一个重要且有趣的问题。时间是我们一直想要准确测量的量。为了知道特定事件在一天中的什么时间发生在特定计算机上,有必要将其时钟与权威的外部时间源同步。时间通常是系统事件完整性、系统日志、系统审计、系统故障排查以及系统取证的基本标准。在现代的复杂系统中很多地方都会和时间发生关系,比如基于时间的访问控制、加密认证等。很显然,在复杂的分布式系统中,准确的时间十分重要。既然时间这么重要,那时间不准确或者出现跳变的情况,会对系统产生影响吗?答案是会的。

手机里的时间准确吗?

当别人问你现在什么时间的时候,你会怎么做?打开手机,看一眼时间,告诉对方。但是这个时间真的准确吗?并不是!现在绝大部分的电子设备都是和协调时间时(UTC)对准的,你可以打开time.is查看当前的UTC时间。

但是这个时间是经过协调的,真正准确的时间是国际原子钟时间(International Atomic Time, TAI)。UTC时间和TAI时间是有差异的。换句话说,你手机上的时间并不是真正意义上的准确时间。

UTC和TAI

国际原子时(缩写TAI,来自其法语名称temps atomique international )是一种高精度的原子 坐标 时间标准,它基于地球大地水准面上适当时间的概念流逝。TAI 是全球 80 多个国家实验室的 450 多个原子钟保持时间的加权平均值。它是一个连续的时间尺度,没有闰秒,它是地球时的主要实现(带有固定的纪元偏移量))。它是协调世界时(UTC) 的基础,它用于地球表面的民用计时,具有闰秒。——维基百科

目前,国际原子时比协调时间时要快37秒。那为何会差距半分多钟呢?其实和维基百科中提到的闰秒(leap second)相关.

闰秒(Leap Second)

什么是闰秒?

闰秒其实国际地球自转和参考系统服务 (IERS)人为添加到UTC时间的一秒,会在某个时间点,加入1s(23:59:60)。

地球在围绕其轴自转的速度每天都在波动(月球/潮汐),并且随着时间的推移它会略微减慢。通过在时间计数上增加一秒,我们有效地停止了那一秒的时钟,让地球有机会赶上。添加闰秒的那一分钟为 61 秒,而那一天为 86,401 秒,而不是通常的 86,400 秒。

一般情况下,闰秒都会加在6月30日或者是12月31日的深夜,此时,一些时钟会出现23:59:60的奇怪时间。

已经加入的闰秒

截止到目前,总共添加了27个闰秒,在第一个闰秒加入之前,UTC时间已经慢于TAI时间10秒了。所以,现在UTC时间和TAI时间相差了37秒。

UTC 日期

UTC 时间

UTC慢于TAI (s)

30/06/1972

23:59:60

11

31/12/1972

23:59:60

12

31/12/1973

23:59:60

13

31/12/1974

23:59:60

14

31/12/1975

23:59:60

15

31/12/1976

23:59:60

16

31/12/1977

23:59:60

17

31/12/1978

23:59:60

18

31/12/1979

23:59:60

19

30/06/1981

23:59:60

20

30/06/1982

23:59:60

21

30/06/1983

23:59:60

22

30/06/1985

23:59:60

23

31/12/1987

23:59:60

24

31/12/1989

23:59:60

25

31/12/1990

23:59:60

26

30/06/1992

23:59:60

27

30/06/1993

23:59:60

28

30/06/1994

23:59:60

29

31/12/1995

23:59:60

30

30/06/1997

23:59:60

31

31/12/1998

23:59:60

32

31/12/2005

23:59:60

33

31/12/2008

23:59:60

34

30/06/2012

23:59:60

35

30/06/2015

23:59:60

36

31/12/2016

23:59:60

37

闰秒故障

在2012年6月30日,IERS准备在这天的最后一秒之后插入闰秒。但是万万没想到,插入的这一个闰秒,导致了很大一部分业务系统宕机。

Reddit

在这天,2012年6月30日的深夜,许多人和往常一样正在Reddit上快乐水贴,突然发现,自己的回复发不出去了。

闰秒故障在Reddit上发生了,起初,Jason Harvey并没有意识到是闰秒加入的问题,仅仅认为是网络质量差的原因。但是问题持续了半个多小时,他们意识到了问题的严重性。最后他们追溯到他们的一组运行着Linux操作系统的服务器上,他们发现,由于没有正常适应当天晚上加入的闰秒,这组服务器几乎完全停顿下来,无法做任何响应。

这些机器到底发生了啥呢?

John Stultz(Linux Kernel & AOSP devboards)在2012-7-1日的一封邮件链接中提到了这个问题:

从 Stultz 的邮件列表帖子来看,当闰秒来临时,这些 hrtimer 突然比核心操作系统领先一秒,它们同时唤醒无数休眠的应用程序,并使机器的 CPU 过载。Reddit最后通过重启服务器才使得业务恢复。该站点在大约 30 到 40 分钟内几乎无法运行,并且完全离线大约一个半小时,可以说是一个比较严重的现网事故了。

其他故障

在2012-6-30这天,不光Reddit出现了问题,Reddit 只是在格林威治标准时间周六午夜过后遭受闰秒故障的几家网络公司之一,包括 Gawker Media 和 Mozilla,每次进行闰秒调整时都会出现此类问题。例如,据报道,2009 年 1 月闰秒导致 Sun Microsystems 的 Solaris 操作系统和Oracle 软件包出现问题;2016年12月31日的闰秒导致了Cloudflare DNS的崩溃https://blog.cloudflare.com/how-and-why-the-leap-second-affected-cloudflare-dns/

启示

因为闰秒问题,很多系统都产生了不同程度的故障。可见系统时间对于系统的重要性。以后在设计复杂系统时,需要特别关注一下时间的问题。但是现在系统设计得越来越复杂,往往是不同的微服务之间相互依赖,怎么去定位或者发现系统中潜在的和系统时间相关的问题呢?

腾讯云混沌演练平台

混沌演练平台提供多场景的故障主动注入,便于用户模拟真实环境的故障扰动,协助用户发现其系统韧性不足之处。本文的场景,其实就可以使用混沌演练平台提供的CVM系统时间跳变混沌故障动作模拟,并且可以注入故障之后回滚操作,可以帮助用户在业务上线之前验证类似复杂系统中时间跳变的场景,这样当真实场景发生时,被问到 A U OK?时,也能十分有底气的说:I'm OK, thanks, A U ?

CVM系统时间演练示例

示例告警系统

假设目前有一个监控系统,里面有两个微服务告警服务/数据采集服务。告警服务依赖于数据采集服务的数据。这里简化为如下程序(详细程序附件中提供):

alarm_client

代码语言:go
复制
func main() {
    log.Println("===========Starting Client=============")
    var threshold float64
    threshold = 0.0
    for {
        // getFlowMetricData 从监控数据服务中获得流量总量
        // return (flowTotal, latestTime): (流量总量数据,上次请求数据时间)
        flowMetric, latestTime := getFlowMetricData()
        times := float64(time.Now().UnixNano() - latestTime)
        // 判断是否每纳秒流量是否超过阈值,这里铁定会超过(用作示例)
        if float64(flowMetric)/times > threshold {
            // alarm
            log.Println("超过阈值,告警。")
            // 模拟告警执行用时2s
            time.Sleep(time.Second * 2)
        }
        // 其他逻辑
        time.Sleep(time.Second * 1)
    }
}

data_server

代码语言:go
复制
func main() {
    var latestTime int64
    latestTime = -1
    r := gin.Default()
    r.GET("/getMetricData", func(c *gin.Context) {
        // 结构体方式
        currentTime := time.Now().UnixNano()
        data := JsonResponse{
            Code: 200,
            Msg:  "获取数据成功",
            Data: rand.Int63n(1000),
        }
        if latestTime > 0 {
            data.LatestTime = latestTime
            latestTime = currentTime
        } else {
            data.LatestTime = currentTime
            latestTime = currentTime
        }
        c.JSON(http.StatusOK, data)
    })
    _ = r.Run(":8080")
}

这个简化的程序实际上是存在问题的,下面我们将演示通过腾讯云混沌演练平台进行CVM系统时间跳变来发现这个问题。

创建混沌演练任务

演练目的

通过混沌演练平台CVM系统提供的时间跳变故障动作对上述系统进行混沌演练,发现程序中存在的潜在问题。

步骤一:选择告警服务CVM实例,时间回退5秒钟

步骤二:故障注入成功之后,观察程序是否正常执行

步骤三:启动恢复动作,恢复告警服务CVM实例系统时间

步骤四:恢复动作执行成功之后,观察程序是否恢复正常运行

演练准备

将上述两个程序,编译成可执行文件,并上传到2个不同的CVM实例上(chaos-test-1实例运行告警客户端程序,chaos-test-2实例运行数据采集服务),启动程序。此时两个CVM实例的系统时间是一致的。程序可以正常无误地运行。并在腾讯云混沌演练平台上选择对应的CVM实例,添加CVM时间跳变故障动作。

开始演练

  1. 启动告警系统,正常运行

2. 启动故障动作注入。

3. 发现问题,启动恢复动作,恢复时间。

演练复盘

通过混沌演练,我们发现示例的告警系统在面对系统发生跳变时候,韧性是不足的,出现了理应发生告警的数据时,并没有触发告警逻辑,这对于一个监控系统是相当致命的,如此以来,监控系统就形同虚设了。这个问题是在故障动作注入告警服务的CVM中的,现在回顾这个代码,很容易发现是其在获取当前时间的时候出现了问题。

代码语言:javascript
复制
times := float64(time.Now().UnixNano() - latestTime)

这个在两台服务器时间统一的情况下,times >= 0, 但是当告警服务所在实例发生系统时间跳变之后,告警服务所在实例的系统时间回退了5s, 使得times < 0,进而无法触发告警逻辑,而且这个异常会一直存在除非时间恢复。经过混沌演练,可以帮助我们发现程序中潜在的问题,并针对其进行优化,这里可以调整数据采集服务接口返回(流量总量,上次结束时间,本次请求时间)来避免这个问题。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 手机里的时间准确吗?
  • UTC和TAI
  • 闰秒(Leap Second)
    • 什么是闰秒?
      • 已经加入的闰秒
      • 闰秒故障
        • 其他故障
        • 启示
        • 腾讯云混沌演练平台
          • CVM系统时间演练示例
            • 示例告警系统
          • 创建混沌演练任务
            • 演练目的
            • 演练准备
          • 开始演练
            • 演练复盘
            相关产品与服务
            混沌演练平台
            混沌演练平台(Chaotic Fault Generator)提供高效便捷、安全可靠的故障演习服务,除可视化故障注入服务外,还提供行业经验模板,监控护栏等核心功能,致力于帮助用户及时发现业务容灾隐患、验证高可用预案的有效性,从而提高系统的可用性和韧性。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档