关于服务器:服务器内存故障预测居然可以这样做

3次阅读

共计 6500 个字符,预计需要花费 17 分钟才能阅读完成。

作者:vivo 互联网服务器团队 -  Hao Chan

随着互联网业务的疾速倒退,基础设施的可用性也越来越受到业界的关注。内存产生故障的故障率高、频次多、影响大,这些对于下层业务而言都是不能承受的。

本文次要介绍 EDAC(Error Detection And Correction)框架在内存预测方面的利用。首先介绍了 EDAC 利用的背景,接着是 EDAC 的原理介绍,而后通过 EDAC 装置——配置——测试过程具体地介绍了 EDAC 在 vivo 服务器上的利用,最初提出了内存预测应用 EDAC 的计划总结以及服务器 RAS(Reliability, Availability and Serviceability)利用减小硬件故障对系统的影响的瞻望。

一、背景介绍

随着互联网业务的疾速倒退,基础设施的可用性也越来越受到业界的关注。然而硬件故障始终以来都是一种普遍存在的景象,因为硬件故障而造成的损失往往是微小的。在服务器各个部件中,除硬盘故障以外,内存故障是第二大常见的硬件故障类型。并且服务器内存的数量泛滥,vivo 的内存数量达到 40w+ 条,内存故障造成的最重大的结果是会间接导致系统解体,服务器宕机,这些对于下层业务而言都是不能承受的。

内存故障可分为 UCE(Uncorrectable Error)和 CE(Correctable Error)。当硬件侦测到一个谬误,它会通过两种形式报告给 CPU 的。其中一种形式是中断,这种状况如果是 UCE 也就是不可纠正错误,则可能会导致服务器立马宕机。如果是 CE,即可纠正错误,硬件会利用一部分资源对该谬误进行修复,而当内存 CE 累计过多,无奈进行自我修复时,则会产生 UCE,造成零碎宕机重启。因而,咱们须要尽早地发现 CE 过多的内存条,及时进行更换,防止造成重大的损失。

以往内存故障大多是通过 MCE(Machine Check Exception)log 和 BMC 记录的 SEL(System Error Log)日志联合去发现定位故障的,而这些最大的问题是不可能提前发现内存问题,往往是服务器宕机重启后才被动发现的。除此之外还存在以下几个方面的问题:

  1. MCE 日志很难间接定位到故障内存槽位。
  2. 没有直观的 CE/UCE 谬误计数。
  3. 无奈依据内存条上 CE/UCE 的数量判断内存的健康状况。

针对以上问题,咱们须要寻找别的解决方案。这时 EDAC 便呈现在咱们的视线,它可能完满地解决下面所说的所有问题,并且可能实现内存 CE 故障的被动发现,提前发现内存问题。

本文将次要介绍 EDAC 的原理以及如何通过它实现的故障预测。

二、EDAC 原理介绍

EDAC(Error Detection And Correction)是 Linux 零碎的谬误检测和纠正的框架,它的目标是在 linux 零碎运行过程中,当谬误产生时可能发现并且报告出硬件谬误。EDAC 由一个外围(edac\_core.ko)和多个内存控制器驱动模块组成,它的子系统有 edac\_mc、edac_device、PCI bus scanning,别离是负责收集内存控制器,其余控制器(比方 L3 Cache 控制器)以及 PCI 设施所报告的谬误。

这里次要讲述 EDAC 子系统 edac\_mc 是如何收集内存控制器的谬误。内存 CE 以及 UCE 是 edac\_mc class 获取的次要谬误类型,它次要波及了以下几个函数:

  • 【edac\_mc\_alloc()】:应用构造体 mem\_ctl\_info 来形容内存控制器,只有 EDAC 的外围能力接触到它,通过 edac\_mc\_alloc()这个函数去调配填充构造体的内容。
  • 【edac\_device\_handle_ce()】:标记 CE 谬误。
  • 【edac\_device\_handle_ue()】:标记 UCE 谬误。
  • 【edac\_mc\_handle_error()】:向用户空间报告内存事件,它的参数包含故障点的层次结构以及故障类型,累计的相干 UCE/CE 谬误计数统计。
  • 【edac\_raw\_mc\_handle\_error()】:向用户空间报告内存事件,然而不做任何事件来发现它的地位,只有当硬件谬误来自 BIOS 时,才会被 edac\_mc\_handle_error()间接调用。

那么 EDAC 是如何管制和报告设施故障的呢?它又是如何将故障定位以及记录到对应的内存条上的呢?

Linux 是通过 sysfs 文件系统来展现内核设施的档次关系,EDAC 则通过它来管制和报告设施故障。EDAC 是通过形象进去的内存控制器模型,将故障定位到对应的内存条上,这次要也是与内存在零碎中的排列构造相干。CPU 对应的每个 MC(memory controller)设施管制着一组 DIMM 内存模块,这些模块通以片选行 (Chip-Select Row,csrowX) 和通道 (Channel,chX) 的形式排布,在零碎中能够有多个 csrow 和多个通道。

通过下列门路能够查看相干文件:

# ls /sys/devices/system/edac/mc/mc0/csrow0/
ce_count  ch0_ce_count  ch0_dimm_label  ch1_ce_count  ch1_dimm_label  dev_type  edac_mode  mem_type  power  size_mb  subsystem  ue_count  uevent

局部文件的用处如下表所示:

EDAC 如果发现硬件设施控制器报告的是 UE 事件,并且控制器要求 UE 即停机,则会重启零碎。控制器查看到 CE 事件后,能够看作对将来 UCE 事件的预测。咱们能够通过一些屏蔽伎俩或者更换内存条缩小 UE 事件以及零碎宕机的可能性。

三、EDAC 的利用

EDAC 在 vivo 现网中的利用过程次要分为以下几步:

(1)EDAC 在 Linux 零碎中的反对

EDAC 在 Linux 2.6.16 以上的内核中以及零碎发行版都曾经失去了反对,然而内核中 edac 的驱动模块却有很多,不同的零碎版本反对的驱动模块却不尽相同,能够通过以下形式查看零碎反对哪些驱动模块。

# ls /lib/modules/3.10.0-693.el7.x86_64/kernel/drivers/edac/
amd64_edac_mod.ko.xz  edac_core.ko.xz     i3000_edac.ko.xz  i5000_edac.ko.xz  i5400_edac.ko.xz  i7core_edac.ko.xz   ie31200_edac.ko.xz  skx_edac.ko.xz
e752x_edac.ko.xz      edac_mce_amd.ko.xz  i3200_edac.ko.xz  i5100_edac.ko.xz  i7300_edac.ko.xz  i82975x_edac.ko.xz  sb_edac.ko.xz       x38_edac.ko.xz

那么这些驱动模块之间有什么区别?咱们又应该怎么抉择呢?拿 sb\_edac 与 skx\_edac 进行阐明,咱们先来看一下它们形容。

# modinfo sb_edac
filename:       /lib/modules/3.10.0-693.el7.x86_64/kernel/drivers/edac/sb_edac.ko.xz
description:    MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers -  Ver: 1.1.1
...

# modinfo skx_edac
filename:       /lib/modules/3.10.0-693.el7.x86_64/kernel/drivers/edac/skx_edac.ko.xz
description:    MC Driver for Intel Skylake server processors
...

通过查看形容咱们发现,原来驱动模块是和 CPU 的产品架构无关,装置不匹配的模块会呈现 edac-util: Error: No memory controller data found 这样的报错。通过咱们测试发现,一般而言,如果 CPU 的产品架构反对的驱动模块存在的话,零碎会默认装置反对的驱动。

(2)配置内存槽位与物理槽位对应关系

通过 sysfs 文件系统咱们能够看到哪个 CPU 的哪个内存管制下的哪个通道的哪条内存的 CE 计数,然而它对应的零碎下的哪一个内存呢,毕竟咱们服务器日常的运维,常常看到的是零碎槽位名称,那么它们的关系是怎么的呢?

通过查看 edac-util 的源代码构造发现,它提供了 labels.db 这个配置文件,去存储服务器内存的零碎槽位与物理槽位对应关系。

# cat /etc/edac/labels.db
# EDAC Motherboard DIMM labels Database file.
#
# $Id: labels.db 102 2008-09-25 15:52:07Z grondo $
#
#  Vendor-name and model-name are found from the program 'dmidecode'
#  labels are found from the silk screen on the motherboard.
#
#Vendor: <vendor-name>
#  Model: <model-name>
#    <label>:  <mc>.<row>.<channel>

编写这个文件的时候,咱们须要晓得内存是如何在服务器上是怎么插,并且晓得它对应的是零碎中的槽位名称,不同服务器型号零碎槽位的名称不同。个别能使内存性能施展最大的插法,总结起来就是对称插法,并且先插离 CPU 远的通道,每个通道外面先插离 CPU 远的槽位。

配置实现后,如何去查看是否配置正确呢,次要分为两步:

① 应用 edac-ctl 查看 SYSFS CONTETS 条数是否正确

② 用 dmidecode -t memory 查看内存的名称是否统一

这里咱们还遇到一个 rpm 包的问题:对于厂商的主板的 model name 前后有多个空格的状况,edac-ctl 无奈辨认到主板的 model name,lables.db 无奈注册胜利。最初咱们批改了 edac-utils 包的源代码,从新进行了打包。

(3)测试与验证

装置配置实现后,就到了测试验证环节了,要怎么去验证 EDAC 的正确性,保障 CE 谬误记录到了对应的内存条上呢?咱们能够应用 APEI Error inject 做一些谬误注入的测试。

APEI Error inject 它的原理是依赖 APEI(ACPI Platform Error Interface),它的构造中有四张表:

  • BERT(Boot Error Record Table):次要用来记录在启动过程中呈现的谬误
  • ERST(Error Record Serialization Table) :用来永恒存储谬误的形象接口,存储各种硬件或平台的相干谬误,谬误类型包含 Corrected Error(CE),Uncorrected Recoverable Error(UCR),以及 Uncorrected Non-Recoverable Error,或者说 Fatal Error。
  • EINJ(Error Injection Table):次要作用是用来注入谬误并触发谬误,是一个用来测试的表
  • HEST(Hardware Error Source Table):定义了很多谬误源和谬误类型。定义这些硬件谬误源的目标在于标准化软硬件谬误接口的实现。

这里是通过 debugfs 向内核 APEI 构造中的 EINJ 表注入内存谬误来进行测试,debugfs 是一种用于内核调试的虚构文件系统,简略来说就是能够通过 debugfs 映射内核数据到用户空间,使用户可能批改一些数据进行调试。

办法步骤如下:

# 查看是否存在 EINJ 表
# ls /sys/firmware/acpi/tables/EINJ 

# grep < 以下字段 > /boot/config-3.10.0-693.el7.x86_64

CONFIG_DEBUG_FS=y 
CONFIG_ACPI_APEI=y
CONFIG_ACPI_APEI_EINJ=m

# 装置 einj
# modprobe einj


# 查看内存地址范畴,这一步是因为 /proc/iomem 这个文件记录的是物理地址的分配情况,有些内存地址是零碎预留寄存以及其余设施所占用的,无奈进行谬误注入。# cat /proc/iomem | grep "System RAM"
00001000-000997ff
00100000-69f79fff
6c867000-6c9e6fff
6f345000-6f7fffff
100000000-407fffffff

# 查看内存页大小
# getconf PAGESIZE
4096 即 4KB

# 进入 edac 谬误注入目录

# cat /proc/mounts | grep debugfs
debugfs /sys/kernel/debug debugfs rw,relatime 0 0

# cd  /sys/kernel/debug/apei/einj/

# 查看反对注入的谬误类型
# cat available_error_type
0x00000008  Memory Correctable
0x00000010  Memory Uncorrectable non-fatal
0x00000020  Memory Uncorrectable fatal

# 写入要注入的谬误的类型
echo 0x8 > error_type 

# 写入内存地址掩码
echo 0xfffffffffffff000 > param2

# 写入内存地址
echo 0x32dec000 > param1

# 写入 0x0,若为 1,则会跳过触发环节
echo 0x0 > notrigger

# 写入任何整数触发谬误注入,这是谬误注入的最初一步
echo 1 > error_inject

# 查看日志
# tail /var/log/message
xxxxxx xxxxxxxx kernel: [2258720.203422] EDAC MC0: 1 CE memory read error on CPU_SrcID#0_MC#0_Chan#0_DIMM#1 (channel:0 slot:1 page:0x32dec offset:0x0 grain:32 syndrome:0x0 -  err_code:0101:0090 socket:0 imc:0 rank:0 bg:0 ba:3 row:327 col:300)

# 应用 edac-util - v 查看,能够看到对应的内存条上新增了 CE 计数

四、总结与瞻望

  1. EDAC 能够明确的获取到服务器的每条内存上的 CE 计数,咱们能够通过 CE 计数去设定阈值,剖析 CE 计数曲线等,联合其余 MCE log、SEL 等对内存进行健康状况评估,进行内存预测。EDAC 在 vivo 服务器全量上线过程以来,累计提前发现 450+ case 的内存 CE 问题,服务器的宕机数量显著缩小。对满足报修规范服务器业务进行迁徙,并更换相应的内存条,防止因服务器忽然宕机导致业务的不稳固,甚至因而造成的损失。
  2. EDAC 是服务器 RAS(Reliability, Availability and Serviceability)在内存方面利用的一小部分。RAS 是指通过一些技术手段,软硬件联合去保障服务器的这三个能力。RAS 在内存方面的优化还有很多,例如 MCA(Machine Check Architecture)recovery 等等。将来咱们也将引入 RAS 去缓解硬件故障对系统的影响。

参考资料:

  1. https://www.kernel.org/doc/html/latest/driver-api/edac.html
  2. https://www.kernel.org/doc/html/latest/admin-guide/ras.html
  3. https://www.kernel.org/doc/html/latest/firmware-guide/acpi/apei/einj.html
  4. https://github.com/grondo/edac-utils/
  5. https://uefi.org/specs/ACPI/6.4/18\_ACPI\_Platform\_Error\_Interfaces/ACPI\_PLatform\_Error_Interfaces.html
正文完
 0