1. 磁盘扩容这件事,为什么主节点总是最先扛不住
干过大数据平台运维的人大概都有个共同体会:集群里最先亮红灯的,往往不是算力最紧张的计算节点,而是那个看起来"没干多少活"的主节点。我接手过好几个 CDP 集群的救火任务,十次里有六七次都是主节点根目录使用率冲到 90% 以上,监控告警一响,整个团队的心都跟着悬起来。这次要聊的就是这个高频场景——CDP 集群主节点根目录磁盘扩容,一个听起来简单、真动起手来处处是坑的活。
先把话说清楚:CDP 是 Cloudera 的数据平台发行版,主节点上跑着一堆关键服务——Cloudera Manager Server、管理数据库、NameNode 元数据、ZooKeeper、Kerberos KDC、各种网关和审计日志。这些东西有个共同特点:默认全往根目录写。日志越滚越大、审计数据越攒越多、元数据快照不断堆积,根目录那点初始容量根本撑不住长期运行。所以磁盘扩容不是"要不要做"的问题,而是"什么时候做、怎么做才不出事"的问题。
这篇内容适合谁看?如果你正在维护一套 CDP 或类似 Hadoop 生态集群,遇到过根目录告警、服务因为磁盘满而挂掉、或者正准备给主节点做容量规划,那这篇基本能当操作手册用。我会从整体思路、方案选型、具体操作、参数计算到踩坑排查,一层层拆开讲,尽量把每个"为什么这么干"都说明白,让你看完能直接照着复现,而不是只知道敲几条命令。
需要提前说明的是,下面涉及的具体容量数值、分区大小、路径名称都是基于常见实践的示例,你实际动手时一定要按自己集群的真实情况换算,别照抄数字。
2. 整体思路与方案选型:扩容不是简单加块盘
2.1 先搞清楚"根目录满"到底是谁在吃空间
动手之前最忌讳的就是上来就加盘。我见过有同行直接给虚拟机挂了一块新硬盘,结果根目录还是满的,因为新盘根本没挂到根上,白忙一场。所以第一步永远是定位空间消耗的真实来源。
在主节点上跑几条命令就能摸清底细:
df -h du -sh /* 2>/dev/null | sort -rh | head -20第一条看各挂载点的使用率,确认到底是/满了还是某个独立挂载的子目录满了。第二条从根往下逐层统计,找出占用最大的目录。实际经验里,主节点上吃空间的大户通常集中在这么几个地方:
/var/log:Cloudera Manager 和各个组件的日志,尤其是没配轮转策略的时候,几个月就能吃掉几十 G。/var/lib/cloudera-scm-server:CM Server 的数据库和内部数据。/opt/cloudera: parcels 包和配置,parcels 解压后体积不小。/dfs/nn或自定义的 NameNode 元数据目录:edits 和 fsimage 堆积。/var/lib/zookeeper:事务日志和快照。
把这份清单列出来,你才能判断是该"清理"还是该"扩容"。有些情况下清一轮日志、调一下轮转策略就能缓过来,但如果是元数据、数据库这类不能随便删的东西占大头,那就必须扩容。
2.2 三种扩容路径的取舍逻辑
定位清楚之后,扩容方案大致有三条路,各有适用场景,我做个对照表方便你决策:
| 方案 | 做法 | 优点 | 风险与限制 | 适用场景 |
|---|---|---|---|---|
| 原地扩盘 | 云盘/虚拟盘在线扩容后扩展分区和文件系统 | 不停机、路径不变、最省事 | 依赖底层存储支持在线扩容 | 云主机、支持热扩的虚拟化环境 |
| 新增磁盘挂载 | 挂新盘,把大目录迁移过去再挂载 | 灵活、可独立管理 | 需要停服务迁移数据,有停机窗口 | 物理机、无法原地扩盘的环境 |
| LVM 逻辑卷扩展 | 加物理卷到卷组,扩展逻辑卷 | 容量管理灵活、可后期再扩 | 前期必须已用 LVM 布局 | 规划时就用 LVM 的环境 |
选哪条路,核心看两个条件:底层存储能不能在线扩,以及根目录当初是不是 LVM 布局。如果是云环境且根盘支持在线扩容,那基本走第一条,最省心;如果是物理机或者根目录是普通分区,那就得考虑第二条,做好停机窗口;如果当初规划就用了 LVM,那第三条最优雅,加盘扩 LV 再 resize 文件系统,一气呵成。
我个人的偏好是:能原地扩就原地扩,不能原地扩就优先考虑把大目录迁到独立盘,而不是硬去动根分区表。因为动分区表(比如用 growpart 之外的手段调整分区边界)风险最高,一旦操作失误,主节点起不来,整个集群的管理面就瘫了。
2.3 为什么主节点扩容必须"先备份再动手"
这一点我要单独强调,因为它是最容易被忽略、后果又最严重的环节。主节点上跑着 Cloudera Manager 的数据库和 NameNode 的元数据,这两样东西一旦在扩容过程中损坏,恢复成本极高。所以无论走哪条路,动手前必须做两件事:
第一,备份 CM 数据库。用数据库自带的导出工具把 scm 库导一份出来,放到独立的位置。第二,备份 NameNode 元数据目录,至少把 fsimage 和 edits 拷一份。这两步花不了多少时间,但真出事的时候就是救命稻草。
注意:备份要落到"扩容操作不会影响到的地方",比如另一台机器的共享存储或者对象存储,别备份完还放在同一块要动的盘上,那就等于没备。
3. 核心细节解析:原地扩盘的完整实操链路
3.1 扩容前的容量计算,别拍脑袋定大小
很多人扩容就是"看着不够就加一倍",这其实不科学。合理的做法是先估算增长速率,再定扩容后的目标容量。举个实际的算法:假设你观察了三个月,根目录从 60G 涨到 90G,那月均增长约 10G;再结合业务规划,比如未来一年数据量预计增长 50%,那预留空间至少要覆盖 12 个月的增长再打个安全系数。
一个常用的经验公式是:
目标容量 = 当前使用量 + 月均增长 × 规划月数 × 安全系数(1.5~2)按上面的例子,当前 90G,月增 10G,规划 12 个月,安全系数取 1.5,那目标就是 90 + 10×12×1.5 = 270G。取个整数扩到 300G 比较稳妥。这个计算过程看着简单,但它能避免两个极端:扩太小很快又满,扩太大浪费成本。云盘按量计费的环境里,这个账还是要算的。
另外要留意文件系统的开销。ext4 默认会预留 5% 给 root,XFS 也有元数据开销,所以实际可用空间会比标称容量小一点,计算时心里要有数。
3.2 云盘在线扩容的分区与文件系统扩展
假设底层已经把云盘从 200G 扩到了 300G,但操作系统里看到的还是 200G,因为分区表和文件系统还没跟着扩。这一步是整套操作的核心,顺序不能乱:先扩分区,再扩文件系统。
先确认磁盘设备名和分区情况:
lsblk fdisk -l /dev/vda假设根目录在/dev/vda1,磁盘整体已经变成 300G,但分区还是 200G。这时候用growpart扩展分区最安全:
growpart /dev/vda 1这条命令只调整分区边界,不动数据,风险很低。执行完再用lsblk确认分区大小已经变成 300G。
接下来扩文件系统,这一步要根据文件系统类型选命令,选错了会出问题:
# ext4 文件系统 resize2fs /dev/vda1 # XFS 文件系统 xfs_growfs /XFS 只能扩不能缩,而且必须挂载状态下操作,命令参数是挂载点而不是设备名,这点特别容易搞错。ext4 的 resize2fs 参数是设备名。我见过有人对着 XFS 敲 resize2fs,报错还以为是盘没扩成功,其实是命令用错了。
扩完用df -h验证,根目录应该已经显示新容量了。整个过程服务不用停,这是原地扩盘最大的优势。
3.3 新增磁盘挂载方案的迁移细节
如果底层不支持在线扩,那就得走"加盘 + 迁移目录"的路子。这个方案的关键在于选对要迁移的目录,以及迁移过程中的服务停止顺序。
选目录的原则是:挑那些体积大、增长快、又不是系统启动必需路径的目录。主节点上最典型的候选是/var/log、/opt/cloudera/parcels、NameNode 元数据目录。迁移/var/log相对安全,但要注意迁移后日志服务还能正常写入;迁移 parcels 目录要小心 CM 的路径配置。
操作流程大致是:挂新盘 → 格式化 → 挂到临时挂载点 → 停相关服务 → 用rsync把数据同步过去(保留权限属性)→ 原目录改名备份 → 新盘挂到原路径 → 启服务验证 → 确认无误后删备份。
rsync的参数很关键,必须带-a保留权限、属主、时间戳,否则迁移后服务可能因为权限不对而起不来:
rsync -avx /var/log/ /mnt/newdisk/log/-x的作用是不跨文件系统,避免把挂载点下的其他内容也带过去。同步完还要用diff -r或者对比文件数量确认一致性,别急着删原数据。
注意:迁移 NameNode 元数据目录时,必须先停掉 NameNode 服务,等它把 edits 刷盘完成再迁,否则可能迁到一半数据还在变,导致元数据不一致。这个顺序错了,恢复起来非常麻烦。
4. 实操过程实录:一次典型的主节点扩容
4.1 环境摸底与变更窗口确认
拿一次我实际处理过的场景来说。某套 CDP 集群主节点根目录 200G,使用率冲到 93%,告警频发。我先做摸底:df -h确认是/满,du定位到/var/log占了 70G、/opt/cloudera占了 50G、NameNode 元数据 30G,剩下是系统和数据库。增长速率看监控历史,月均约 12G。
底层是云环境,根盘支持在线扩容,所以直接定方案:原地扩到 400G。变更窗口选在业务低峰期,虽然在线扩容理论上不停机,但为了保险还是提前通知了相关方,并准备了回滚预案——万一扩完文件系统有问题,至少能快速切到备份节点。
动手前先备份:导出 CM 数据库到对象存储,打包 NameNode 元数据目录到另一台机器。这两步做完,心里才踏实。
4.2 分步执行与现场验证
第一步,在云控制台把根盘从 200G 扩到 400G,等待底层完成。完成后进系统lsblk一看,磁盘是 400G 了,但/dev/vda1还是 200G,符合预期。
第二步,growpart /dev/vda 1扩分区,再lsblk确认分区变成 400G。这一步很快,几秒钟。
第三步,确认文件系统是 XFS(df -T /一看便知),执行xfs_growfs /。命令跑完输出一堆信息,最后df -h显示根目录 400G,使用率降到 46%,扩容成功。
第四步,验证服务。逐个检查 CM Server、NameNode、ZooKeeper 的状态,确认都正常。再故意往根目录写个大文件测试写入,没问题后删掉。整个操作从开始到确认完成不到半小时,服务全程没停。
这里有个细节值得说:扩完分区后我没有立刻扩文件系统,而是先lsblk确认分区表真的更新了。因为偶尔会遇到内核没重新读取分区表的情况,这时候直接扩文件系统会报错。如果真遇到,用partprobe让内核重新读一次分区表再继续。
4.3 扩容后的收尾与监控调整
扩容不是扩完就完事。我做了三件收尾工作:一是把这次扩容记录进变更台账,写清楚扩容前后的容量、操作步骤、验证结果,方便以后追溯;二是调整监控阈值,原来根目录 85% 就告警,现在容量大了,把告警线设到 80%,留出更充裕的响应时间;三是顺手检查了日志轮转配置,发现有几个组件的日志没配轮转,补上配置,从源头上减缓增长。
这三件事看着琐碎,但第二件和第三件其实是在"治本"。光扩容不治理增长源头,过几个月又得再来一次,运维不能总当救火队。
5. 常见问题与排查技巧实录
5.1 扩容后容量没变化的排查思路
这是最高频的问题:明明扩了盘,df -h还是老样子。排查顺序我整理成了一张速查表:
| 现象 | 可能原因 | 排查命令 | 解决 |
|---|---|---|---|
| 磁盘大了但分区没变 | 分区表未扩展 | lsblk、fdisk -l | growpart扩分区 |
| 分区大了但文件系统没变 | 文件系统未 resize | df -T看类型 | 按类型选 resize 命令 |
| 命令报错"设备忙" | 分区表未重读 | partprobe | 重读后重试 |
| XFS 用 resize2fs 报错 | 命令用错 | 确认文件系统类型 | 改用xfs_growfs |
| 扩完很快又满 | 增长源头未治理 | du定位 | 清理+调轮转策略 |
排查的核心逻辑就是逐层确认:物理盘 → 分区 → 文件系统,哪一层没跟上就补哪一层。别跳步,也别假设。
5.2 迁移目录后服务起不来的典型坑
走新增磁盘方案时,迁移完目录服务起不来是常见问题,八成是权限或 SELinux 上下文的问题。rsync -a能保留普通权限,但 SELinux 的安全上下文不一定能完整保留。如果系统开了 SELinux,迁移后要用restorecon -Rv /目标目录恢复上下文,否则服务读不到文件。
另一个坑是挂载配置。新盘挂载要写进/etc/fstab,但写的时候要用 UUID 而不是设备名,因为设备名在重启后可能变。用blkid查 UUID,写进 fstab 后用mount -a测试,确认不报错再重启验证。我见过 fstab 写错导致机器起不来的,那真是大事故。
提示:改 fstab 之前,先
cp /etc/fstab /etc/fstab.bak备份一份,改完mount -a验证通过再放心。这个习惯能救你很多次。
5.3 几个只有踩过才知道的经验
第一个经验:扩容前先看/etc/fstab里根目录是怎么挂的。如果是 LVM,那扩容路径和普通分区完全不同,得先pvcreate加物理卷、vgextend扩卷组、lvextend扩逻辑卷,最后才 resize 文件系统。搞错布局直接上手 growpart,会白忙活。
第二个经验:在线扩容虽然不停机,但别在业务高峰期做。文件系统 resize 本身很快,但期间 IO 会有短暂波动,赶上业务高峰可能引发连锁反应。低峰期操作,出问题也有缓冲时间。
第三个经验:扩容后一定要验证写入。df显示容量对了不代表真能写,用dd往根目录写个几百兆的测试文件,确认能正常写入再删掉,这一步能提前发现文件系统层面的隐患。
第四个经验:把扩容和容量治理绑在一起做。每次扩容都是一次审视增长源头的机会,顺手把日志轮转、审计清理、临时文件策略都检查一遍,能显著延长下次扩容的周期。我现在的习惯是扩容必带一次"增长源治理",效果比单纯加盘好得多。
这套流程走下来,主节点根目录扩容这件事就从"提心吊胆的救火"变成了"有章可循的常规操作"。真正让我安心的从来不是扩容命令本身,而是动手前的摸底、备份,和动手后的验证、治理——这些看起来"不直接产生结果"的步骤,才是让整个操作稳得住的关键。