- 集群管理
- 任务调度
- 后端
【免费下载链接】mesos
Apache Mesos
本文以 Apache Mesos 的 Multiple Disks 机制为核心,系统讲解 Root、Path、Mount 三类磁盘资源的概念、JSON 配置方法与底层实现原理,帮助集群运维人员正确地在 Agent 启动时暴露多块磁盘,并让框架(Framework)在创建持久卷时根据DiskInfo.source精确选择存储介质。读完本文,你将掌握--resources参数的手工编写规范、三类磁盘的适用场景与限制,以及 Mesos 在卷路径映射、销毁清理和磁盘配额隔离上的真实行为。
为什么需要多磁盘支持
在 Mesos 集群中,磁盘(disk)是 Agent 上报的标量资源之一。默认情况下,Agent 只把操作系统主盘暴露给集群,所有任务数据都落在 Agent 的work_dir里。但在生产环境中,日志、数据库、写前日志(WAL)、缓存等负载对存储介质的要求截然不同,因此 Mesos 提供了一种机制,让运维人员可以把多块磁盘以不同形态暴露给集群。
当框架通过acceptOffers响应资源 Offer 并执行Offer::Operation::Create创建持久卷时,可以检查磁盘资源的source字段来决定是否使用某块特定磁盘。也就是说,source是框架区分“普通根盘”与“指定数据盘”的唯一依据。
三类磁盘资源
在 include/mesos/mesos.proto 中,Resource.DiskInfo定义了可选的Source子消息,其Type枚举为:
UNKNOWN = 0 PATH = 1 MOUNT = 2 BLOCK = 3 RAW = 4对应地,Mesos 的磁盘资源以三种形态呈现:
1.Root磁盘(根盘)
Root磁盘是 Mesos 中最基本的磁盘资源,表现为DiskInfo中不设置source。它通常映射到运维人员提供给 Agent 的操作系统主盘存储,数据被映射进 Agent 的work_dir(即--work_dir指定的目录)。默认情况下(未指定--resources时),Mesos Agent 只会向集群暴露这块根盘。
在源码中,未带source的持久卷会被直接映射到工作目录下,见 src/slave/paths.cpp:
// If no `source` is provided in `DiskInfo` volumes are mapped into // the `workDir`. if (!volume.disk().has_source()) { return getPersistentVolumePath( workDir, role, volume.disk().persistence().id()); }2.Path磁盘
Path磁盘是运维人员提供的辅助磁盘资源,表现为DiskInfo.source.type设为PATH,并通过source.path.root指定用于存储数据的目录。它可以被框架切割成更小的块——框架可以在同一块 Path 磁盘上创建多个占用量小于总空间的持久卷。
常见的适用场景包括:额外的日志空间、文件归档或缓存、以及其他对性能不敏感的应用。运维人员只需创建一个目录,并把该目录设为Path的root,即可把一块磁盘以Path形态暴露出来。
Path磁盘还非常适合在测试或预发环境模拟多磁盘环境——直接在操作系统盘上创建几个目录即可,无需真实物理盘。但要注意:在同一文件系统上创建多个Path磁盘,等于静态地瓜分了磁盘容量。例如,10GB 存储设备挂载到/foo,若配置两个 Path 盘/foo/disk1与/foo/disk2,则 Agent 启动时这两块盘的总配置容量不应超过 10GB,否则存在磁盘写满的风险。
3.Mount磁盘
Mount磁盘同样是辅助磁盘资源,但表现为DiskInfo.source.type设为MOUNT,通过source.mount.root指定挂载点。与Path磁盘相反,它不能被框架切割——框架无法只取该盘的一部分,这种“非灵活性”反而让运维人员可以向框架保证:拿到这块盘的框架将独占整个磁盘设备。
常见适用场景包括:数据库存储、写前日志、以及其他性能敏感的负载。在 Linux 上,Mount磁盘必须对应/proc/mounts挂载表中的真实挂载点:运维人员先以首选文件系统挂载物理磁盘,再把挂载点作为Mount的root提交给 Agent。
除了性能优势,运行在Mount磁盘上的应用还能依赖“写满时报磁盘错误”的行为(只要所用文件系统能正确向上层传播这些错误)。正因如此,Mesos 对Mount磁盘关闭了disk/du隔离——配额由底层文件系统天然保证,无需 Mesos 再用du统计(见下文“配额与隔离”)。
Block磁盘(当前不支持)
Mesos 目前不允许运维人员直接暴露裸块设备(raw block devices)。虽然Source.Type枚举中已预留BLOCK与RAW,但该能力可能在未来引入,前提是先以设计文档解决安全与灵活性方面的顾虑。在 src/slave/slave.cpp 中,Agent 启动校验会对BLOCK、RAW、UNKNOWN直接报错退出:
case Resource::DiskInfo::Source::BLOCK: case Resource::DiskInfo::Source::RAW: case Resource::DiskInfo::Source::UNKNOWN: { EXIT(EXIT_FAILURE) << "Unsupported 'DiskInfo.Source.Type' in '" << resource << "'"; }通过--resources配置多磁盘
运维人员在 Agent 启动时,通过 JSON 格式的--resources参数提供这些不同形态的磁盘资源。需要特别强调的是:
注意:一旦你通过
--resources手工指定了任何disk资源,Mesos 将停止自动探测Root磁盘。因此若还想使用根盘,必须按下面描述的格式手工将其一并写入--resources。
这一行为的根源在 src/slave/containerizer/containerizer.cpp:Containerizer::resources会解析--resources,逐项检查是否显式包含cpus、mem、disk、ports;只有未显式给出的项才会触发系统自动探测。对disk而言,自动探测逻辑是取--work_dir所在文件系统的容量(fs::size(flags.work_dir))。
Root磁盘的 JSON 示例
不设置source即为根盘,其中scalar.value的单位为 MB,2048表示 2GB。运维人员还可以可选地为磁盘指定role字段,从而把磁盘静态预留(statically reserving)给单一角色(role):
[ { "name" : "disk", "type" : "SCALAR", "scalar" : { "value" : 2048 } } ]Path磁盘的 JSON 示例
source.type设为PATH,source.path.root设为存储根目录。同样可选用role字段实现静态预留:
[ { "name" : "disk", "type" : "SCALAR", "scalar" : { "value" : 2048 }, "disk" : { "source" : { "type" : "PATH", "path" : { "root" : "/mnt/data" } } } } ]Mount磁盘的 JSON 示例
source.type设为MOUNT,source.mount.root必须是一个真实挂载点(Linux 下须存在于/proc/mounts):
[ { "name" : "disk", "type" : "SCALAR", "scalar" : { "value" : 2048 }, "disk" : { "source" : { "type" : "MOUNT", "mount" : { "root" : "/mnt/data" } } } } ]root路径的取值规则
根据 include/mesos/mesos.proto 的注释,无论是Path.root还是Mount.root:
- 若为绝对路径(如
/mnt/raid/disk0),直接使用; - 若为相对路径,则相对于 Agent 的
work_dir解析。
这一规则在 src/slave/paths.cpp 中得到印证:
if (!path::is_absolute(root)) { // A relative path in `root` is relative to agent work dir. root = path::join(workDir, root); }Agent 启动时的磁盘校验
在 src/slave/slave.cpp 中,Agent 初始化时会遍历所有带source的磁盘资源并逐一验证其可访问性,任何一项失败都会导致 Agent 启动失败退出:
PATH磁盘:要求source.path及其root必须存在,否则报错;若目录尚不存在,Agent 会主动创建(os::mkdir(source.path().root(), true),true表示递归创建父目录)。这意味着运维人员可以预先写好配置,目录由 Agent 自动补建。MOUNT磁盘:要求source.mount及其root必须存在。在 Linux 上,Agent 会先对root做realpath解析,再读取/proc/mounts挂载表(fs::MountTable::read)逐条比对,只有realpath与某个挂载条目目录完全一致才通过;非 Linux 平台则只检查路径是否存在。
此外,Agent 还把校验后的资源写入SlaveInfo并向 Master 注册(info.mutable_resources()->CopyFrom(resources.get()),见 src/slave/slave.cpp)。
持久卷的底层实现差异
Path与Mount磁盘在持久卷的路径组织与销毁语义上存在根本区别,运维人员在检查或清理残余数据时必须留意。
卷路径映射
在 src/slave/paths.cpp 中,持久卷的路径按source类型映射:
PATH:Mesos 会在root内创建子目录来区分其上创建的各个卷,卷路径为getPersistentVolumePath(root, role, persistence.id()),即“根目录 + 角色 + 卷 ID”的组合目录。MOUNT:卷直接映射到root(挂载点本身),不会创建子目录,应用可以使用该设备上完整且预先存在的目录结构。
正是这种设计,让 Mesos 任务可以直接访问包含既有数据的卷——例如导入一个已存在的 PostgreSQL 数据目录或 HDFS 数据目录时,无需复制数据即可直接使用。
销毁语义
在 src/slave/slave.cpp 中,Slave销毁持久卷时的行为由source.type决定:
bool removeRoot = true; if (source.type() == Resource::DiskInfo::Source::MOUNT) { removeRoot = false; } Try<Nothing> result = os::rmdir(path, true, removeRoot);- 销毁
Path卷时,Mesos 会删除卷中存储的所有文件与目录,连同Mesos 在root下为该卷创建的子目录一起删除(removeRoot = true)。 - 销毁
Mount卷时,Mesos 会删除卷中存储的所有文件与目录,但不会删除根目录(即挂载点本身,removeRoot = false)。
因此,在人工清理残余数据时:Path 盘上遗留的卷子目录可以安全删除;而 Mount 盘上的挂载点必须保留,只能清理其中的内容。
配额与disk/du隔离
disk/du是 Mesos 的 POSIX 磁盘隔离器(实现于 src/slave/containerizer/mesos/isolators/posix/disk.cpp,注册名映射见 src/slave/containerizer/mesos/containerizer.cpp),负责统计容器磁盘用量并执行配额限制。
在 src/slave/containerizer/mesos/isolators/posix/disk.cpp 中,配额强制逻辑会显式跳过MOUNT类型的磁盘资源:
// We need to ignore the quota enforcement check for MOUNT type // disk resources because its quota will be enforced by the // underlying filesystem. bool isDiskSourceMount = false; foreach (const Resource& resource, info->paths[path].quota) { if (resource.has_disk() && resource.disk().has_source() && resource.disk().source().type() == Resource::DiskInfo::Source::MOUNT) { isDiskSourceMount = true; } } if (!isDiskSourceMount) { ... }也就是说,Path卷的配额由 Mesos 用du统计并强制执行,而Mount卷的容量约束交给底层文件系统(应用写满时会收到磁盘错误)。XFS 磁盘隔离器(src/slave/containerizer/mesos/isolators/xfs/disk.cpp)也通过同样的isMountDisk判断对MOUNT磁盘采取不同处理。
实战建议与注意事项
综合文档与源码,给运维人员如下操作要点:
- 手工指定即全量指定:一旦
--resources中出现任何disk条目,Agent 就不再自动探测根盘;根盘、Path 盘、Mount 盘必须一次全部写全。 - Path 盘注意总容量:同一文件系统上的多个 Path 盘,配置容量之和不得超过设备真实容量,避免静态分区导致磁盘写满。
- Mount 盘必须真实挂载:Linux 下
source.mount.root必须是/proc/mounts中的真实挂载点(Agent 启动时校验,realpath后逐条比对),不能只是一个普通目录。 - Mount 盘适合有状态高性能负载:独占设备、无子目录、配额由文件系统保证、可访问预置数据目录,是数据库与 WAL 的首选;Path 盘则适合日志、缓存等可切割场景。
- 清理残余数据看类型:Path 卷销毁后其卷子目录一并消失;Mount 卷销毁后挂载点仍保留,只能手动清理其中的文件,切勿删除挂载点本身。
- 权限控制:卷的创建与销毁受到授权(authorization)机制的约束,框架与运维人员操作时需提供
principal;结合预留(reservation)与角色(roles)可实现对特定磁盘的静态预留。
延伸阅读
- 持久卷 Persistent Volumes:如何在
Path/Mount磁盘上创建持久卷 - 预留 Reservation:磁盘资源的静态与动态预留机制
- 角色 Roles:资源与角色绑定关系
- 共享资源 Shared Resources:可被多个任务同时访问的共享持久卷
- 授权 Authorization:卷创建/销毁的 ACL 控制
- 集群管理
- 任务调度
- 后端
【免费下载链接】mesos
Apache Mesos
相关推荐
Apache Mesos 多磁盘(Multiple Disks)详解:Root / Path / Mount 磁盘资源模型与持久卷实战
Apache Mesos 多磁盘(Multiple Disks)详解:Root / Path / Mount 磁盘资源模型与持久卷实战 Apache Mesos
云原生集群管理容器编排任务调度Apache Mesos 0.27.0 版本技术解读:资源配额、多磁盘支持与隐式角色
Apache Mesos 0.27.0 版本技术解读:资源配额、多磁盘支持与隐式角色 Apache Mesos 0.27.0 是 Mesos 演进历程中的一个重
集群管理任务调度后端5分钟快速入门:使用 node-dependency-tree 分析你的项目依赖
5分钟快速入门:使用 node dependency tree 分析你的项目依赖 你是否曾经面对复杂的 JavaScript 项目,想要快速了解模块间的依赖关系
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考