一个伪linux粉丝的blog

  1. 首页
  2. Uncategorized
  3. 正文

Troubleshooting a DDN Lustre I/O Error

22 9 月, 2026 6点热度 0人点赞 0条评论

引子:一个 Input/output error 引发的三种猜想

故事的开始很普通。上午,有人反馈:某个容器里的 Python 脚本读文件直接抛IO异常,让查下 DDN(lustre)。

Shell
1
2
3
4
$ python -c "open('.../pytest-9.1.1.dist-info/entry_points.txt','rb').read(200)"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
OSError: [Errno 5] Input/output error

同一个目录下的另一个文件,读起来却完全正常。

Shell
1
2
$ python -c "open('.../pytest-9.1.1.dist-info/top_level.txt','rb').read(200)"
# 正常返回

这种"一半好一半坏"的现象最容易带偏人。现场迅速形成了三种猜想:

  1. 权限问题——uid/gid 对不上,容器里某个用户没权限;
  2. 存储坏了——DDN 后端出问题,数据损坏;
  3. 容器坏了——旧容器有 bug,重建就好。

后来证明:三个都不对。真正的答案是第 4 个——InfiniBand 网络在某几分钟里抖了一下,导致一系列后续故障。

第一现场:一台节点上的完整证据链

出问题的节点(下称 node-a)在 08:31 到 08:46 这个窗口内表现异常。我们先看整体结构。

图 1 · 拓扑与故障路径:问题出在客户端与 Fabric 之间

证据一:OST 没有进入只读

排查的第一件事是确认存储后端本身的状态——因为"存储坏了"是最吓人的猜想。

1
2
3
$ lctl get_param obdfilter.*.readonly
obdfilter.lustrefs-OST0000.readonly=0
obdfilter.lustrefs-OST0001.readonly=0

readonly=0 意味着 OSS 数据层从未降级为只读。 Lustre 只有在后端文件系统检测到严重错误时才会切只读。它是 0,说明磁盘阵列和数据层是健康的。

判定

存储后端健康,"DDN 坏了"这条猜想初步排除。

证据二:服务器自己的 IB 网卡进了 recovery

这是整条证据链里最关键的一行。在内核日志里:

1
2
3
08:39:12  LNet: <span class="y">1 local NIs in recovery</span> (showing 1): 192.0.2.101@o2ib
08:39:50  LNet: kiblnd_check_conns() <span class="r">Timed out tx</span>
08:40:28  LNet: kiblnd_check_conns() Timed out tx  (Skipped 2 previous similar message)

注意 local NIs 这个词——local,指的是服务器自己。也就是说,存储服务器自身的 IB 网卡进了 recovery 状态。这不是客户端单方面的问题,是服务器端的 o2ib 链路发生了抖动或断开重连。

紧接着的 kiblnd_check_conns() Timed out tx 来自 o2iblnd(InfiniBand 的 LNet 驱动层),是传输层连接超时的直接证据。它和文件权限、uid/gid 没有任何关系。

证据三:客户端的 import 状态是 EVICTED

从服务器视角看完,再切到客户端视角。node-b 上一度能直接复现问题:

1
2
3
4
5
$ lfs check servers | grep -i OST000f
lfs check: error: check 'lustrefs-OST000f-osc-...': Cannot send after transport endpoint shutdown (108)
 
# 对照节点 node-c 上同一条命令
lustrefs-OST000f-osc-... active。

 

而真正把状态钉死的,是客户端 import 参数里的这一行:

Shell
1
2
3
4
5
6
7
8
9
10
11
$ lctl get_param osc.lustrefs-OST000f-osc-....import
import:
    name: lustrefs-OST000f-osc-...
    target: lustrefs-OST000f_UUID
    state: EVICTED          # ← 关键
    import_flags: [ invalid, replayable, pingable, connect_tried ]
    connection:
       nids_stats:
          "192.0.2.114@o2ib": { connects: 514, replied: 514, ... sec_ago: 73140 }
       current_connection: "192.0.2.114@o2ib"
       idle: 73140 sec

 

这里有三个信息量很大的细节:

  • state: EVICTED——客户端被服务端驱逐,所有发往该 OST 的操作都会失败;
  • import_flags 里有 invalid——连接已失效;
  • replied: 514——最后那次连接是收到了应答的,应答内容就是"你被驱逐了"。说明那一刻网络还通,是服务端先动了手。

图 2 · 客户端 import 状态机:修复路径是重建实例,不是改权限

把时间线拼回来

单独看每行日志没什么感觉,按时间顺序排就一目了然了。

图 3 · 时间线复原:从驱动异常到客户端被驱逐,再到恢复

为什么"新容器没问题"反而帮了倒忙

现场最容易被当成结论的一句话是:"我重建了个容器,读写就正常了,所以是旧容器的问题。"

这句话逻辑上没错,但它证明不了"旧容器本身有缺陷"。因为 Lustre 的驱逐是客户端实例级别的:

对象 状态 读写结果
旧容器(对应被驱逐的客户端实例) 已被服务端驱逐,锁与缓存状态被撤销 全部 I/O 返回 EIO
新容器(全新客户端实例) 网络已恢复,重新挂载、重新连接 正常

新建容器时,网络抖动窗口已经过去了,它自然一切正常。这只能说明问题窗口已经结束,不能说明旧容器有 bug。

为什么是 EIO 而不是 Permission denied

权限不足会返回 Permission denied。而 Input/output error(rc -5 / -EIO)是客户端被驱逐后,Lustre 对 OST/MDT 的后续操作统一返回的错误码。二者含义完全不同,这也是排除权限猜想的直接依据。

另一台节点的独立佐证

同期 node-b 上也出现了同类现象,而且更"教科书":先是 lock enqueue 失败,然后是脏页被丢弃。

1
2
3
4
Sep 20 18:26:54  LustreError: lustrefs-OST000f-osc-...: operation ost_write to node 192.0.2.114@o2ib <span class="r">failed: rc = -107</span>
Sep 20 18:26:54  LustreError: lustrefs-OST000f-osc-...: <span class="r">This client was evicted by lustrefs-OST000f</span>;
                 in progress operations using this service will fail.
Sep 20 18:26:55  LustreError: ldlm_resource_complain() ... refcount nonzero (1) after lock cleanup; forcing cleanup.

还有一条容易被忽视、但含义很重的日志:

1
<span class="r">dirty page discard</span>: ...: [0x200006ae1:0x1ff39:0x0]// <span class="y">may get corrupted</span> (rc -5)

dirty page discard 意味着客户端有尚未刷回存储的脏页被丢弃。这是真实的数据风险点——不是存储坏了,而是网络中断导致写缓存里的数据没能落盘。

图 4 · 排除法:三个嫌疑人,只有第三个对得上全部证据

收网:证据链的完整表述

把所有片段串成一条链:

结论

08:31 起,HCA 驱动层出现密集异常(mlx5 ACCESS_REG failed),持续约 15 分钟,指向固件/寄存器交互异常;
08:38:51 起 RPC 请求批量超时;
08:39:12 存储服务器本地 IB 接口进入 recovery;
08:39:50 / 08:40:28 连续出现 IB 传输层连接超时;
08:40:28 客户端因锁回调超时(rc -110 / ETIMEDOUT)被 OST 驱逐;
08:41 MGS/MDT 又因 151 秒无心跳将其驱逐。

全程 OST readonly=0,无文件系统错误。根因是 IB 链路/驱动层异常,不是 DDN 存储后端,也不是容器权限。

同时要诚实标注一个未完全闭合的点:证据包里的 IB 端口计数器(link_downed、symbol_error、link_error_recovery)在采集时全是 0,hw_counters 也是空文件。lctl 日志中只有 drop_count: 5。

这意味着:物理链路本身没有经历 Link Down,抖动的成因更可能在固件/驱动交互层(呼应 08:31 的 mlx5 报错),而不是线缆或光模块。要彻底闭合,还需要看交换机端口计数器和同一 Fabric 上其他节点的同期表现——但就目前证据,方向已经明确。

经验小结

  1. 先看错误码,再看错误信息。 EIO 和 EACCES 指向完全不同的层,一个字母的差别就是两个排查方向。
  2. 区分"服务端健康"和"链路健康"。 readonly=0 只证明数据层没事,不证明客户端能连上。
  3. "重建就好了"不是归因。 它只说明故障窗口结束了。要问的是:窗口内发生了什么。
  4. 警惕被驱逐后的连锁反应。 锁失效、脏页丢弃(可能损坏)、资源未释放(refcount 异常),都发生在驱逐之后,是结果不是原因。
  5. 取证要趁早。 计数器是累加的,但很多状态是易失的;本文的证据包能成型,靠的是在故障后尽快系统性采集。

附录:一键证据收集清单

排查这类问题最怕"知道要查什么,但当时没存下来"。以下是在客户端节点上一次值得跑完的采集项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1) 客户端与存储的连接状态(最关键)
lctl get_param osc.*.import | grep -E "state|nids_stats|idle|replied"
lctl get_param mdc.*.import | grep -E "state|idle"
lfs check servers
 
# 2) 服务端数据层健康度
lctl get_param obdfilter.*.readonly
lctl get_param *.*.recovery_status
 
# 3) 内核日志中的 IB / LNet / 驱逐事件
journalctl -k --since "$START" --until "$END" --no-pager -o short-precise \
  | grep -iE "kiblnd|o2iblnd|LNet|evict|LustreError|mlx5"
 
# 4) IB 设备与端口状态
ibstat
for f in /sys/class/infiniband/*/ports/*/counters/*; do
  echo "$f: $(cat $f)"; done | grep -viE ": 0$"
 
# 5) 驱动版本(判断是否需要匹配固件)
modinfo mlx5_core | head -5
ibstat -s | grep -E "CA '|Firmware"

 

把这些输出连同时间窗口一起打包留档,下次再遇到"是不是存储坏了"的争论时,就不需要靠猜了。

—— 本文由某调试中的自建AI模型整理 ——

相关文章:

  1. Container platform disk management solution
  2. 如何撰写网站策划方案与网站运营方案
  3. 流水账之上海公共交通卡-退卡
  4. 一个塑料袋引发的思考--人民币存贷款利率表1990-2008
标签: ai ddn k8s lustre
最后更新:22 9 月, 2026

wanjie

这个人很懒,什么都没留下

点赞
< 上一篇

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

This site uses Akismet to reduce spam. Learn how your comment data is processed.

归档
分类
  • network / 335篇
  • Uncategorized / 117篇
  • unix/linux / 126篇
  • 业界资讯 / 38篇
  • 公司杂事 / 11篇
  • 数码影像 / 14篇
  • 美剧 / 3篇
  • 美图共赏 / 21篇
  • 英语学习 / 3篇
标签聚合
Nginx docker brew Google Adwords LinuxDeepin iMac VPS k8s 泰国 日全食 gitlab debian google-chrome kernel nexus Google Voice squid wget 邮件归档 网站运营 dreamhost d90 Linux ldap Google dreamhost空间 Ubuntu deepseek 纵贯线 虚拟主机

COPYRIGHT © 2008-2026 wanjie.info. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang