ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Lustre OST 架构新解:基于对象存储与ZFS的HPC存储实践

Lustre OST 架构新解:基于对象存储与ZFS的HPC存储实践 先从一个相对反常识的判断说起Lustre 这类高性能计算文件系统过去几乎和“本地高速磁盘 IB 网络 独占存储节点”是绑定关系。大家默认它能跑在 NVMe 阵列上、能榨干每一条 InfiniBand 链路但没有人认真想过把它的 OST 放在对象存储上能带来什么。这个项目展示的架构恰好颠覆了其中一环OST 不一定要落在本地物理盘上它可以构建在对象存储之上甚至底下还能叠一层 ZFS 来做数据管理。这不是一个“玩具级”的改造。对象存储便宜、容量近乎无限、数据和计算节点生命周期解耦而 Lustre 的语义又天然是“对象”的——文件被切分成多个对象分布在多个 OST 上。这两层对象语义如果能打通意味着 HPC 场景里最贵的那部分存储成本有可能被大幅压低。但它显然也有代价对象存储的延迟、一致性模型、小文件吞吐能力都和传统 Lustre 部署完全不同。这篇文章不想只做一个“看新闻式”的解读。我会从 Lustre 的基础架构讲起解释 OST、ZFS 和对象存储在这个过程中分别扮演什么角色再给你一套能在本地模拟的最小实践链路最后把这种方案真正的适用范围、风险点和工程建议讲清楚。如果你正在评估云上 HPC 存储、冷热数据分层或者对分布式文件系统的存储后端解耦感兴趣这篇文章会比较适合你。1. 这篇文章真正要解决的问题先说一个真实的矛盾。HPC 集群要跑大规模科学计算、AI 训练、基因测序这类业务Lustre 依然是最常见的并行文件系统之一。但一旦把这样的集群搬到云上问题就会冒出来云厂商提供的本地 SSD/NVMe 实例盘的容量太小大容量云盘的价格又比较贵而且实例的生命周期和存储的生命周期是绑定的。你销毁一组计算节点本地盘上的数据可能就没了想保留数据就得把云盘单独保留下来持续付费。传统思路是把“计算节点”和“存储节点”分开部署存储节点用好一点的实例挂载大容量云盘然后在上面跑 Lustre 的 MDS/OSS。这个方案本身没问题但它的成本模型不划算。对于一个需要几十 TB 甚至上百 TB 存储的数据集你不能真的买一堆高配实例去天天空转只为等着计算任务来读写。存储的价值在于长期保存而计算的资源只需要在任务期间存在。两者生命周期解耦才是云原生存储的核心理念。这正好是“把 OST 放到对象存储上”的切入点。对象存储本身就天然具备“长期保存、按量付费、无限扩容”的特性把 Lustre 的 OST 从本地云盘换到对象存储理论上可以让文件系统的容量和计算实例完全解耦。你要跑任务就临时拉起一组 Lustre 客户端和 MDS/OSS 节点任务结束整个计算组可以销毁而数据仍然以对象的形式安全躺在对象存储里。那 ZFS 又进来干什么这里有个容易误解的点。ZFS 并不是“直接认识对象存储”它本职是一个文件系统和卷管理器的组合。它需要块设备来创建 zpool然后在 zpool 里创建数据集来承载 Lustre 的 OST。所以整体架构里通常还需要一层“适配层”把对象存储“伪装”成块设备或文件ZFS 在它之上工作。ZFS 的价值在于它给 Lustre 的数据加了一层事务保证、校验和校验、快照、压缩和远程复制能力弥补了对象存储某些先天缺陷。所以这篇文章的核心问题可以归纳成一个Lustre ZFS 对象存储 这个组合在架构上为什么能成立它能解决什么问题又会引入哪些新问题2. Lustre 核心概念MGT、MDT、OST 与一次文件写入在继续之前我们得先把 Lustre 的术语对齐。因为后面讲 OST 放在对象存储上如果对 OST 的定位不清楚整个架构就理解不了。Lustre 是一个分布式并行文件系统它最常见的部署形态是把“元数据管理”和“数据存储”彻底拆开术语全称作用类比MGTManagement Target管理整个文件系统的配置、状态、日志一个“全局注册中心”MDSMetadata Server管理文件系统命名空间、目录、权限的服务器节点“文件的户口本”MDTMetadata Target存放元数据的底层存储目标户口本数据库OSSObject Storage Server管理数据存储的服务节点数据仓库管理员OSTObject Storage Target存储文件数据对象的底层存储目标数据仓库中的一排排货架ClientLustre 客户端应用访问文件的入口用户本人Lustre 最核心的设计是文件数据会被拆成多个对象object分散存放在多个 OST 上这个拆分行为就叫条带化striping。比如一个 1 GB 的文件如果条带大小是 4 MB而系统有 4 个 OST那么这个文件会被切成约 256 个对象轮流写到 4 个 OST 上。当多个客户端同时读这个文件的不同部分时它们可以并行访问不同的 OST读写带宽因此能很高。一次典型的数据写入流程大概是这样的客户端向 MDS 发起打开文件请求MDS 在 MDT 上创建元数据并分配一组 OST 和对象 ID。MDS 把 OST 列表返回给客户端。客户端直接向对应的 OSS 发送写请求数据绕过 MDS 直接写入 OST。数据落盘后OSS 返回确认客户端再把文件的 size、mtime 等属性更新回 MDS。整个过程里MDS 只负责“指路”真正的数据传输不经过它。这是 Lustre 高性能的一个重要原因元数据路径和数据路径是分离的。理解了这一点就会发现OST 承载的是文件的实际数据它必须可靠、可扩展。传统做法里OST 通常就是一个单独的磁盘或 RAID 卷或者由 ZFS 管理的一块存储池分配给多个 OST 使用。当一个 OST 挂掉对应这些对象的数据就不可用了除非启用副本或备份机制。所以如果能把 OST 放到对象存储上第一个被解决的就是“OST 本身的生命周期和物理设备绑定”这个痛点。3. ZFS 在 OST 中的角色从物理盘到存储引擎需要明确一下Lustre 本身并不依赖 ZFS它可以直接创建在最原始的磁盘上也可以基于 LVM、MD RAID 甚至 ext4 文件系统来创建。但 ZFS 是社区里很受欢迎的 OST 底层原因主要有四点第一数据完整性。ZFS 在每个数据块上都存储校验和。读数据时发现校验和不匹配它会尝试通过冗余副本或 RAIDZ 结构来自动修复。这个能力对 HPC 数据来说很有价值因为很多科学计算数据动辄几十 TB一旦静默损坏损失很难弥补。第二事务机制。ZFS 写入遵循 copy-on-writeCoW模型新的数据会写到新位置而不是覆盖旧数据。这种设计保证了系统在崩溃重启后文件系统始终处于一个一致的状态。对于需要长期存储的数据这是一个很大的加分项。第三压缩和快照。ZFS 可以做在线压缩比如 zstd、lz4节省空间同时可以几乎免费地创建快照快照可以用于备份和回滚。在对象存储上如果你想做数据分层或者定期做一致性快照ZFS 的这两个能力会很有用。第四存储池抽象。ZFS 用一个 zpool 把多个磁盘聚合成一个存储池然后在池里创建多个数据集dataset。每个数据集可以独立设置配额、压缩、挂载点等属性。在 Lustre 场景里每个 OST 可以是一个 ZFS dataset也可以对应一个 zvol 块设备。但注意ZFS 的底层要求依然是一个“块设备”。传统场景下这个块设备就是一块物理磁盘或者是一个 RAID 阵列提供给系统的虚拟磁盘。而在这个项目展示的架构里这个“块设备”不再来自本地物理盘而是来自对象存储映射出来的资源。这实际上引出了一个很多人忽略的细节ZFS 本身不关心底层设备是 SSD 还是 HDD也不关心这个“设备”是不是一个物理设备。只要 Linux 内核能把它当作块设备来访问ZFS 就可以在上面创建 zpool。对象存储可以被一层适配器转换成块设备接口虽然性能上远不如物理盘但语义上是能跑通的。另外要提一下 ZFS 的 vdev 概念。一个 zpool 里可以包含多种 vdev单个磁盘、mirror 镜像对、RAIDZ 阵列等。每个 vdev 提供一定的容量和冗余能力。如果你用对象存储映射出来的“块设备”作为 vdev 创建 zpool那么在 ZFS 眼中它看到的只是一个容量巨大但延迟较高的“虚拟磁盘”。这整个过程里存在一个容易混淆的“对象”双关Lustre 的数据单元叫 object对象存储的存储单元也叫 object。用 ZFS 连接两者时需要意识到它们的语义并不是完全一致的。Lustre 的对象要求严格的随机读写语义和事务一致性而对象存储只提供简单的 PUT/GET/DELETE 接口并且很多对象存储具有最终一致性。中间那一层适配器要做的就是把这套简单接口“翻译”成块设备语义。这是整个方案最微妙的地方。4. 把 OST 放到对象存储上的架构推演现在我们把视角拉到系统架构层面对比一下“经典 Lustre 存储”和“基于对象存储的 OST”到底差在哪里。经典本地盘方案的结构是[Lustre 客户端] ---- 网络 ---- [MDS MDT] |---- [OSS OST本地云盘/物理盘] |---- [OSS OST本地云盘/物理盘]这个方案的优点很强本地盘延迟低IOPS 有保证Lustre 的条带化可以充分压榨多块磁盘的带宽。缺点也很明显存储容量受限于实例规格数据冗余和备份都需要自己另做存储实例不能随便销毁。对象存储方案的结构是[Lustre 客户端] ---- 网络 ---- [MDS MDT可临时起] |---- [OSS OSTZFS 管理] | |-- 对象存储适配层把 S3/OSS 映射成块设备或文件 |-- 对象存储S3 / OSS / COS / MinIO这个方案里MDS/OSS 节点可以按需启动它们本身只需要系统盘和一个很小的本地盘来存放缓存和元数据信息。真正的数据居住在对象存储里。计算任务来了拉起服务任务结束关掉节点数据还在。从成本模型看两种方案差别明显。传统方案是“计算资源 存储资源”强绑定容量越大你必须保留的实例性能就越高。对象存储方案是“按容量和请求次数付费”容量再大也不需要你预留计算资源。对“写多读少”或“数据长期归档、偶尔被计算任务访问”的场景后者的优势会很显著。但必须说清楚代价。首先对象存储的访问延迟通常远高于本地盘。一个最常见的对象存储 GET/PUT 请求延迟在几十毫秒量级而本地 NVMe 的延迟是微秒级。这对大量小文件随机读写场景是致命的。其次对象存储很多不支持严格的强一致性可能出现“写进去后立刻读不出来”的窗口期。Lustre 和 ZFS 都属于对数据一致性要求很高的系统最终一致性会带来额外复杂度。再次对象存储按请求计费如果你频繁读写小块数据每月的请求费用可能比存储费用还高。所以更稳妥的判断是这个架构适合大文件、顺序读写为主的场景不适合海量小文件随机访问的通用文件存储场景。它本质上是用性能和实时一致性换取成本和容量弹性。这里面一定有取舍没有免费午餐。5. 环境准备与前置条件接下来我们做一个最小化验证环境把“Lustre 客户端 MDS OSS ZFS 对象存储”这条链路跑通。需要说明的是本文的演示重点是把概念链路和关键命令讲清楚不会追求生产级性能。版本号请以实际环境为准这里只演示通用思路。为了降低门槛我们用 MinIO 来模拟对象存储。MinIO 是一个兼容 S3 协议的开源对象存储可以跑在一台普通 Linux 机器上非常适合本地验证。你只需单机部署不涉及云账号。环境准备清单如下操作系统一个 Linux 发行版即可建议 CentOS Stream 或 Ubuntu Server内核较新。软件依赖zfsZFS 用户态工具和内核模块lustre-client以及服务端相关工具mkfs.lustre、mount.lustre等minio对象存储服务s3fs或rclone把对象存储挂载为本地目录磁盘仅需系统盘。为了演示 ZFS 池我们可以用本地文件来充当虚拟磁盘。网络三个进程可以都跑在同一台机器上不需要特殊网络配置。如果是在云上做生产验证对象存储使用云厂商的 S3、OSS、COS 等产品客户端和服务端需要能访问该对象存储的 VPC 端点。这一步看起来动作很多但其实都是为了“把对象存储变成 ZFS 能识别的块设备/文件”做铺垫。在后续步骤中我们会用 s3fs 或 rclone 把 MinIO 挂载为一个目录然后在这个目录里创建一个文件作为 ZFS 的 file vdev。ZFS 官方并不推荐用文件做 vdev因为它在崩溃恢复时可能有额外开销性能也比较差但用来验证架构链路已经足够。6. 核心流程拆解与最小示例下面我们按步骤拆解整个验证流程。我会把每一步的核心操作、关键命令、可能出现的错误都写出来。6.1 启动 MinIO 并创建对象存储桶MinIO 的启动很简单单机模式下可以使用下面的命令# 设置访问密钥 export MINIO_ROOT_USERminioadmin export MINIO_ROOT_PASSWORDminioadmin # 启动 MinIO 服务数据放在 /mnt/minio-data 下 minio server /mnt/minio-data --console-address :9001启动后MinIO 会在9000端口提供 S3 兼容 API在9001端口提供管理控制台。然后我们使用mc客户端创建一个桶名字可以叫lustre-bucketmc alias set myminio http://localhost:9000 minioadmin minioadmin mc mb myminio/lustre-bucket这一步如果做错常见问题是 MinIO 未启动、端口被占用或密钥不匹配。可以先访问http://localhost:9001确认控制台能否登录。6.2 把对象存储挂载为本地目录为了演示我们把 MinIO 的桶直接挂载成 Linux 本地目录。使用rclone mount是比较稳妥的选择# 配置 rclone 远程存储 rclone config create myminio s3 \ provider MinIO \ access_key_id minioadmin \ secret_access_key minioadmin \ endpoint http://localhost:9000 \ env_auth false # 创建挂载点 mkdir -p /mnt/objstore # 挂载桶到本地目录 rclone mount myminio:lustre-bucket /mnt/objstore --allow-other --daemon挂载成功后/mnt/objstore目录下的文件实际上会以对象的形式保存在 MinIO 中。这一步做完我们就获得了“一个本地目录 底层是对象存储”的可用路径。需要注意rclone mount默认性能很有限它主要通过 FUSE 在用户态转发请求。在演示环境里够用但在生产环境你必须考虑更高效的适配方案否则整个文件系统会被 FUSE 层卡住。6.3 在对象存储文件上创建 ZFS 池接下来我们在/mnt/objstore目录下创建一个固定大小的文件模拟 ZFS 的块设备。# 创建一个 10G 的文件作为 ZFS 的 file vdev dd if/dev/zero of/mnt/objstore/ost-file.img bs1G count10 statusprogress # 创建 ZFS 池关闭访问时间并开启压缩 zpool create -m /mnt/lustre-ost zfspool /mnt/objstore/ost-file.img # 查看池状态 zpool status这里有一点要特别提醒ZFS 的 file vdev 官方并不推荐用于生产环境因为 ZFS 在写入时会假设底层块设备具备一定的一致性保障而对象存储上通过 FUSE 挂载出来的“文件”语义没那么可靠。演示的时候可以生产环境请使用对象存储厂商提供的块存储适配方案或专门的存储网关。zpool create执行完可以检查状态正常情况下会显示state: ONLINE。如果创建失败先看是否权限不足或者文件所在目录是否支持mmap之类的操作。6.4 创建并挂载 ZFS 数据集ZFS 池创建后我们创建一个数据集来存放 OST 的数据zfs create -o compressionzstd -o atimeoff zfspool/ost0 zfs list这一步的目的是让 ZFS 对文件数据进行压缩同时关闭atime更新减少不必要的写入放大。注意ZFS 压缩的收益对文本类、科学计算数值类数据可能比较明显对已经高度压缩的文件比如随机数、加密数据、部分 PNG/JPEG压缩不会带来好处反而消耗 CPU。实际使用时需要根据业务数据特征来开启或关闭。6.5 用 mkfs.lustre 创建 OST现在我们把 ZFS 数据集作为 Lustre 的 OST 来格式化。mkfs.lustre \ --fsname demo-fs \ --ost \ --mgsnode10.0.0.10tcp \ --index0 \ zfspool/ost0这里的几个参数解释一下--fsname demo-fs文件系统名称所有节点需要一致。--ost表示这个存储目标是一个 OST。--mgsnode10.0.0.10tcpMGSManagement Server节点地址IP 需要换成你实际的 MDS 节点 IP。--index0这个是 OST 在文件系统中的编号多个 OST 需要从 0 开始递增。mkfs.lustre命令执行成功后ZFS 数据集下会生成 Lustre 的标签和配置信息。如果这里出错通常是因为--mgsnode的 IP 或者网络类型tcp不对可以先用lctl工具检查本地网络配置。6.6 挂载 OST 到 OSS 服务格式化完成后需要挂载 OST让 OSS 进程能够使用它mkdir -p /mnt/lustre-ost0 mount -t lustre zfspool/ost0 /mnt/lustre-ost0挂载成功以后OST 就变成 OSS 服务的一部分。你可以在 MDS 节点上继续创建 MGT 和 MDT然后在客户端挂载整个文件系统。为了保持文章聚焦这里不再展开 MDS/MDT 的完整步骤但它和 OST 的流程是对称的mkfs.lustre --mgs、mkfs.lustre --mdt然后挂载。6.7 客户端挂载文件系统当 MDS、OSS、OST 都就绪之后客户端可以用下面的命令挂载整个 Lustre 文件系统mkdir -p /mnt/lustre-client mount -t lustre 10.0.0.10tcp:/demo-fs /mnt/lustre-client如果挂载成功/mnt/lustre-client就是一个可读写的并行文件系统目录。你可以在里面创建目录、写入文件并通过lfs工具观察条带分布。7. 运行结果与效果验证挂载完成后我们需要验证文件系统是否真的可用以及数据是否真的落到对象存储上。7.1 查看文件系统状态使用lfs命令可以查看 Lustre 文件系统的总体状态lfs df -h /mnt/lustre-client你会看到类似下面的输出UUID 1K-blocks Used Available Use% Mounted on demo-fs-OST0000_UUID 10485760 102400 10383360 1% /mnt/lustre-client[0] filesystem summary: 10485760 102400 10383360 1% /mnt/lustre-client如果能看到demo-fs-OST0000_UUID说明 OST 已经被正确识别并加入文件系统。如果没有看到说明 OST 挂载或者 MGS 配置有问题。7.2 测试文件写入与读取创建一个测试文件看看数据能不能正常读写dd if/dev/urandom of/mnt/lustre-client/testfile bs1M count128 lfs getstripe /mnt/lustre-client/testfilelfs getstripe会输出文件在哪些 OST 上有对象分布。由于我们只创建了一个 OST它应该只显示一个对象但这一步能确认“文件被切分并写入 OST”的逻辑是生效的。7.3 确认对象存储里的数据因为我们把/mnt/objstore挂载到 MinIO 上理论上/mnt/objstore/ost-file.img这个文件已经作为对象存储在 MinIO 中了。你可以直接在 MinIO 控制台里查看lustre-bucket桶内是否出现了一个ost-file.img对象大小约为 10GB。这看起来很简单但它验证了一个关键结论Lustre 的数据链路最终确实落到了对象存储上而不是本地物理盘。7.4 验证失败怎么办如果lfs df显示不了 OST优先按以下顺序排查在 OSS 节点执行lctl list_osts看 MGS 是否注册了 OST。检查 MDS 和 OSS 之间的网络连通性比如lctl ping 10.0.0.11tcp。查看dmesg里 Lustre 模块的报错信息重点搜LustreError或Lustre:相关日志。8. 常见问题与排查思路下面这个表格汇总了这类架构里最容易遇到的问题。这里的很多问题不是“能不能跑通”而是“跑起来后会不会出大麻烦”。问题现象可能原因排查方式解决方案文件系统挂载慢或挂载超时对象存储请求延迟高MGS/MDT 心跳超时查看 Lustre 客户端日志检查 MDS 到对象存储的网络质量为 MDS 和 OSS 增加本地缓存盘调整 Lustre 超时参数lfs df看不到 OSTOST 没有成功挂载到 OSS或 MGS 未注册lctl list_osts、lctl ping、检查 OST 挂载点重新挂载 OST确认 MGS 参数一致写文件速度极慢FUSE 对象存储链路性能瓶颈用iostat、iftop观察磁盘和网络换用更低延迟的块设备适配方案增加本地缓存层读文件时发现数据损坏ZFS 检测到校验和不匹配zpool status查看是否有损坏恢复副本或从快照回滚检查对象存储是否发生静默替换对象存储出现最终一致性窗口数据刚写入对象存储后立即读取失败监控读请求错误码增加一致性校验逻辑或在应用层重试ZFS 池显示 DEGRADEDfile vdev 损坏或底层对象不可用zpool status -v查看损坏文件替换 vdev 或删除损坏文件尽快迁移到生产级方案小文件写入延迟高到不可用每个文件都要进行多次对象存储请求压测小文件随机写入重新评估业务场景考虑引入元数据缓存或分层存储每一个问题都要针对真实场景去排查。这个架构最大的风险其实不是配置不对而是“语义错位”Lustre 和 ZFS 都假设底层存储是可靠的本地块设备而对象存储并不完全满足这个假设。这也是为什么要强调快照和备份。9. 最佳实践与工程建议如果你真的要在生产环境尝试 “Open Lustre ZFS OST on object storage”我的建议是循序渐进分四步走。第一步先跑通本地 MinIO 验证环境把架构链路、命令、参数全部摸清楚。这一步的目的不是获得性能数据而是验证语义是否正确。重点观察数据在对象存储中的组织方式以及 ZFS 快照能否正常工作。第二步做一次小规模的云上技术验证。用云厂商的对象存储替代 MinIO用更接近生产的网络环境测试大文件顺序读写、集群并发读写的吞吐量。切忌直接上大集群否则一旦语义有问题排查成本非常高。第三步设计缓存层。这个架构的软肋是对象存储的高延迟缓存是必要的补偿手段。比如 OSS 节点可以配备本地 NVMe 盘作为读写缓存热数据留在本地冷数据落到对象存储。ZFS 本身有 ARC 缓存也可以用 L2ARC 扩展缓存但要注意对象存储的“设备”延迟高L2ARC 的命中率很关键。第四步建立完整的备份和回滚策略。ZFS 快照是天然的选择但快照不能替代备份。你需要把快照定期导出到另一个对象存储桶或者使用对象存储自身的版本控制。对关键数据集建议启用对象存储跨区域复制避免单一区域故障导致数据丢失。另外安全边界一定要重视。对象存储的访问凭据不能直接写在应用配置里推荐使用云厂商的 IAM 角色、临时凭证或 Kubernetes Secret 管理。Lustre 集群需要限制可信任网络MDS/OSS 节点应配置防火墙规则禁止公网直接访问。生产环境的变更必须经过测试环境验证并准备好回滚方案。任何格式化、删库、改配置文件的操作都要在维护窗口内进行并提前备份相关状态。从场景适配性来看这个架构最适合两类业务第一类是“大数据集低频计算”数据集很大、计算频率低计算任务结束后可以销毁计算资源数据继续留在对象存储。第二类是“数据归档 按需计算”数据平时只是归档保存偶尔需要被 HPC 作业读取读完后不需要保留计算集群。不适合的场景也明显高频小文件读写、数据库存储、交互式分析这类对延迟极其敏感的业务不建议采用这个方案。10. 总结与后续学习方向把 OST 放到对象存储上本质上是用“语义替换”的方式解决云上 HPC 存储的容量和成本问题。Lustre 提供并行文件系统的访问语义ZFS 在中间做数据完整性和快照管理对象存储提供海量低成本的数据承载能力。这个组合看起来有些“绕路”它确实绕过了本地云盘生命周期绑定的限制但代价是延迟、一致性和请求费用都需要额外设计和处理。对这个方向感兴趣的读者下一步可以从几个角度深入一是研究 Lustre 的 HSMHierarchical Storage Management功能它本身就是为冷热数据分层设计的思考对象存储能否成为 HSM 的底层目标二是研究 ZFS 在非标准块设备上的行为尤其是事务组txg和对象存储请求模式之间的关系三是关注云厂商是否有官方的“文件系统到对象存储”的适配方案它们往往有更成熟的性能优化也更值得生产环境依赖。在动手之前建议把这样一条原则记在心里任何分布式存储方案先证明数据在故障下不丢、不错、能恢复再谈性能优化。对象存储不是磁盘它不是魔法只是另一种存储语义。谁能把这层语义处理好谁才能真正把 HPC 存储搬到云上。
返回列表