本文完整阅读约需 28 分钟,如时间较长请考虑收藏后慢慢阅读~

笔者有一台服役多年的 X79 芯片组台式机,配备了 E5-2680 处理器,由于最近需要升级更大容量的 ECC 内存,便为其刷入了新的 BIOS。在配置 BIOS 的过程中,突然发现 BIOS 设置里多了一项内存模式,即标题中的 LockStep 模式,好奇心驱使下,笔者在搜索引擎中搜素 LockStep,却所获不多。本文将为读者分享我在探索这一模式过程中的发现,以及解释该模式为什么能让 ECC 内存比可靠更可靠。

0x01 现象

首先介绍一下笔者的电脑配置:

CPU:Intel E5-2680
芯片组:X79
内存:4*8GB DDR3 ECC 1333MHz

如序言所述,笔者在 BIOS 的设置中找到了一个名为内存模式(Memory Mode)的选项,其中包含四项:

  • 独立(Independent)
  • 镜像(Mirroring)
  • 锁步(Lock Step)
  • 热备(Sparing)

独立、镜像、热备都非常直观,可以类比为磁盘阵列中的 JBODRAID10RAID 热备,但『锁步』是什么意思呢?

笔者抱着好奇心打开了 Lock Step 模式,重启后发现系统一切正常,依旧能够识别 32GB 的内存,但存在两处奇怪的现象:

  1. Windows 识别的内存插槽从 4*8GB 变成了 2*16GB ,和物理内存不一致:

  1. 使用 AIDA64 对内存读写速度进行基准测试,读写速度均从 40GB/s 降低到了 20GB/s

以上现象似乎表明,开启了 Lock Step 之后,相邻的内存被合并了,并且通道数也从 4 通道变成了 2 通道。

但这个模式到底有什么意义呢?为什么它会在不影响容量的情况下导致通道数下降,进而影响性能呢?它损失了性能,换取了什么呢?

0x02 探索

1. 寻找思路

带着众多疑问,笔者打开了搜索引擎,尝试搜索 Lock Step in Computer(因为 Lock Step 作为一个单词,其实和电脑没有关系,指的是军事上军人紧贴着同步前行的步调),却搜到了大量和内存无关的内容:

搜索结果往往指向多处理器架构下的锁步模式,即保证不同处理器的时钟周期同步,避免出现竞态错误。显然这不是我们想要的。

于是笔者换了一个思路,尝试在中文互联网中搜索 Lock Step ,搜索到了哔哩哔哩上的一篇文章:如何选择内存模式?(Independent/Mirroring/Lock Step)区别与性能 – in a nutshell – 哔哩哔哩

相比笔者上文的发现,这篇文章尽管写了很多,但依旧只流于现象,并没有解释这个模式背后的原理。好在这篇文章并非一无是处,因为它提到了“安全性”和“高级 ECC”,这为我们提供了探索的方向。

也就是说,这个模式是只存在于 ECC 内存架构中,它损失了性能,带来更高的“安全性”,而对于 ECC 而言,安全性就是可靠性;此外,既然叫高级 ECC,也就说明了它基于 ECC ,但比 ECC 更可靠。

2. 精确搜索

找到了突破点,于是笔者开始着重搜索 LockStep Memory ECC 关键词,搜索到了这条 Wikipedia 页面:Lockstep (computing) – Wikipedia

笔者摘录其中较为关键的一部分:

Lockstep memory
See also: Chipkill

Some vendors, including Intel, use the term lockstep memory to describe a multi-channel memory layout in which cache lines are distributed between two memory channels, so one half of the cache line is stored in a DIMM on the first channel, while the second half goes to a DIMM on the second channel. By combining the single error correction and double error detection (SECDED) capabilities of two ECC-enabled DIMMs in a lockstep layout, their single-device data correction (SDDC) nature can be extended into double-device data correction (DDDC), providing protection against the failure of any single memory chip.[2][3][4][5]

简而言之:Lock Step 只是一个商业用语,无需钻牛角尖理解其字面意思,本质上是将一个内存通道的缓存线对半平分到两个内存条上,利用 ECC 内存条的纠错能力,可以在双内存条环境下将单设备数据纠正(SDDC)升级为双设备数据纠正(DDDC),以抵御任何单个存储芯片的故障。

如果读者此时已经感觉一头雾水:什么是缓存线?ECC 内存条提供了什么纠错能力?基于什么原理纠错?单双设备数据纠正是什么意思?为什么 DDDC 可以抵御任何芯片的故障?没关系,笔者曾和你有一样的感受,尤其在使用上述关键词搜索了大量的技术资料后,接下来就让我们逐一分析这些术语背后的含义。

0x03 分析

1. 什么是缓存线

在了解缓存线之前,笔者希望读者能理解 CPU 访问内存的分层架构,如果不了解,推荐阅读这篇文章:计算机缓存Cache以及Cache Line详解 – 知乎

很多书籍将 Cache Line 翻译成缓存线,会给人一种和流水线类似的错觉,但笔者认为 Cache Line 更应该被翻译为缓存行,即缓存数据的单元。该单元在 64 位处理器中一般是 64Byte,而两条内存共享一个缓存行,也就意味着逻辑上这两条内存可以被合并为一条,在 CPU 或内存控制器看来,这就是一根内存。

2. ECC 内存条

如果读者没有见过 ECC 内存条,去网上搜索内存条的照片,找到最丑的那一根就是了:

如果说将芯片横竖放置是为了尽量利用空间,尚且能够理解,但请读者数一数这根内存条上有多少颗芯片:19 颗!

是的,对于习惯了二进制的我们而言,19 无疑是一个不和谐的数字,从标签上体现,这颗内存命名是 16GB 的内存,而搜索颗粒信息我们可以得知,中间那颗芯片是 REG 寄存器,便于 CPU 驱动更大容量的内存(感谢网友任勇勘误),而剩余的 18 个颗粒均为容量 8Gbit,即 1GByte 的颗粒,加起来……明明是 18 呀?容量为什么只剩 16GB 了呢?剩余的 2GB 到哪里去了呢?

3. ECC 内存条纠错的原理

要想知道为什么 ECC 内存相比普通内存多出了几颗内存颗粒,就要先了解 ECC 内存条是如何纠错的。如果读者有计算机专业背景,且本科没有翘掉计算机组成原理的课程,应该无需笔者重新解释纠错和错误检测的原理,但如果读者和笔者一样,一节计算机组成原理都没去上过,只在考试的时候见了老师一面的话,笔者还是愿意翻出当年的书籍,来稍微解释一下 ECC 内存条在纠错过程中涉及的算法:

3.1 奇偶校验

奇偶校验,即 Parity Check,通常用于确定数据是否出错,可以被分别分为奇校验和偶校验,以奇校验为例:如果 8Bit 数据采用 1Bit 奇校验,那么当数据为 10100010 时,奇校验结果应该为 1,因为这些数字有奇数个 1,反应在电路上则是对比特进行异或运算获得奇偶校验的结果。

3.2 纠错码

纠错码,即 Error Correcting Code,其实是一类编码方式的统称,而在内存条中,业界通常会使用汉明码来存储多余的纠错位(其实在计算机网络和存储设备中也会使用同样的算法),在读取数据的时候计算读取出数据的汉明码,与内存中额外存储的汉明码进行比对,如果数据不一致,则说明数据出现错误,此时再利用汉明码的排错原理,获取错误的比特位,进行修复。

如果读者想要了解汉明码是如何检测错误的,可以阅读这篇文章:汉明码——计算机网络——全网最通俗的讲解扬俊的小屋-CSDN博客汉明码

但由于计算汉明码速度慢于奇偶校验,因此一般不使用汉明码进行错误检测,而是使用奇偶校验进行错误检测,再使用汉明码恢复特定 Bit 的错误。

解释完 ECC 内存条纠错的原理,相信读者应该理解了为什么 ECC 内存条需要比一般内存条多一些颗粒了。业界一般会使用 16 个 Bit为一个校验单位,这也就解释了为什么 16GBit 的内存条要使用 18GBit 的颗粒,其中一个颗粒用于存储汉明码,另一个颗粒则用于存储奇偶校验码,即 256Bits 数据最后在内存中的占用为 288Bits(256 + 16 + 16)。借用一张来自超微的说明书便于读者理解:

4. 什么是单设备数据纠正(SDDC)?

此处单设备是相对双设备而言,读者可以将其理解为一根内存条内实现数据纠正,其纠错过程如下所示:

图中 D0 ~ D15 是存储颗粒,而 P 是奇偶校验颗粒,C 是纠错颗粒。此时我们假设 D0 颗粒由于强电磁影响导致一个比特出现了翻转,即数据出现了错误。

如果受影响的数据是笔者买煎饼果子的一笔钱,数目使用 64 位整数存储,其中的第 16 位从0 变成了 1。在比特翻转的影响下,这笔数目可能会从 1000b 即 8 元,变成 1000000000001000b 即 32776 元:


由于整个交易系统中的一环出现了错误,这笔交易可能会出现两种结果:携带支付金额的交易出现签名校验错误,或由于笔者的余额不足交易失败。但不管是哪一种,对于追求可靠性的行业,如科学计算、金融、商业甚至是臭打游戏的我们而言,都会带来极大的困扰。更别提比特错误可能导致潜在的数据溢出问题,甚至能够导致巨大的灾难:阿丽亚娜-5运载火箭 – 维基百科,自由的百科全书

但好在有一直在努力的数学家和科学家们,于是我们有了 ECC 内存,也有了“不会溢出”的 Python语言。回到 SDDC 上,如果有一个比特出现错误,那么在下次读取这个区域的时候,其奇偶校验值会出现翻转,此时我们可以使用汉明码找到出现错误的比特,并按照奇偶校验的预期结果对其进行修复。

5. 什么是双设备数据纠正(DDDC)?

ECC 内存加持下的 SDDC 似乎能够修复由单个比特翻转导致的内存错误,这很不错,但为什么这个颗粒会出现比特翻转呢?会不会是因为这个颗粒已经濒临损坏?每次出现问题都进行修复是否会导致内存稳定性下降?或者如果出现的不是比特翻转而是死比特,无论如何都无法修正区域内的错误,又该怎么办呢?难道就只能坐等数据丢失,或使用昂贵又缓慢的内存镜像吗?双设备数据纠正就是在 ECC 基础上用于解决内存颗粒失效的方案,它不仅可以保证一颗内存颗粒故障时的性能可靠,还能保证两颗内存颗粒故障时的安全性。

6. 为什么 DDDC 可以抵御任何两个颗粒的故障?

免责声明:下文小剧场纯属虚构,如有雷同,懂得都懂😄。

那么,古尔丹,代价是什么呢?为什么 DDDC 可以如此强大,强大到能抵御两个颗粒的故障?根源在于 DDDC 充分利用两根内存条中可用的四块校验区域,使其能够承担多种职责。

通过上文那张超级丑的三星内存条照片,读者应该能看出来,虽然我们人为给两个颗粒设定了校验和纠错的角色,但他们和普通的内存颗粒其实并无区别,上文解释汉明码的时候,有提到过其实汉明码兼有识别错误和纠错的能力,也就意味着奇偶校验在必要情况下可以被舍弃,但多必要算必要呢?一个颗粒出现错误,就要将错误的颗粒迁移到奇偶校验颗粒上,然后损失这根内存条的性能吗?DDDC 就是为了解决这个问题而出现的一种架构:

可以看到,两条内存被放置在一个Buffer里(即 Cache Line),其中内存条 0 的冗余颗粒全部用来存储两根内存条中的汉明码,而内存条 1 的冗余颗粒分别用于存储奇偶校验码(数据和校验位的比例翻倍)和冗余。

假设可怜的 D0 颗粒背负了无数次算错煎饼果子钱的锅后终于开始『摆烂』,触发了内存控制器的忍受阈值,即“DDDC Device Sparing event”,此时内存控制器会命令 D0 颗粒赶快调岗,于是 D0 颗粒带着它最后一次修复的数据来到了新的场所(即冗余颗粒)上,如下图所示:

在冗余颗粒上的 D0 终于愿意安分下来,但在 D0 旁边的 D1 看着 D0 搬进了新房子,却有些不平衡,也开始『摆烂』,触发大量的 ECC 纠错,再次导致“DDDC Device Sparing event”被触发,但此时已经没有新房子能给 D1 住了,于是内存控制器认为保留奇偶校验颗粒带来的性能已经不如保障数据安全重要了,命令奇偶校验颗粒立刻滚蛋,将奇偶校验留下的职责交给 ECC 颗粒进行,尽管 ECC 颗粒有苦难言,但它们的职责实在太重要,一旦请辞就会导致内存可靠性出现问题,为了考虑大局,只得勉强接下校验的任务,并报告系统管理员:咱俩要撑不住了,请求管理员注意并解决,否则后果自负!而 D1 此时已经带着最后一次修复的数据住进了奇偶校验颗粒中,如下图所示:

尽管此时该通道的数据安全和性能均处于大厦将倾的状态,但好在每个比特依旧各司其职,只是如果管理员继续放任不管,就不会再有机会给第三个『摆烂』的内存颗粒了……

0x04 结论

相信笔者介绍到这里,读者应该能理解 BIOS 里那个 Lock Step 内存模式的意义了:在损失一半通道的前提下,保证内存容量不变,还能使得安全性极大提升。

该模式在工作正常的时候对内存延迟无影响,对内存容量无影响,对内存读写速度减半,对于个人用户而言,特别适合对内存吞吐量要求不高或通道数较多的环境(如利用白菜价的 X79、X99 平台搭建工作站)。

在完成本文写作的过程中,笔者参考了来自互联网上的大量资料,还翻箱倒柜找到了一个字都没写过的,99新计算机组成原理课本,恶补了当年遗漏的知识。此外还想真诚感谢计算机组成原理给了我 61 分的某云华老师,毕竟他的课程伴随了我大学生涯四年,尽管我的签到记录屈指可数,但他从不记恨,甚至在毕业设计阶段最后一次高抬贵手,让我大学生涯最后一程走得同他之前教过我的每堂课一样顺利。

本文如有错误或遗漏,纯属笔者水平有限,欢迎在评论区指正,笔者愿意虚心接受并对本文进行必要的修订。


0x05 扩展阅读

  1. Lockstep (computing) – Wikipedia
  2. Chipkill – Wikipedia
  3. Independent Channel vs. Lockstep Mode – Drive your Memory Faster or Safer | Intel® Developer Zone
  4. 如何选择内存模式?(Independent/Mirroring/Lock Step)区别与性能 – in a nutshell – 哔哩哔哩
  5. Memory RAS Configuration User’s Guide 1.0.indd
  6. The Benefits of Chipkill-Protect for PC Server Main Memory
  7. 内存的可靠性、可用性和诊断功能(内存RAS)-宿迁波仔博客
  8. Parity(奇偶校验)和ECC(错误检查和纠正)_IC小鸽的博客-程序员宅基地 – 程序员宅基地