zoukankan      html  css  js  c++  java
  • GitHub网站究竟可不可靠?谷歌工程师教你用BigQuery一探究竟

    作者简介:Felipe Hoffa,谷歌开发顾问,来自智利,现工作于旧金山以及全球各地,谷歌Cloud Platform社区编辑。


    以独特方式组织的可视化数据往往能够为我们提出一些有趣的观点。Felipe Hoffa最近使用BigQuery结合Reddit近八年来的网站活动以及上线时间数据进行了可视化分析,我们从中看到了一些非常有趣的信息。作为一名刚入门的负责任务控制的网站可靠性工程师,我总是会这样问自己,"如果我是负责这项服务的可靠性工程师,我会采用什么方法解决这个问题?"

    这次,Felipe将从可靠性工程师的角度出发,对GitHub的一些历史数据展开分析。首先,我们需要先确定,使用BigQuery对GitHub Archive上关于GitHub的部分事件数据进行分析是否足以推断出GitHub网站的健康状况。GitHub为开发者定义了很多种不同的活动事件类型,但在本篇文章的分析中,我们仅关注成功向GitHub发出请求的事件。

    我们可以使用这个查询语句:

    #StandardSQL 
    SELECT TIMESTAMP_TRUNC(created_at, MINUTE) minute, COUNT(*) 
    FROM `githubarchive.month.201607` 
    GROUP BY 1 
    ORDER BY 1
    

    我们可以找到在2016年7月中GitHub在每一分钟发生的事件数量。created_at字段记录了一个以微秒为单位的时间戳,查询语句将其按分钟进行截取。这使得我们将查询结果按时间戳分组时,可以使用COUNT聚合函数来统计每分钟对应的事件数量。将查询结果简单可视化即可得到下图:

    9a26e9f745bea2c293acd60f823df35236e30f64

    在上图中我们可以发现一些很有趣的数据点,这些数据点对应的事件数量格外得低,但是,仅通过上图我们很难准确判断每一分钟究竟是"正常的"还是"异常的"。因此,我们可以根据查询结果创建事件数据直方图,使判断的过程变得更加清晰。

    b4346e1a391eedfaee31ff66c2d9bc79172d69be

    这幅图很明显地表明,对于GitHub,当每分钟内处理的事件总数低于200时,网站处于异常的状态,这一结论至少在2016年7月份是成立的。我们假设每分钟极少数的事件与异常少的终端用户请求无关,而是由于网站自身服务器问题所导致的。在这个前提下,有两种可能的解释:用户请求未达到服务器,或者服务器无法成功响应用户请求。这为我们提供了一个标志来近似地判断GitHub当前的状态是"健康"还是"不健康"。

    在这里我们定义了一个"服务水平指标",即一个SLI(Service Level Indicator)。根据网站可靠性工程相关文献中的介绍,服务水平指标是"一个针对所提供服务水平中的某些方面谨慎定义的定量标准"。在我们这个例子中,服务水平指标是指"每分钟成功处理的事件数量"。我们要做的是,对这个服务水平指标进行转换,帮助我们判断网站服务在某一时刻是否上线或宕机。最简单的方法是为"每分钟成功处理事件"设置一个阈值,低于这个阈值时,我们将认为网站服务"宕机"。那么,我们应该怎么选择这个阈值?

    总中断会导致在特定的时间内没有请求事件记录。因此,我们可以将"宕机"阈值设置为0来检测总中断的情况。然而,大多数的中断都不是总中断。网站服务可能会进入某种不健康的状态,进而在提供服务的过程中开始出现异常高的错误率,这一现象会在日志数据中格外低的(成功请求)事件比例上得以体现。

    考虑到总中断情况下不会记录请求事件,我们在前面使用的简单查询在这种情况下可能会出现一些问题。没有事件记录的分钟不会显示在查询结果中!这样的结果完全忽略了总中断的情况。下面的查询语句展示了解决此类问题的方法。它创建了一个包含查询月份所有分钟的表格,并将其与前面的查询结果连接,随后将所有为NULL的结果(意味着不存在对应的行)映射为0事件数量:

    #StandardSQL
    SELECT b.minute m, IFNULL(c, 0) c
    FROM (
      # first day of month
      SELECT i*60 + UNIX_SECONDS(TIMESTAMP('2016-07-01')) minute 
      FROM `fh-bigquery.geocode.numbers_65536`
      WHERE i < 60*24*
        # number of days in month
        EXTRACT(DAY FROM DATE_SUB(DATE_ADD(DATE('2016-07-01'), INTERVAL 1 MONTH), INTERVAL 1 DAY))
    ) b 
    LEFT JOIN (
      SELECT UNIX_SECONDS(TIMESTAMP_TRUNC(created_at, MINUTE)) minute, COUNT(*) c
      FROM `githubarchive.month.201607`
      GROUP BY 1
    ) a
    ON a.minute=b.minute
    ORDER BY b.minute
    

    为了使接下来的查询操作更加简便,我们将本次查询的结果以视图形式保存,命名为events_per_minute_201607,并在接下来的查询中基于该视图检索数据。

    既然我们现在有一个视图,其中记录了所有零事件对应的分钟,那么我们可以使用一个分位数函数来探索在每分钟事件数量较低情况下的数据分布。

    #StandardSQL 
    SELECT APPROX_QUANTILES(c, 10001) as q 
    FROM `fh-bigquery.public_dump.events_per_minute_201607`
    

    APPROX_QUANTILE函数的"10001"参数表明数据将被划分至10000个桶中,每个桶具有相同数量的数据点。非统计学专业的读者可能对具有100个桶的分位数函数的特殊情况比较熟悉。例如,如果你在测试中处于95分位数,这意味着在测试中有5%的人成绩比你好,有94%的人成绩不如你,同时还有1%的人的成绩与你相同。

    下图为其中20条结果对应的条形图:

    70658b7e4fcd720187a15cc4eb49c23fbd10aedb

    由于我们认为中断属于异常情况,因此在这里我们寻找的是超出"正常"范围的数据点。我们想要选择一个合适的阈值,这样的阈值足够低,不会误将事件处理数较少的分钟判断为宕机时间,同时阈值也应足够高,以至于我们可以检测到任何明显导致请求事件响应数降低的操作。通常情况下,每分钟响应的用户请求数在20到77之间时,可能会出现"状态转换"的情况,这可能意味着当每分钟响应请求数低于20时,网站的服务几乎完全"宕机"。

    尽管上面的分析还未得出任何结论,但是我们可以先将阈值设为每分钟20个事件,并以此为服务是否"宕机"的判断依据,看看我们能够发现什么。使用下面的查询语句我们可以看到GitHub在2016年7月总共宕机了多少分钟:

    #StandardSQL
    SELECT m, c
    FROM `fh-bigquery.public_dump.events_per_minute_201607`
    WHERE c <= 20
    

    查询语句返回了54行记录,因此,根据我们的定义,GitHub的服务在七月份总共"宕机"了54分钟。但是54分钟究竟是好还是不好呢?

    为了回答这个问题,我们需要确定可接受的宕机时间是多少。正常运行时间目标通常以你希望达到多少个9的形式表示,例如,99%的正常运行时间,99.9%的正常运行时间等等。99.9%的正常运行时间意味着你只能在0.1%的时间内宕机。但是,为了让这样的表述有实际意义,我们必须先选择一个时间段。一个月是一个不错的选择。此时,正常运行时间目标的确切表述可能是"网站服务在一个公历月内宕机时间不得超过总共运行时间的0.1%"。

    为服务水平指标添加这样一个条件可将其转换为服务水平目标(SLO,Service Level Objective)。2016年7月共有44640分钟。这意味着在未达到服务水平目标前,我们总共有44.6分钟的宕机时间。这通常被称为"错误预算"。

    因此我们可以说在2016年7月份,GitHub的网站服务消耗了44分钟错误预算中的54分钟,因此,它以10分钟的差距未达到99.9%的服务水平目标。

    将服务水平目标可视化的典型方法是在给定时间段内累积错误时间,在我们的例子中,累计计算的时间段是七月的31天时间。接下来的查询语句统计了七月份的累积宕机时间。

    #StandardSQL
    SELECT m, cumulative_down, next_cum
    FROM (
      SELECT m, cumulative_down, LEAD(cumulative_down) OVER(ORDER BY m) next_cum, MIN(m) OVER() min_m, MAX(m) OVER() max_m
      FROM (
        SELECT m, SUM(IF(c <= 20, 1, 0)) OVER(ORDER BY m ROWS BETWEEN 43200 PRECEDING AND CURRENT ROW) cumulative_down
        FROM (
          SELECT m, c, 1 as down
          FROM `fh-bigquery.public_dump.events_per_minute_201606` UNION ALL
          SELECT m, c, 1 as down
          FROM `fh-bigquery.public_dump.events_per_minute_201607` UNION ALL
          SELECT m, c, 1 as down
          FROM `fh-bigquery.public_dump.events_per_minute_201608`)
        )
      )
    WHERE cumulative_down!=next_cum 
    OR m IN (min_m, max_m)
    ORDER BY m
    

    根据查询结果我们绘制了下图。图中折线的阶跃对应于"中断"的情况。中断时间越长,阶跃的幅度越大。当折线越过44分钟时,我们的宕机时间已经超过了错误预算,称该服务在30天的时间窗口内"未达到服务水平协议的要求"。

    07f0747764d1a0670d32beb22413c3806f1d58b5

    我们的分析表明,两次中断消耗了大部分的错误预算,一次是在月中,而另一次则发生在月末。事实上,如果我们查看GitHub的状态日志,我们可以看到GitHub在7月12日的报告中记录了"异常率激增"的情况,并在7月27日的报告中记录了"主要服务中断"。

    尽管服务水平目标有时按照公历月定义,但是这样的定义方式有时会给工程师带来困扰,主要有两个原因。首先,"公历月"并不是一个固定的时间跨度。一个公历月可能有28天也可能有31天,这取决于当前时间碰巧属于哪个月份。其次,这样的定义使个别几天变得非常特殊,错误预算在这几天会被神奇地重置。例如,对于一个服务水平目标为公历月99.9%正常运行时间的服务,可能在7月31日发生44分钟的中断,并且在8月1日又遭受另一次中断,这种情况下只要该服务在这两个月未发生其他中断,我们仍称其达到了服务水平目标,尽管该服务在48小时内总共发生了88分钟的中断。

    为了解决这些不一致的现象,服务水平目标通常采用30天滑动窗口的形式定义 ,而非公历月的形式。在不考虑闰秒的情况下,30天相比于公历月,是一个固定的时间跨度。而且,使用滑动窗口的方式也可以解决前面讨论的第二个问题。假设在7月31日和8月1日发生的两次44分钟中断将使该服务在8月1日中断发生后,便"超过服务水平目标的要求",直到7月31日的中断脱离30天滑动窗口的范围。

    这一点很重要,因为"超过服务水平目标的要求"应该引起负责团队的注意,并采取更为保守有效的决策。例如,如果你提供的服务"未达到服务水平目标",那么现在可能不是进行关键软件升级的最佳时机。48小时内88分钟的宕机时间足以令一个需达到99.9%服务水平目标的团队采取更保守的措施。第一个基于公历月的服务水平目标定义无法做到这一点,而第二个基于30天滑动窗口的定义则可以。

    阅读全文:http://click.aliyun.com/m/10281/  

  • 相关阅读:
    最小二乘拟合(scipy实现)
    接口实例
    类的继承:员工和老板
    设计模式(Design Patterns)
    创建类
    面向对象1
    java随机数:彩票抽奖 + 验证码
    判断字符串中字符出现的次数+去除空格
    输出二维数组所有元素的和
    输出 一维数组中最大的数+数组遍历
  • 原文地址:https://www.cnblogs.com/iyulang/p/6636836.html
Copyright © 2011-2022 走看看