Silent Data Corruption 幽灵杀手

为了提高数据在存储系统中的可靠性,我们使用冗余的办法来抵御不稳定因素,如副本或纠删码。 然而单凭冗余策略,我们不仅不能完全保障数据安全,可能还会面临系统雪崩的风险。这类被大多数人忽视, 或是不甚了解的潜在错误无时无刻不在威胁着我们的系统安全。

那么是什么如幽灵一般存在呢?我们如何抗击它呢?在这篇文章中,我们将一起来追踪这位幽灵杀手。

Silent Data Corruption,原来是你

通常我们认为硬件是完全可靠的,然而,有些错误可以穿透这些校验机制,从而造成潜在的危害与事故。 我们称这一类错误为 Silent Data Corruption (SDC)。尽管 SDC 出现的概率并不高,但对于有大量数据交互的服务来说, 可以认为它是必现的,有时它能造成难以修复的故障。

“亡魂”

  1. AWS S3 因 bit corruption 造成 36 小时的服务中断[1]
  2. Facebook 遇到 10%-15% 的图片无法访问 (48 小时)[2]
  3. Netflix 宕机超过 3 天[3]
  4. ...

以上这些重大事故的无一例外,都是 Silent Data Corruption 这位鬼魅般的数据杀手的 “杰作”。

捉鬼有方

我们固然可以执行非常严厉的计划来避免 SDC 问题,然而无论多么精巧的设计都不能 100% 避免问题的发生,而且会急剧降低系统的整体性能。这就要求我们学会在 性能 与 可靠性 之间做工程上的平衡。

但这并不意味着放弃抵抗或是拍脑袋决策,我们率先需要认真考察 SDC 出现的场景和影响。从而进行提出有针对性的方案。

对数据流分类

对数据流分类

根据数据的目的,我们可以将数据流分为 控制流 和 文件流 两种形态。这两种形态对于数据的完整性提出了不同的要求。对于控制流,我们必须保证整条数据流中任意两端的完整性,这是因为控制流出错可能引发出大的灾难。

对于文件流,我们只需要提供最终完整的机制即可。如客户可以拿本地的 SHA1 与存储系统返回的 SHA1 进行对比。(值得注意的是,任意一端的 SHA1 可能并不反映真实的数据情况)

分类依据:媒介

根据数据的媒介,我们可以将数据流分为 网络流 和 本地流 两种形态。分别代表服务器之间的通信过程和服务内部的通信过程。

幽灵魅影

在本小节点中,我们将根据上文的分类去分析 SDC 出现的场景以及预防机制。

网络流

在应用层之下,我们已经拥有 switch 的 CRC32 与 TCP Checksum 的防护机制,然而数据经流的每一台 switch 都会重新计算 CRC32 (除非是两台机器简单的通过一台 switch 相连),也就是说,目前我们拥有的机制无法避免 switch 内部错误。如果经过了路由,情况会变得更加复杂。 TCP Checksum 的设计目标之一就是为了预防这样的错误,但其强度太低,不足以胜任这样的任务。[4]

CRC32 与 Adler32 (Fletcher 的替代品) 的设计目的都是为了做以太网 frame (around 1500B) 的校验,其中 Adler32 的强度还要低于 Fletcher32[5]

我们所需要考察的是,在较大的数据尺度上(校验在应用层上做),这两种算法能否满足我们提高系统可靠性的要求。

出错原因

主要为 bit flipping 错误,以及交换机/路由的固件和逻辑问题。因此既要预防少量的 bit 随机反转,也要能应对成片的错误。在交换机日志上可能会看到被交换机纠错过的记录,如果错误日志相关条目的数据量非常大,可以考虑进行对交换机的维护/更换。

所需要校验的数据特征

上文中,我们指出应对数据流做区别对待,其中要更加注重控制流(即指令参数等控制信息)。原因如下:

  1. 对于存储系统来说,我们并不能控制客户端行为。如果客户端在上传时不提供数据摘要,也就是说不能实现完整的 end-to-end data integrity
  2. 文件流危害范围小,不会造成系统雪崩

控制流呈现如下特点:

  1. 数据量相对较小,通常小于 1MB。哪怕设计到集群信息也一般在百MB以下
  2. 信息相对比较重要,部分出错需要零容忍。比如文件唯一 id 由于 bit flipping 出现重复
  3. 数据一般进行了封装,以便 unmarshal 成可以使用的数据结构。而数据结构本身具备一定的抗随机错误的能力
校验算法

无论是 CRC32 IEEE802.3 还是 Adler32 或者 Fletcher32 在上述最大数据尺度上其 hamming distance 均为 2。对于校验算法来说,hamming distance 指的是其最少多少位错误的情况下会有 1bit 无法检测。这里的 2 是指,只要有 2bit 错误至少会有 1bit 错误无法被识别到。

因此,如果觉得强度不满意。还可以选择非加密的散列算法,如 xxhash[6] 或 seahash[7]。

本地流

与磁盘进行数据交互的可以分为三类:定位,读取,写入这三个过程互相组合,需要我们有不同的应对方案

定位

主要是写定位错误 (Misdirected writes) ,数据写入的磁盘位置与预期不符。这个错误可能导致两个文件同时被污染。

读取

最常见的 SDC 错误发生过程,这是因为其本质上可能是多种错误导致的最终结果。最常见的情况有:

  1. 超过扇区 ECC 检错能力的错误
  2. 读取过程中的 bit flipping
  3. 所读取的数据在写入过程中的错误
写入

主要为写丢失 (lost writes),这个错误意味这没有写入成功的情况下返回写入完成(注意和掉电导致的缓存数据未刷入非易失性存储介质的情况相区别)。其后果是在正确的位置读到旧数据。

另外,需要注意的是,SDC 在 HDD 上有扩散趋势[8]

磁盘保护

磁盘厂商针对 SDC 能做的是尽量保证数据在磁盘内不出问题,各家厂商都有自己的 end-to-end integrity 技术。我们的存储系统主要是由 SATA 和少量 SSD 组成。服务器系统盘则可能为 SAS 盘(以上均为企业级磁盘)。其中绝大多数的 SATA 盘中并没有 SDC 防御机制。

SAS 盘提供 Fat-Sector 来进行保护。其中包括 CRC, 地址标签,程序标签。[9]

SSD 的 flash media 层以及 DRAM 都不易发生 bit flipping 。但在 controller 中有大量 SRAM CMOS 是非常容易发生错误的。 Intel 为企业级 SSD 在做了一系列保护之后,还进行了 high intensity particle beams 实验来做 SDC 测试[10]

文件系统保护

xfs 提供了元数据的一致性保护[11],其措施能避免 读 与 misdirected 错误。由于对象存储不存在修改文件元数据信息的场景,因此 lost writes 的未处理可以接受。相对而言, zfs 则提供了全面的一致性校验[12]。但 zfs 的文件级别的保护并不适用于对象存储 append-only 的场景。

Scrub

Scrub 可以分为两类,一类是 Media Scrubs (可以通过 SCSI cmd 触发),另一种是 Data Scrubs。这分别代表磁盘内部对扇区进行扫描,以及在应用层对数据摘要的对比扫描。

我们常说的就是 Data Scrubs。这种 Scrub 的目的是检测 silent corruption,它可能说明本地流中某个或某几个环节有问题,但不能直接表明扇区有错误,尽管我们可以通过这样一个过程来发现扇区故障。

实践

控制流

必须进行 end-to-end integrity 校验。使用 seahash 算法在请求体中追加校验值,接受方必须进行数据对比。

副本集群

副本集群采用最终一致性的策略要预防 SDC。对于多个副本来说,同时发生写错误的概率微乎其微。因此我们在读时校验,在校验失败后锁定相应磁盘即可。

需要注意的是,将原始数据与摘要分开存放并不能处理 misdirected writes 错误。

对于我们所使用的 xfs 文件系统来说,由于其开启了 metadata 保护,因此文件系统层面很难出现 misdirected 错误。因此,倘若我们要进行 misdirected writes 保护,只需要在原先的 checksum 前加上该数据在大文件块中的偏移量即可。偏移量一致且能返回数据和 checksum 的概率几乎可以忽略不计(在数据错误的情况下)

特别需要说明的是 lost writes 错误,lost writes 的应对方案主要有两种:

  1. read-after-write
  2. checksum 与 data 分开存放

这两种方案的代价都非常高昂。在对象存储 append-only 的场景下,lost writes 发生且校验一致的概率微乎其微。因此 lost writes 在副本集群下不采取特别的措施。

纠删码集群

EC 由于没有副本机制保护,因此必须进行 misdirected writes 保护,其方法与多副本中描述一致,这里就不在赘述了

数据库集群

数据库要面临的 SDC 风险与本地流一致,利好消息是数据库集群为多副本架构。在 chekcusm match 之后,就意味着获得的值不会造成系统风险。如果发生了 misdirected writes 或者 lost writes 错误导致查询失败,我们几乎可以肯定的能从其它副本中获得正确的数值。除了加入 checksum 字段之外,为数据库所使用的 SSD 必须符合我们对于可靠性的要求。

结束语

此篇文章如图幽灵一般结束了。。。

附录

  1. Amazon S3 Avaliability Event: July 20, 2008, http://status.aws.amazon.com/s3-20080720.html
  2. Facebook temporarily loses more than 10% of photos in hard drive failure, http://www.computerworld.com/s/article/9129263
  3. Netflix Outage Blamed on Hardware, https://www.pcmag.com/article2/0,2817,2328778,00.asp
  4. Jonathan Stone and Craig Partridge, When The CRC and TCP Checksum Disagree
  5. Theresa Maxino, Revisiting Fletcher and Adler Checksums
  6. xxhash, http://www.xxhash.com
  7. SeaHash: Explained: http://ticki.github.io/blog/seahash-explained/
  8. An Analysis of Data Corruption in the Storage Stack
  9. HGST End-to-end Data Protection
  10. Data integrity in solid state drives: what supernovas mean to you, https://itpeernetwork.intel.com/data-integrity-in-solid-statedrives-what-supernovas-mean-to-you/
  11. XFS Self Describing metadata, https://www.kernel.org/doc/Documentation/filesystems/xfs-self-describing-metadata.txt
  12. End-to-end Data Integrity for File Systems: A ZFS Case Study