MENU

【歪门邪道】探究Linux为什么突然死机 & 为NUC更换SSD

May 1, 2024 • 瞎折腾

上一篇文章介绍了我购买并配置Intel NUC13Pro的过程。在使用过程中,我发现有时候开机会找不到启动盘,有时候系统会突然卡死。本文将记述我逐步排查问题,并最终更换SSD的过程。

SSD掉盘的三种形式

其实在最开始的一周,这块金士顿的SSD并没有表现出太多的问题。偶尔在打开IDEA的时候会卡顿,有时候会直接导致系统卡死。我一开始以为是Swap的原因,因为Swap给的太小了,我平时工作需要开40多个Chrome标签,还有2个左右的IDEA,整体不够用。后来紧急从京东下单了一条DDR4 32GB的内存条,变成了8+32的配置,内存就赋予了很多,现在基本上日常占用在20GB左右,因此也就不着急升级到32+32了。但这个时候系统卡顿的情况还是会偶尔发生,但不是很频繁,我就没在意。第一次系统卡死发生后我就开启了Sysrq,这样我就可以通过REISUB来安全的重启系统了。

但后来我发现了两个现象:首先就是卡死后重启有机率找不到SSD,表现形式就是BIOS提示A bootable drive has not been detected,进入bios后发现NVMe槽是空的,和没插盘是一样的。其次就是我注意到在按下Alt+PrtScr+R之后,输出会被强制切换到控制台,这个时候有机会能看到NVMe相关的报错,主要有三条:

  • 第一条的具体报错记不清了,大概就是Btrfs进行IO操作的时候因为超时失败了
  • 第二条也记不清了,大意是NVMe没有及时响应系统的请求,内核尝试reset控制器
  • 第三条则是一个Abort status: 0x371

但大部分情况都能在重启后解决,于是我就没有当回事。直到周五晚上我打开IDEA,系统突然崩溃——和卡死不同,鼠标和UI都是有响应的,但任何从硬盘读数据的行为都会被阻塞(事后才知道,这个时候盘已经掉了,ui还能响应全靠内存的缓存)。于是我便重启了,重启之后看到控制台询问我的luks密码,我就按了电源键关机,睡觉去了。可等到周六我再开机,那盘就再也没出现过了。

当时我想可能是因为金手指接触不良,我拆开擦擦就是了。结果拆开再装回去,还是不识别。我就很奇怪,于是就保持后盖打开,装好SSD,再开机——识别了。好的,那我们把后盖合上,然后再开机——系统找不到盘。

我:???

此时我心中有了一些假设,因为刚才拆下来擦金手指的时候我就觉得这块盘的做工极差——像是三星和西数的SSD,你轻微施力掰它,它的PCB是比较硬的,这种手感的回馈就是告诉你不要掰;而金士顿这块硬盘的PCB很薄,也很软,你轻微施力掰它,它就随着你用力而弯曲,没有太多的抵抗。而NUC为了节省空间,它的SSD并不是贴在主板上的,反而是悬空的。在垂直方向,先是网卡在主板上,然后是SSD摞在网卡上。所以我推测会不会是背盖上的散热条把SSD压弯了,导致M.2接口接触不良呢?针对这个假设,我做了一个实验:

  • 不装背盖:可以检测到盘
  • 装上背盖,但不拧螺丝:可以检测到盘
  • 装上背盖,用手旋紧螺丝:有机率可以检测到盘。如果遇到掉盘,拆下背盖后重新安放、拧紧
  • 装上背盖,用螺丝刀拧紧螺丝:我试了好几次,就是检测不到盘

虽然不能确定就是散热条把SSD压弯了导致接触不良,但从结果来看,螺丝的松紧程度确实能够影响盘能不能被识别到。因此我想到了一个很简易的办法:把纸叠起来,垫在ssd底下。因为叠起来的纸有弹性,所以可以确保把SSD压在散热条上,这样就可以保证它处于正确的位置了。

经过这样一番折腾,我成功地解决了PCB太软的问题。但这还并不是问题的全部。周六中午我在进行网络冲浪的时候,突然发现浏览器崩溃了,而且没有崩溃报告,同时所有需要从硬盘读数据的操作都卡住了。我很自然地按下Alt+PrtScr+R,看到了先前说的几条报错信息。于是我就去网络上搜索了一下,大部分结果都指向一个叫做APST的东西。这东西全称Autonomous Power State Transition,中文叫自动电源状态转换。这个功能的主要目的就是在你不使用或轻度使用NVMe盘时自动缩减功耗,从而为移动设备争取一些续航。但这种缩减功耗带来的就是响应延迟的上升,而这里我确实在控制台上看到一个timeout,所以我觉得有戏。根据ArchWiki)所说,Linux内核对于Power State最大延迟设置是25ms,任何超过25ms的硬盘都应该通过内核参数手动调整这个值,来避免Linux误认为NVMe盘出问题了。于是我通过sudo nvme id-ctrl /dev/nvme0n1查看了一下我这个盘的延迟:

ps      0 : mp:5.00W operational enlat:0 exlat:0 rrt:0 rrl:0
            rwt:0 rwl:0 idle_power:- active_power:-
            active_power_workload:-
ps      1 : mp:3.50W operational enlat:0 exlat:200 rrt:1 rrl:1
            rwt:0 rwl:0 idle_power:- active_power:-
            active_power_workload:-
ps      2 : mp:2.50W operational enlat:0 exlat:1000 rrt:2 rrl:2
            rwt:0 rwl:0 idle_power:- active_power:-
            active_power_workload:-
ps      3 : mp:1.50W non-operational enlat:5000 exlat:5000 rrt:3 rrl:3
            rwt:3 rwl:3 idle_power:- active_power:-
            active_power_workload:-
ps      4 : mp:1.50W non-operational enlat:20000 exlat:70000 rrt:4 rrl:4
            rwt:4 rwl:4 idle_power:- active_power:-
            active_power_workload:-

总延迟是enlat + exlat,这么来看,如果SSD进入了4号电源状态,那么总共需要90ms才能响应系统的指令,这远超过Linux内核默认的25毫秒。所以我在YaST中添加了内核参数nvme_core.default_ps_max_latency_us=100000,我打出富裕量,给了100ms的超时。此时我以为这些问题都被解决了,可以高枕无忧了。但随后的事情让我直接去京东下单了新的SSD。

故事发生在周六下午。我在为接下来的五一假期做准备,我计划带着这个NUC和一个便携屏幕出游。这个NUC比笔记本要轻大约一斤多,而这块便携屏幕不用的时候还可以给Switch用,我觉得甚是方便。于是便开始从家里的NAS拷贝一些要看的电影、动漫之类的。就在拷贝途中,整个系统突然崩溃了,那我能怎么办?重启呗。结果重启之后就找不到盘了。

我这一想,纸也垫了,内核参数也加了,怎么就还是有问题呢?而且这次掉盘持续时间很长:无论怎么开机,就是提示找不到。我只能又拆开背盖。拆开背盖之后用手一摸SSD,我本意是想可能还是接触不良,我就伸手押着SSD头部,没想到我瞄的特别准,一手指头就按到主控上去了,当时我就后悔了——烫啊,真他妈烫啊。

凉了差不多十分钟,盖上盖子再开机,SSD又像个好人似的了。于是我便继续复制影视作品,没想到,梅开二度,又来一次。这下我可就犯难了:垫上纸可能会导致SSD过热,毕竟纸基本不导热,而且更像是给SSD加了个褥子。可是不加纸吧,这动不动就掉盘,我真怕数据丢了。每次强制重启之后我都要用btrfs scrub检查一下数据和元数据,幸好没有出错。但是老这样不是办法啊,看了一眼时间,我还有机会,现在下单明天(周日)就能到。于是开始考虑购买哪一款SSD。

首先排除三星,不是它不好——我笔记本的两条SSD都是三星的,我给亲戚组电脑也推荐的三星,我用的很满意——但就是太贵了。我这个月为了NUC和望远镜已经花了不少钱了,我想控制一下预算。但是又得避免因为控制预算而买到类似这个金士顿的情况,于是左思右想,买了2TB的西数SN580。虽然不是顶级产品线,比三星差了不老少,但是我从一些测评来看,它至少稳定,不会翻车,保修也靠谱,三年900TB写入,最主要的是2TB卖1000块钱,隔壁三星1千连1TB都不给你,还要什么自行车啊。

周日上午硬盘如期而至,下面的问题就是怎么在不重装系统的情况下迁移并扩容硬盘。

迁移启动盘

如果是数据盘那就好办了,直接复制粘贴。但是系统盘的话有启动分区,还有好多安装的配置,如果重装的话就太麻烦了。我安装系统时使用了LUKS加密,并且开启了LVM,主文件系统是Btrfs。由于这次是从500GB到2TB的“升级”,所以相对来说还是容易一些。计划大体分两部:使用CloneZilla迁移数据,然后再想怎么扩容。

Clonezilla

Clonezilla一直是一个我很喜欢的工具。它和dd不一样,clonezilla能够感知文件系统。对于没有全盘加密的分区,它可以只保留实际有数据的部分。对于有加密的分区,新版本还可以先解密再按照分区抓取。不过我这里的目的更像是1:1复制整个硬盘,所以我没有选择解密。整个盘500G,实际使用不到80GB,最终经过压缩,占用的数据量只有120GB左右。不过这个是新盘,如果用过一段时间的话,没被使用的部分会留下难以压缩的脏数据,这个到时候就麻烦了。这次好在我有可以用来存储的移动硬盘,因为移动硬盘也是固态,所以抓取很快就结束了。在抓取的过程中,我根据以前的经验,让SSD尽可能处在最佳状态:打开背盖、吹风扇。

抓下来数据之后,保存下来就可以往新的SSD里还原了。还原的过程不需要任何额外的配置,由于分区大小不一样,我选择按照原始分区大小还原,之后由我手动来扩容。还原之后重启,看到屏幕上询问我LUKS密码的字样,我心头的石头就放下了一半。进到系统进行了简单的测试,确认文件系统没有任何错误之后可以进行扩容了。

扩容

本节的命令如果没有特殊说明,则都是在root权限下运行。

扩容阶段我使用的是openSUSE TW的Gnome LiveCD,它里面包含了一个叫做GParted的图形工具,可以用来分区,比YaST的分区工具要好用。

在分区工具里,我发现我的硬盘上竟然有4个分区:1个Linux的启动分区,1个Windows EFI分区(16MB),1个LVM数据卷,还有1个不知道是做什么的大小只有500MB的分区。虽然我在安装系统的时候指示安装器把Windows分区删掉,可能安装器以为我要Dual Boot,就没删干净。不过没关系,这里我们可以把他们删掉,这样一来,nvme0n1p1是Linux的启动分区,nvme0n1p3是LVM数据卷。这个数据卷前后都有空闲空间,虽然前面的空闲空间只有16MB,那也不能闲着。

默认情况下LVM分区是没有解密挂载的,所以我们可以直接开始操作:在GParted里右键LVM卷选择Move,然后通过滑块调整,让前面的空闲空间变为0MB,然后把大小拉到最大。这样除了100MB的启动分区,剩下的就全都是LVM的天下了。保存结果后GParted需要将原来的数据复制过去,就是说前面的16MB不能空着,得让数据整体往前移动16MB。好在NVMe固态硬盘很快,没有十分钟就复制完了。接下来就是让LVM扩容。

我在网上看到一些资料声称要给LUKS扩容。我查询了一些资料,发现LUKS是不需要扩容的,它本质是一种映射:你访问一个块,它把数据解密之后给你,它并不关心这个分区有多大,它只关心在数据写入磁盘之前进行加密、从磁盘读出来之后解密。由于先前我们使用GParted进行了位移操作,所以LVM肯定是没有挂载的。挂载LVM时只能往后延伸分区,并不能位移。如果你挂载了LVM,那么你可以通过关闭再打开的方式让LUKS设备刷新它的大小,或者通过如下命令让LUKS知晓你对分区的变更:

cryptsetup resize <name>

这里的name是解密挂载时的名称,如果你是让GParted挂载的,那么名字通常是<partition>_crypt,比如我的分区是nvme0n1p3,那么我解密挂载的设备就是nvme0n1p3_crypt

当LUKS能够检测到新的硬盘大小之后,我们就可以扩容LVM了。这里涉及到LVM的三个概念:

  • PV,也称Physical Volume,即物理卷。物理卷是在磁盘中实际存储数据的分区,比如我们的nvme0n1p3
  • VG,也称Volume Group,即卷组。一个卷组类似一个存储池,它将多个物理卷抽象成一个块设备,形成一个逻辑上的硬盘
  • LV,也称Logical Volume,即逻辑卷。一个卷组可以分配出多个逻辑卷。逻辑卷就像是虚拟硬盘上的分区,这个也是我们实际给文件系统用的分区

这样就看出来LVM的好处了:通过将多个物理设备抽象成逻辑概念,我们可以保持分区不动的情况下更换或调整物理设备。那么从这个结构中也能看出来,物理卷是最基础的一层,我们应该先扩容它:

pvresize /dev/mapper/nvme0n1p3_crypt

在没有任何多余选项的情况下,pvresize命令会让/dev/mapper/nvme0n1p3_crypt这个物理卷扩展到整个分区。如果你不知道这个路径该用什么,可以使用命令pvs查询所有可用的物理卷。通常情况下只有一个,因为livecd不会用lvm的。调整完成后再看pvs的输出结果,PSize变成1.82TB就算是成功了。

接下来调整逻辑卷。我想调整两个,一个是Swap,从原来的2GB调整成8GB,然后是root,让它占满余下的分区。由于Btrfs可以缩小,所以这里我就让它先占满了。如果你使用的文件系统不支持缩小,那么扩容的时候最好谨慎一些,等不够用了给。不然等日后多了新的需求,却发现硬盘没地方了,那就有点尴尬了。

首先来调整swap分区:

lvresize -L+6G /dev/system/swap

这里的意思是将/dev/system/swap的大小增加6GB。这个路径是怎么来的呢?使用lvs可以查询到,我的卷组名字叫system,swap分区的逻辑卷名字就叫swap,所以这个路径就是这样了。目前我看tab自动补全的效果还是不错的,如果实在不会写,可以让自动补全碰碰运气。

现在分区的大小是变大了,可是上面的文件系统还没有扩容。好在swap分区不存在任何实际的数据,直接格式化就好了:

mkswap /dev/system/swap

这个时候注意检查一下原来系统的fstab,我这里发现fstab使用的是路径,也就是说无论分区的uuid怎么变,只要最后被挂载到/dev/system/swap的就是交换分区。如果你的fstab还在使用uuid的话,那这里要记录一下mkswap输出的新分区的uuid,之后你要自己更新fstab,不然系统是找不到swap分区的,可能会在启动的时候引发内核panic。

接下来就可以扩容root分区了:

lvresize -l+100%FREE /dev/system/root

这里的小写字母L是通过比例来调整分区大小。显而易见,我这条指令让root分区的大小占满剩余空间。完成后查询lvs,确保分区大小如我所愿。最后就可以扩容btrfs了。我很喜欢btrfs的一个点就是它的好多操作就可以在线进行,并且交互简单明了:

mkdir /mnt/root
mount /dev/system/root /mnt/root

这样一来我们就把原来的根分区挂载到/mnt/root路径了。然后使用btrfs进行在线扩容:

btrfs filesystem resize max /mnt/root

这样扩容就完成了。这时就可以修改fstab了(如果需要的话),路径是/mnt/root/etc/fstab。除此之外,还可以顺手检查一下数据和元数据是否正确:

btrfs scrub start /mnt/root
btrfs scrub status /mnt/root

第一条命令启动scrub,第二条命令查询scrub的状态。当第二条命令返回的状态为finish,并且没有error时就万事大吉了。这个时候我们就可以卸载分区了,卸载之后还可以顺手检查一下btrfs的结构完整性:

umount /mnt/root
btrfs check /dev/system/root

我本以为无事发生,结果走到7/7的时候出错了,说qgroup读不出来。这好办,qgroup是和quota(配额)有关的,虽然我现在不用,但是可以先修好:

mount /dev/system/root /mnt/root
btrfs quota disable /mnt/root
btrfs quota enable /mnt/root # 执行完成后要等一会儿,开启配额后需要rescan
umount /mnt/root

这样一通操作之后再去做check,7/7全部通过,非常好。最后我们需要退出livecd,进入原本的系统看看是否一切正常。

进系统

进入系统之后除了检查数据在不在,还可以根据ArchWiki的简易配置一下Power State超时。这是新硬盘的电源状态:

ps      0 : mp:4.80W operational enlat:0 exlat:0 rrt:0 rrl:0
            rwt:0 rwl:0 idle_power:0.3000W active_power:4.80W
            active_power_workload:80K 128KiB SW
ps      1 : mp:3.50W operational enlat:0 exlat:0 rrt:0 rrl:0
            rwt:0 rwl:0 idle_power:0.3000W active_power:3.00W
            active_power_workload:80K 128KiB SW
ps      2 : mp:2.40W operational enlat:0 exlat:0 rrt:0 rrl:0
            rwt:0 rwl:0 idle_power:0.3000W active_power:2.00W
            active_power_workload:80K 128KiB SW
ps      3 : mp:0.0150W non-operational enlat:1500 exlat:2500 rrt:3 rrl:3
            rwt:3 rwl:3 idle_power:0.0150W active_power:-
            active_power_workload:-
ps      4 : mp:0.0050W non-operational enlat:10000 exlat:6000 rrt:4 rrl:4
            rwt:4 rwl:4 idle_power:0.0050W active_power:-
            active_power_workload:-
ps      5 : mp:0.0033W non-operational enlat:176000 exlat:25000 rrt:5 rrl:5
            rwt:5 rwl:5 idle_power:0.0033W active_power:-
            active_power_workload:-

真不是我黑金士顿。金士顿那个p3和p4延迟差距巨大,可是功耗还都是1.5W。人家西数的蓝盘,在P3就降到15mW了,虽然P5的延迟比200ms还高,可是人家功率小啊,人家能干到3.3mW。金士顿,呸。

除了配置内核参数之外,我还进行了一些简单的测试,比如持续拷贝大文件之类的。主要是给这块盘上点压力,看看会不会掉盘。目前为止也都很稳定。至此这一套换盘的操作也算是打完收工了。

后日谈

虽然这一次有惊无险的解决了问题,但时候回想起来,从原来的SSD里抓数据是最悬的——如果抓到一半盘突然暴毙,那我就只能重新装系统,重新配环境了,这得耽误多少事啊。这件事情你要说生气吧,倒也不至于,毕竟解决了。但是你说心平气和吧,我又不是很平和。其中我最想不明白的一点就是,Intel NUC一直以来溢价就比较高,我花五千多块钱买个NUC,去隔壁零刻能买俩。那我都花了这么多钱了,为什么不能给我配个好点的SSD呢?再后来我就想:你既然都知道它溢价严重,那你不想想它为什么溢价?你花了钱就得给你应得的配置,那还叫溢价吗?你猜为什么京东上裸机一直缺货?

文章结尾再劝诫一下大家吧:买存储相关的设备,别碰金士顿。我这个OEM的盘是金士顿NV2系列的,500GB,当时得亏没买1TB的,不然肠子得悔青了。后来有一个国际友人得知此事后跟我说,Tom's Hardware有一篇关于这个硬盘的测评,最后的结论是:

在大多数情况下,金士顿 NV2 根本不是我们可以推荐的硬盘,因为它可能配备的硬件范围让购买者风险太大。你可以买到优秀的 SM2269XT 控制器,也可以买到平庸的 SM2267XT 控制器。你可以购买 BiCS5 TLC 或速度更慢的 QLC。这些产品都没有 DRAM,而且在所有这些产品中,称这款产品为 PCIe 4.0 硬盘可能有失公允。

在测试中,该硬盘即使在空闲时也会发热,而且耗电量相当大,因此对于包括笔记本电脑在内的许多机器来说,它并不是理想之选。它的优势在于其令人惊叹的价格,这使得它除了作为主硬盘外,或许还能用于其他用途。

除此之外,你可能并不希望掷骰子来赌运气。最好从最坏的角度看:这是一款经济型硬盘,旨在以低廉的价格增加更多 NVMe 级存储空间。如果您使用过 A400 或 NV1,那么您就会知道 NV2 的预期效果。许多主板都配备了自己的 M.2 散热器或屏蔽罩,这也有助于缓解这款硬盘可能存在的发热问题,从而减轻其缺点之一。

我们的样品都使用了 SMI SM2267XT 控制器,它在 TLC 或 QLC 上的表现都不尽如人意。无论是哪种情况,闪存的性能其实都不差。只是市场上还有很多更好的选择。价格确实是您在考虑 NV2 时必须考虑的最终因素。如果它的价格与 SATA 替代品相比具有竞争力,那么作为游戏硬盘也许还不错,但这意味着你需要更高的容量。在容量较低的情况下,它只是一种廉价升级旧机器的方式——但我们没有对这些 SKU 进行评测。

这时候我想到了我买的SN580,正好也有一篇测评,结论是这么说的:

蓝盘 SN580 是西部数据推出的一款相对低成本的产品,它不冒任何风险,但却能提供令人满意的体验。它汲取了 SN570 和 SN770 的基因,是一款介于两者之间的硬盘,其核心是一款出色的经济型固态硬盘。虽然称其为 PCIe 4.0 硬盘有些夸张,但它确实比 SN570 性能更强、缓存更好,而且没有踩到 SN770 的脚趾。在大多数情况下,它将以更低的价格带来与 SN770 相当的体验,尽管这表明 SN770 最终会被取代。

SN580 拥有相当不错的保修服务,软件支持也不差。这些都不是主要的优势,但加上西部数据成熟的设计,它是一款非常可靠的硬盘。无论您的用途如何,它都是一个不错的选择。西部数据在硬盘硬件上确实有过更新换代的历史,比如 SN550 和 SATA 蓝盘,但从测试和推出的情况来看,SN580 是一款值得信赖的经济型硬盘。它并不是我们见过的最令人兴奋的产品,但这并不意味着它不好或没有用武之地。

我们已经测试过这个级别的许多优秀硬盘,即 4-5GBps 范围内的无 DRAM PCIe 4.0 硬盘,它们提供的出色体验甚至可以与高端硬盘媲美。但 2TB 硬盘可能是个例外,许多 2TB 硬盘都换成了 QLC,不过 SN770、SN570 和现在的 SN580 并不适用。如果您正在寻找一款预算充足的 2TB TLC 硬盘,那么 SN580 将是您的不二之选。与 SN570 相比,SN580 在性能上的小幅提升和缓存设计上的改进是一大优势,这将带来更好、更高效的使用体验。

SN580 的真正竞争对手是 SN770,以及以 Predator GM7 为代表的更高端无 DRAM 4.0 产品。虽然 SN580 有西部数据的名字,但后者可能会以相当的成本提供更好的体验。就 SN770 而言,它仍然是一款出色的硬盘,但可能需要及时更新。这样一来,SN580 就成了一个安全、全面的选择,没有任何新意或令人兴奋的功能。它只是填补了阵容中的一个位置,在这个位置上,它可以碾压金士顿 NV2 等不太理想的经济型 PCIe 4.0 硬盘。剩下的就是价格了。

看起来不错。

-全文完。本片撰写于Linux上。-


知识共享许可协议
【歪门邪道】探究Linux为什么突然死机 & 为NUC更换SSD天空 Blond 采用 知识共享 署名 - 非商业性使用 - 相同方式共享 4.0 国际 许可协议进行许可。
本许可协议授权之外的使用权限可以从 https://skyblond.info/about.html 处获得。

Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment

2 Comments
  1. “和卡死不同,鼠标和 UI 都是有响应的,但任何从硬盘读数据的行为都会被阻塞(事后才知道,这个时候盘已经掉了,ui 还能响应全靠内存的缓存)”
    实验室为我配的一台3090的电脑就经常这样,听说足足花了5w大洋,结果SSD好像还不如金士顿。害得我定期和家里的私有云进行数据同步#(喜极而泣)

    1. @硫酸钡那你这不得换个ssd?我买的那个西数的盘感觉就还行,而且量大管饱还便宜,clonezilla直接整盘复制,也不是不能用(