49 | 数据完整性(上):硬件坏了怎么办?

2012年的时候,我第一次在工作中,遇到一个因为硬件的不可靠性引发的Bug。正是因为这个Bug,让我开始逐步花很多的时间,去复习回顾整个计算机系统里面的底层知识。

当时,我正在MediaV带领一个20多人的团队,负责公司的广告数据和机器学习算法。其中有一部分工作,就是用Hadoop集群处理所有的数据和报表业务。当时我们的业务增长很快,所以会频繁地往Hadoop集群里面添置机器。2012年的时候,国内的云计算平台还不太成熟,所以我们都是自己采购硬件,放在托管的数据中心里面。

那个时候,我们的Hadoop集群服务器,在从100台服务器往1000台服务器走。我们觉得,像Dell这样品牌厂商的服务器太贵了,而且能够提供的硬件配置和我们的期望也有差异。于是,运维的同学开始和OEM厂商合作,自己定制服务器,批量采购硬盘、内存。

那个时候,大家都听过Google早期发展时,为了降低成本买了很多二手的硬件来降低成本,通过分布式的方式来保障系统的可靠性的办法。虽然我们还没有抠门到去买二手硬件,不过当时,我们选择购买了普通的机械硬盘,而不是企业级的、用在数据中心的机械硬盘;采购了普通的内存条,而不是带ECC纠错的服务器内存条,想着能省一点儿是一点儿。

单比特翻转:软件解决不了的硬件错误

忽然有一天,我们最大的、每小时执行一次的数据处理报表应用,完成时间变得比平时晚了不少。一开始,我们并没有太在意,毕竟当时数据量每天都在增长,慢一点就慢一点了。但是,接着糟糕的事情开始发生了。

一方面,我们发现,报表任务有时候在一个小时之内执行不完,接着,偶尔整个报表任务会执行失败。于是,我们不得不停下手头开发的工作,开始排查这个问题。

用过Hadoop的话,你可能知道,作为一个分布式的应用,考虑到硬件的故障,Hadoop本身会在特定节点计算出错的情况下,重试整个计算过程。之前的报表跑得慢,就是因为有些节点的计算任务失败过,只是在重试之后又成功了。进一步分析,我们发现,程序的错误非常奇怪。有些数据计算的结果,比如“34+23”,结果应该是“57”,但是却变成了一个美元符号“$”。

前前后后折腾了一周,我们发现,从日志上看,大部分出错的任务都在几个固定的硬件节点上。

另一方面,我们发现,问题出现在我们新的一批自己定制的硬件上架之后。于是,和运维团队的同事沟通近期的硬件变更,并且翻阅大量Hadoop社区的邮件组列表之后,我们有了一个大胆的推测。

我们推测,这个错误,来自我们自己定制的硬件。定制的硬件没有使用ECC内存,在大量的数据中,内存中出现了单比特翻转(Single-Bit Flip)这个传说中的硬件错误。

那这个符号是怎么来的呢?是由于内存中的一个整数字符,遇到了一次单比特翻转转化而来的。 它的ASCII码二进制表示是0010 0100,所以它完全可能来自 0011 0100 遇到一次在第4个比特的单比特翻转,也就是从整数“4”变过来的。但是我们也只能推测是这个错误,而不能确信是这个错误。因为单比特翻转是一个随机现象,我们没法稳定复现这个问题。

ECC内存的全称是Error-Correcting Code memory,中文名字叫作纠错内存。顾名思义,就是在内存里面出现错误的时候,能够自己纠正过来。

在和运维同学沟通之后,我们把所有自己定制的服务器的内存替换成了ECC内存,之后这个问题就消失了。这也使得我们基本确信,问题的来源就是因为没有使用ECC内存。我们所有工程师的开发用机在2012年,也换成了32G内存。是的,换下来的内存没有别的去处,都安装到了研发团队的开发机上。

奇偶校验和校验位:捕捉错误的好办法

其实,内存里面的单比特翻转或者错误,并不是一个特别罕见的现象。无论是因为内存的制造质量造成的漏电,还是外部的射线,都有一定的概率,会造成单比特错误。而内存层面的数据出错,软件工程师并不知道,而且这个出错很有可能是随机的。遇上随机出现难以重现的错误,大家肯定受不了。我们必须要有一个办法,避免这个问题。

其实,在ECC内存发明之前,工程师们已经开始通过奇偶校验的方式,来发现这些错误。

奇偶校验的思路很简单。我们把内存里面的N位比特当成是一组。常见的,比如8位就是一个字节。然后,用额外的一位去记录,这8个比特里面有奇数个1还是偶数个1。如果是奇数个1,那额外的一位就记录为1;如果是偶数个1,那额外的一位就记录成0。那额外的一位,我们就称之为校验码位

如果在这个字节里面,我们不幸发生了单比特翻转,那么数据位计算得到的校验码,就和实际校验位里面的数据不一样。我们的内存就知道出错了。

除此之外,校验位有一个很大的优点,就是计算非常快,往往只需要遍历一遍需要校验的数据,通过一个O(N)的时间复杂度的算法,就能把校验结果计算出来。

校验码的思路,在很多地方都会用到。

比方说,我们下载一些软件的时候,你会看到,除了下载的包文件,还会有对应的MD5这样的哈希值或者循环冗余编码(CRC)的校验文件。这样,当我们把对应的软件下载下来之后,我们可以计算一下对应软件的校验码,和官方提供的校验码去做个比对,看看是不是一样。

如果不一样,你就不能轻易去安装这个软件了。因为有可能,这个软件包是坏的。但是,还有一种更危险的情况,就是你下载的这个软件包,可能是被人植入了后门的。安装上了之后,你的计算机的安全性就没有保障了。

不过,使用奇偶校验,还是有两个比较大的缺陷。

第一个缺陷,就是奇偶校验只能解决遇到单个位的错误,或者说奇数个位的错误。如果出现2个位进行了翻转,那么这个字节的校验位计算结果其实没有变,我们的校验位自然也就不能发现这个错误。

第二个缺陷,是它只能发现错误,但是不能纠正错误。所以,即使在内存里面发现数据错误了,我们也只能中止程序,而不能让程序继续正常地运行下去。如果这个只是我们的个人电脑,做一些无关紧要的应用,这倒是无所谓了。

但是,你想一下,如果你在服务器上进行某个复杂的计算任务,这个计算已经跑了一周乃至一个月了,还有两三天就跑完了。这个时候,出现内存里面的错误,要再从头跑起,估计你内心是崩溃的。

所以,我们需要一个比简单的校验码更好的解决方案,一个能够发现更多位的错误,并且能够把这些错误纠正过来的解决方案,也就是工程师们发明的ECC内存所使用的解决方案。

我们不仅能捕捉到错误,还要能够纠正发生的错误。这个策略,我们通常叫作纠错码(Error Correcting Code)。它还有一个升级版本,叫作纠删码(Erasure Code),不仅能够纠正错误,还能够在错误不能纠正的时候,直接把数据删除。无论是我们的ECC内存,还是网络传输,乃至硬盘的RAID,其实都利用了纠错码和纠删码的相关技术。

想要看看我们怎么通过算法,怎么配置硬件,使得我们不仅能够发现单个位的错误,而能发现更多位的错误,你一定要记得跟上下一讲的内容。

总结延伸

好了,让我们一起来总结一下今天的内容。

我给你介绍了我自己亲身经历的一个硬件错误带来的Bug。由于没有采用ECC内存,导致我们的数据处理中,出现了大量的单比特数据翻转的错误。这些硬件带来的错误,其实我们没有办法在软件层面解决。

如果对于硬件以及硬件本身的原理不够熟悉,恐怕这个问题的解决方案还是遥遥无期。如果你对计算机组成原理有所了解,并能够意识到,在硬件的存储层有着数据验证和纠错的需求,那你就能在有限的时间内定位到问题所在。

进一步地,我为你简单介绍了奇偶校验,也就是如何通过冗余的一位数据,发现在硬件层面出现的位错误。但是,奇偶校验以及其他的校验码,只能发现错误,没有办法纠正错误。所以,下一讲,我们一起来看看,怎么利用纠错码这样的方式,来解决问题。

推荐阅读

我推荐你去深入阅读一下Wikipedia里面,关于CRC的内容,了解一下,这样的校验码的详细算法。

课后思考

有人说,奇偶校验只是循环冗余编码(CRC)的一种特殊情况。在读完推荐阅读里面的CRC算法的实现之后,你能分析一下为什么奇偶校验只是CRC的一种特殊情况吗?

欢迎把你阅读和分析的内容写在留言区,和大家一起分享。如果觉得有帮助,你也可以把今天的内容分享给你的朋友。

精选留言

  • 有铭

    2019-08-21 10:32:18

    从老师的描述看单比特翻转问题的概率不低啊,但是大部分PC机都没有用ECC,为什么PC机很少听说有出现这个问题带来的bug?
    作者回复

    有铭同学,

    你好,这有两种情况:
    1. 第一种是PC实际的负载比服务器低很多,大部分时间你的PC是很空闲的,CPU占用率和内存使用率都不高,也没有什么东西在计算。而服务器常常是24小时高负载在运转的。服务器可能一天进行的计算量比你PC一年还多。数据中心里又有可能同时有1000台计算机,意味着服务器一天遇到的问题可能PC要一辈子才遇到一次。

    2. 第二是很多时候发生了你没有意识到,比如程序忽然Crash了,机器蓝屏重启了,甚至有程序数据错了,你并会关心到哪个是单比特翻转引起的。

    2019-09-28 16:47:14

  • 明翼

    2019-08-25 09:09:32

    这个bug牛逼了
  • 美妙的代码

    2019-08-21 09:20:45

    老师,发生单比特翻转,只是内存质量与外部射线的原因吗?那买内存的时候,能不能检测到这样的问题的内存。
    ECC 目前只能在物理内存里实现吗,
    作者回复

    we同学,

    你好,单比特翻转不一定是内存质量问题,是我们物理设备本身必然会有精度、工艺以及外部其他干扰信号会带来的问题。ECC也可以在软件层面实现,只是从设计大型系统的角度来讲,我们把这个直接隔离到硬件层面对软件工程师来说是投资回报比最高的。

    2019-09-28 16:44:25

  • 大王叫我来巡山

    2019-12-19 23:58:47

    曾经一个批次的服务器上线后都就频繁出现这个问题,最终猜测是内存的问题,然后统一换了内存以后没有出现过。
    作者回复

    👍

    2020-02-02 21:43:06

  • xindoo

    2019-08-21 08:44:47

    之前好像看到过google大神jeff dean也处理过单bit翻转的故障
    作者回复

    xindoo同学,

    你好,数据量和负载上来,没有ECC的话,单比特翻转其实是一个大概率发生的故障。

    2019-09-28 16:42:24

  • humor

    2019-08-21 11:11:11

    为什么只会发生单比特翻转不会发生多个比特位的翻转呢
    作者回复

    humor同学你好

    也会发生,但是概率要小很多。比如单笔特翻转发生的概率是0.01%,那么两个比特都翻转概率就是0.000001%。 要解决这个问题成本会进一步大幅度上升,就没有必要在硬件层面这么干了。

    2019-09-15 21:57:21

  • 88591

    2019-12-13 14:21:41

    计算机领域有太多的未知的未知知识。
  • 阿卡牛

    2019-08-22 12:04:55

    最近在学网络分层方面的知识,看到检错码和纠错码的方法,没想到在这里也用上了
    作者回复

    是的,计算机科学的底层很多知识是相通的

    2019-09-28 16:40:27

  • 活的潇洒

    2019-09-15 22:35:40

    不管多慢、都要坚持打卡、坚持写博文
    day49天 笔记:https://www.cnblogs.com/luoahong/p/11498124.html
  • 范超

    2022-06-03 21:57:56

    奇偶校验这种方式,如果“校验码位”发生了翻转怎么办呢
  • 超超

    2021-07-24 12:37:01

    这一节讲述的服务器故障的内容与RAS特性密切相关,RAS的全称为 Reliability, Availability,Serviceability。
    Reliability(可靠性)指的是系统必须尽可能的可靠,不会意外的崩溃,重启甚至导致系统物理损坏,这意味着一个具有可靠性的系统必须能够对于某些小的错误能够做到自修复,对于无法自修复的错误也尽可能进行隔离,保障系统其余部分正常运转。
    Availability(可用性)指的是系统必须能够确保尽可能长时间工作而不下线,即使系统出现一些小的问题也不会影响整个系统的正常运行,在某些情况下甚至可以进行 Hot Plug 的操作,替换有问题的组件,从而严格的确保系统的宕机时间在一定范围内。
    Serviceability 指的是系统能够提供便利的诊断功能,如系统日志,动态检测等手段方便管理人员进行系统诊断和维护操作,从而及早的发现错误并且修复错误。
    RAS 作为一个整体,其作用在于确保整个系统尽可能长期可靠的运行而不下线,并且具备足够强大的容错机制。这对于像大型的数据中心,网络中心如股票证券交易所,电信机房,银行的数据库中心等应用环境是不可或缺的一部分。调研机构经过行业调查发现,不同的行业的关键业务中断会带来巨额的经济损失,下图是最新一期的调研报告,88%的企业每小时的服务器宕机会带来超过30万刀的损失,由此可见RAS的重要性以及对于可靠性需求的增长非常迅速。
    服务器的每个部件都有着不同的RAS特性,CPU RAS,内存RAS和PCIe RAS。有兴趣的可以再查些资料。
    参考资料:
    https://zhuanlan.zhihu.com/p/340605298
  • 2020-10-25 12:46:53

    第一次听说单比特反转这个问题,果然还是见识少哈,如果我遇到了,估计挠破脑袋也想不到去查计算机组成原理的知识
  • 西门吹牛

    2020-07-09 10:45:09

    通信里面信号传输的时候,也是这种处理方法,也有奇偶校验,基本方式都一样。数字电路信号传输,传输的就是bit。
  • -_-|||

    2020-01-20 14:30:38

    "定制的硬件没有使用 ECC 内存,在大量的数据中,内存中出现了单比特翻转(Single-Bit Flip)这个传说中的硬件错误",出现这个问题硬件厂商负责吗?还是后果都自负。
    作者回复

    -_-_aaa同学,

    你好,当然是后果自负。

    2020-02-02 12:06:40

  • prader26

    2019-10-17 16:27:22

    没想到内存里的数据在受到射线等外部数据的影响还会出错。幸好有ecc,期待下节课
  • 我爱天上的云朵

    2021-06-20 21:05:26

    想起了被408支配的恐惧
  • 奋斗

    2021-05-17 10:22:09

    当时面试阿里时候,面试官问你写的网络库在进行数据传输时,某个bit位由于外界的影响,由0变成1,这种问题怎么去规避,没回答上来。最后发现传输层也有类似的CRC校验功能。
  • 红薯板栗

    2021-02-25 14:59:57

    串口传输的时候奇偶校验位原来这么重要,以前很信任硬件,学了课程之后,硬件一样会出现BUG
  • LearnAndTry

    2020-12-01 17:12:48

    这才是多么痛的领悟,老师一定记得刻骨铭心
  • 许童童

    2019-08-21 15:01:47

    期待老师下一讲的内容。