ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

HPC负载均衡实战:调度、网络、存储与应用层全解析

HPC负载均衡实战:调度、网络、存储与应用层全解析 做过高性能计算HPC集群运维的朋友大概率都遇到过这种场景明明所有节点的CPU型号、内存大小一模一样跑同一个算例脚本有的节点几分钟就交差了有的节点却直接干到超时被杀。我再翻调度日志发现任务几乎全压在了前面几个节点上后补的节点在那儿躺着睡觉。这不是节点坏了而是负载均衡没做到位。高性能计算里的负载均衡名字听着和Web站点的负载均衡一样但它的思路和复杂度完全不是一个量级——它既要管任务怎么分配给节点也要管数据在网络里怎么流动还要管存储怎么扛住并行读写甚至应用进程内部也在做负载均衡。这篇文章我会把HPC负载均衡从调度、网络、存储到应用层一条线拆开来讲清楚并附上我在实际集群里用过的配置和避坑记录适合刚接手HPC集群的运维工程师、做大规模并行计算的科研人员以及想把服务器资源真正榨干的同学参考。1. 高性能计算里的负载均衡到底是什么1.1 从一次排队算题说起负载均衡在HPC中扮演的角色去年我带团队给一所高校搭了一套128节点的CPU集群主要用于流体力学模拟。刚上线的时候大家都很兴奋觉得总算不用在个人工作站上跑三五天了。结果第一周就收到一堆吐槽同样的算例在A组节点上跑6小时换到B组节点上要跑11小时。一开始我们怀疑B组节点硬件有问题检查CPU降频、内存报错全都正常。后来盯了几天调度日志才明白问题出在节点分配策略上——默认配置下调度器总把任务往编号靠前的节点上塞而B组节点因为扩建时硬件批次不同内存频率反而更低一旦同时跑满性能差距立刻显现。这就是一个很典型的“负载均衡缺失”场景。在HPC世界里负载均衡的本质是让计算、存储、网络链条上的每一份资源都被“恰好地”利用起来计算节点不出现大量空闲、网络链路不出现单点拥塞、存储设备不出现某个磁盘被打满而其余磁盘闲置。你可以把它理解成餐厅后厨有人切菜、有人炒菜、有人传菜如果只盯着炒锅看觉得炒锅够用就拼命点单结果切菜案板堆成山炒锅反而空转。高性能计算集群越大这种木桶效应越明显一个慢节点足以拖垮整个并行任务的完成时间。1.2 负载均衡的四层战场调度、网络、存储、应用HPC负载均衡不是一个单一组件它分布在集群的各个层次。我在实际诊断问题时习惯把它拆成四层来看层次均衡对象典型实现常见问题信号计算调度层作业、任务、进程SLURM、LSF、PBS节点利用率差异大网络层数据流、报文ECMP、LACP、自适应路由端口流量严重倾斜存储层IO请求、元数据Lustre、BeeGFS、Ceph单个OST或OSD打满应用层线程、进程间的计算量OpenMP dynamic、MPI动态任务队列整个程序等待慢速进程这四层不是孤立的它们会互相传导。比如存储层出现热点一堆计算节点都卡在读取同一个文件上看起来就像计算负载不均实际上瓶颈在IO。再比如网络层的哈希策略不当某个交换端口拥塞拖慢的也是一整批跨节点通信的作业。所以我一直强调排查HPC性能问题第一件事就是分清楚当前的“不均衡”到底发生在哪一层。1.3 为什么说HPC负载均衡比普通Web负载均衡更“硬核”做Web应用的同学提到负载均衡脑子里通常是Nginx、LVS、F5负载均衡这些核心目标是让后端服务器的连接数、请求量大致平均再配个健康检查摘除故障节点。这套思路在HPC里只能算入门水平。HPC任务有几个特点直接拉高了负载均衡的难度第一任务粒度差异极大且动态变化。一个OpenMP循环里的每一次迭代耗时可能差出几十倍一个MPI进程负责的子网格也可能在计算过程中不断改变密度。静态的轮询分配根本扛不住这种动态波动。第二通信模式决定了“均衡”的真正含义。并行程序里经常有MPI_Allreduce、MPI_Bcast这类全局同步操作所有进程必须等最慢的一个到达集合点。这时候不光要均衡计算量还得均衡通信量否则某个进程被网络拥塞拖慢全组陪跑。第三耦合度高牵一发动全身。Web后端挂一台服务器一般只影响部分请求但HPC作业一旦出现某个节点负载过高整个作业的完成时间都会被拉长资源浪费成倍放大。所以在HPC里我们谈“等开销负载均衡”Equal-Cost Multi-Path简称ECMP这类技术时关注的不是“有没有被均匀分发”而是“每条路径上的开销是否接近一致”。这也解释了为什么同样是负载均衡HPC领域会更强调延迟、带宽、同步开销这些指标而不是单纯看连接数。2. 方案选型不同规模的HPC集群怎么选负载均衡策略2.1 计算调度层从静态分配到动态感知计算调度层的负载均衡最简单粗暴的是轮询Round Robin按节点顺序循环分配任务。两三个节点的小集群够用一旦集群超过二十个节点轮询就经常翻车节点上的作业执行时间完全不一样前面分配的任务还在跑新任务又来了轮询照样往那个忙节点上塞。所以实际生产集群里很少有人用纯轮询。现在主流的调度器比如SLURM默认做的其实是“基于资源匹配的调度”根据作业申请的CPU、内存、GPU数量结合各节点的实时空闲资源筛选候选节点然后按一定的权重和优先级排序。这个权重就有学问了。我给集群做规划时的经验是十台以内的小集群直接用SLURM默认配置分区规划清楚就行不需要太复杂。几十台到上百台的中型集群建议引入多因素权重把CPU型号、内存带宽、GPU类型、节点功耗都考虑进去。老批次和新批次的节点性能不一样就通过权重调整让调度器优先把作业发给高性能节点。超大规模集群或异构集群纯静态权重不够需要上动态负载感知也就是调度器和监控系统联动。监控发现哪个节点CPU平均负载超过阈值调度器就在一段时间内降低它的调度权重。这里要特别强调调度层的负载均衡目标不是让所有节点利用率都保持一样高而是让作业的平均等待时间和完成时间最小化。有时候保留一部分节点给优先作业反而比“平均主义”更高效。2.2 网络层ECMP等开销多路径与流表分发HPC网络层常用的负载均衡手段最经典的就是等开销多路径路由。所谓“等开销”就是在路由协议比如OSPF、BGP看来去往同一个目的网络有好几条开销一样的路径路由器可以在这些路径之间分摊流量。对应到HPC的胖树拓扑上就是同一对叶子交换机之间有多条等价上行链路哈希让不同流走不同链路避免某一条链路被打满。ECMP的天然问题是哈希碰撞。默认情况下很多交换机按五元组源IP、目的IP、源端口、目的端口、协议做哈希如果某个大流量应用的端口恰好哈希到同一条链路就可能出现某条链路利用率80%旁边链路利用率只有5%的“假拥塞”。解决思路一般有两个一是选择更好的哈希字段组合把源MAC、目的MAC、IP、端口都混进哈希二是用更高级的自适应路由由交换芯片实时监控链路利用率动态调整流量的路径。在Linux服务器层面同样存在等开销路由的配置空间。多网卡bonding时我们可以选择LACP链路聚合控制协议或自适应负载均衡模式让流量在多块物理网卡之间分摊。这里有个常见误区bond的负载均衡和ECMP是两码事。bond处理的是主机和交换机之间的链路冗余与流量分担ECMP处理的是全网路径选路两者可以配合使用但不能互相替代。2.3 存储层分布式文件系统的负载均衡设计HPC的存储负载均衡很多人会忽略但它往往是影响作业性能的大头。以Lustre为例文件被条带化到多个对象存储目标OST上写入时数据按照条带策略分散到不同的OST。条带数越多单个文件的读写并发度越高但如果几百个作业同时往同一个目录里写文件而目录的条带策略又只落在少数几个OST上那几个存储设备就会变成热点。Ceph的负载均衡机制类似但更复杂一些。Ceph通过CRUSH算法把数据映射到OSD上每个OSD可以设置不同的权重。硬件配置高的OSD权重高一点低配盘的权重低一点CRUSH算法会尽量按权重和数据量做平衡。集群扩容时新加入OSD的权重从0开始逐渐调高让数据慢慢回填避免一次迁太多数据把网络打爆。存储层的“均衡”最终要落到两个指标上容量均匀度和IO压力均匀度。我见过不少集群磁盘空间明明没用完但某个OST的IOPS已经顶到天花板因为所有小文件都落在上面。这种问题扩容解决不了得先调整文件的条带化策略和目录分布。2.4 商业与开源方案对比不只盯着调度器提到负载均衡方案选型很多人第一反应是调度器选SLURM还是LSF这没问题。但我会建议大家把视角放宽一点把网络负载均衡和存储负载均衡也放进方案里统一评估。我对常见方案的感受如下方案类型优势劣势适用场景SLURM开源调度器免费、生态大、文档多、二次开发容易高级策略需要自己写插件科研、教育、中小型企业集群LSF商业调度器调度算法成熟、支持完善、报表能力强贵收费按规模算大型企业、生命科学行业PBS Professional商业调度器传统行业积累深、稳定社区活跃度不如SLURM航空航天、制造仿真Linux bonding / LACP开源网络负载均衡配置简单、内核自带哈希策略有限服务器双网卡冗余FRR/Bird 做ECMP开源路由灵活、可编程需要了解路由协议自建数据中心网络F5负载均衡商业应用交付功能全面、健康检查强贵通常用不到HPC核心计算网络集群对外门户、数据服务网关我在企业集群的对外服务入口见过F5负载均衡设备它主要承担Web门户、数据下载服务的分发和健康检查工作得很好。但HPC内部的计算网络、存储网络用F5这种应用交付控制器反而不合适因为性能开销太大而且HPC更依赖低时延的硬件转发。方案选型要记住一句话负载均衡没有银弹每一层用最合适的那一个。3. 核心细节与实操配置把负载均衡落到真实集群上3.1 调度器配置示例SLURM的权重与分区设计我在真实集群里最常用的负载均衡调优手段是调整SLURM的节点权重和分区策略。先看一段典型的slurm.conf片段# slurm.conf 片段 NodeNamenode[01-32] CPUs64 RealMemory250000 Weight1000 StateUNKNOWN NodeNamenode[33-48] CPUs64 RealMemory250000 Weight900 StateUNKNOWN PartitionNamebatch Nodesnode[01-48] DefaultYES MaxTime48:00:00 PartitionNamehighpri Nodesnode[01-16] DefaultNO MaxTime12:00:00这里Weight是SLURM选择节点时的重要依据。节点权重越高调度器在满足资源需求的前提下越倾向于优先分配它。把新批次、性能好的节点权重设成1000老节点设成900调度器自然会优先往新节点上派作业。但要注意Weight不是万能的。它只在作业找到多个候选节点时影响排序如果作业申请了独占整个节点--exclusive所有空闲节点都是候选权重就发挥了作用如果作业只申请1个CPU候选节点会非常多调度器还受内部排序逻辑影响不一定完全按Weight来。所以更稳的做法是配合分区使用。实操中的一个小技巧把经常要跑的短作业放到独立分区长作业分区保留足够空闲资源这样短作业不会抢占长作业的节点长作业也不会因为等待零星资源而卡住。这个思路其实就是“分区隔离 权重引导”比单纯依赖调度算法更可控。提交作业时可以指定分区srun -p highpri --time02:00:00 --cpus-per-task16 ./simulate.sh3.2 网络等开销路径配置BGP ECMP与LACP链路聚合网络层的等开销负载均衡我在自己的实验室环境里也复现过。最基础的场景是一台计算节点有4块25G网卡分别接到两台交换机上我们想在这4条链路之间均衡流量。先配LACP# 编辑 /etc/network/interfacesDebian/Ubuntu auto bond0 iface bond0 inet static address 192.168.10.10/24 bond-slaves ens1f0 ens1f1 ens1f2 ens1f3 bond-mode 4 bond-miimon 100 bond-lacp-rate 1 bond-xmit-hash-policy layer34关键参数是bond-xmit-hash-policy我推荐用layer34也就是按IP和端口做哈希默认的layer2只按MAC地址哈希很容易在大流量场景下撞车。如果跑的是RDMA/RoCE这类流量建议在此基础上再配合优先级流控否则PFC死锁会让负载均衡形同虚设。如果要做真正的ECMP路由选路服务器上可以启用FRR配合BGP与交换机互通。简单场景下Linux本身也支持在路由表里配置多路径ip route add 10.0.0.0/24 nexthop via 192.168.10.1 weight 1 nexthop via 192.168.20.1 weight 1这条命令让发往10.0.0.0/24的流量在两条路径间按权重做哈希分摊。注意Linux内核默认按源IP和目的IP进行多路径哈希如果流量集中在少数几个IP对之间效果会很差。可以调整哈希策略sysctl -w net.ipv4.fib_multipath_hash_policy1hash_policy1表示在IP之外加入源端口和目的端口参与哈希适合业务流比较少的HPC集群。这个改动要小心它会重建整个路由表导致瞬时丢包最好在维护窗口操作。3.3 应用层动态负载均衡MPI任务与OpenMP的实测调优有时候集群规模和网络都正常性能还是上不去问题就出在应用自身的负载不均衡上。以OpenMP为例默认的static调度在编译期把循环的迭代块平均分给每个线程。如果每个迭代的计算量差异很大这种“按份数切”的方式就很不合理。我做过一个网格加密仿真内层循环在不同位置的迭代耗时能差出5倍。后来把调度策略改成动态#pragma omp parallel for schedule(dynamic, 32) for (int i 0; i N; i) { compute(i); }dynamic调度让线程在运行期间从共享任务队列里取迭代块谁算得快谁就多干活自然把计算量拉平。chunk大小选32是我们多次测试后的折中太小会导致调度开销增加太大会失去动态均衡的效果。MPI程序的负载均衡更复杂一些因为线程间还能共享内存进程间只能靠消息传递。对于计算量会动态变化的MPI任务常规做法是引入主从模式一个主进程维护任务队列其他工作进程完成一个任务就去主进程领下一个任务。实测下来在负载波动明显的场景中这种动态任务队列比静态划分能缩短20%到40%的整体运行时间但要注意控制任务粒度任务太碎会让主进程变成通信瓶颈。4. 做一个最小可复现的负载均衡实验4.1 实验拓扑与资源配置理论讲再多不如动手跑一遍。我建议第一次接触HPC负载均衡的同学拿三台虚拟机做实验就够了。配置不需要高4核8GB内存安装了SLURM和MPI环境就行。节点角色划分如下节点角色配置node0调度控制节点running slurmctld和slurmd4核8Gnode1计算节点running slurmd4核8Gnode2计算节点running slurmd4核8G实验目标是模拟“等开销负载均衡”和“调度权重调整”两种效果。先用默认配置跑一组任务记录任务在不同节点上的分布和耗时再修改SLURM权重或手动制造节点繁忙观察调度器如何自动避开高负载节点。4.2 手动模拟“等开销负载均衡”效果第一步在node1上人为制造高负载。我习惯用stress工具# 在 node1 上执行 stress --cpu 4 --timeout 600第二步从node0上连续提交8个短任务每个任务申请1个CPU、运行10秒for i in $(seq 1 8); do srun --cpus-per-task1 --time00:10:00 sleep 10 done wait提交完马上执行sinfo -N大概率会看到大部分任务都跑到了node1上node2在那边“看戏”——因为SLURM默认按节点编号顺序优先分配而node1虽然繁忙但只要它的空闲CPU还没耗尽调度器并不会主动避让。第三步我们改一下node2的节点优先级让它更“抢手”scontrol update NodeNamenode2 Weight2000然后重新提交8个任务这时候新任务会明显向node2倾斜。这个实验虽然简单却把“负载均衡依赖调度策略”这件事说透了没有策略干预负载天生就是倾斜的有了权重调度器才能把任务往有余量的节点带。4.3 实验结果解读吞吐、时延、健康检查实验要记录的关键指标有两个一是作业平均等待时间二是节点CPU利用率。我们当时记录了前后两轮的对比场景任务平均等待时间(秒)任务完成总时长(秒)node1利用率峰值node2利用率峰值默认配置12.565100%35%调整Weight后3.24070%88%这个表很直观调度器做了“负载均衡”之后两个节点的利用率都往上走了任务完成总时长也缩短了。不过我要提醒一句节点利用率接近100%不代表就是好事。如果某个节点长期100%但任务吞吐没提上去就要怀疑是不是有任务在跑无效计算或者IO在拖慢。健康检查在这个实验里也很重要。SLURM可以配置HealthCheckProgram定期执行脚本检查节点状态比如负载、温度、IO错误。如果节点没通过健康检查slurmd会自动把节点置为DRAIN调度器就不会再派任务过去。这个机制和Web负载均衡里的“摘除异常后端”是一个思路强烈建议生产集群都配上。5. 常见问题与排查技巧实录5.1 节点为什么一直在“饥饿”排查调度偏斜几乎每个HPC管理员都会遇到“饥饿节点”问题。所谓饥饿就是集群里明明有很多空闲节点作业却还是挤在一小部分节点上排队。我的排查步骤是固定的先执行sinfo -N看节点状态确认哪些节点是idle哪些是alloc。执行scontrol show node看每个节点的空闲CPU、内存、Weight值重点看Candidate配置是否正常。查看作业分配情况squeue -o %.18i %.20j %.8T %.10M %.6D %R能看到作业跑在哪些节点上。检查分区和QOS配置确认不是某个特殊QOS把节点圈住了。有一次我们发现新加的16个节点一直不被使用查了半天才发现新节点的Weight默认还是1000但老节点的Weight已经调到了2000调度器自然优先老节点。把新节点Weight调高问题马上消失。所以新节点不接活先看Weight和Partition这是最快的排错路径。5.2 网络哈希不均导致某个端口被打满网络层负载均衡最隐蔽的问题就是“看链路都是通的但应用性能上不去”。有一次我们监控到机房某台交换机的一个40G端口利用率到了85%而同一组里其他三个端口都不到10%。查了sFlow发现是一个MPI作业的通信流恰好被哈希到了同一个端口上。这种大流用五元组哈希很难避免因为RDMA通信源目IP是固定的只有端口或QoS字段在变。解决办法有两个方向一是换更精细的哈希策略把ECMP哈希改成包含更多字段二是对通信量大的作业通过调整MPI进程的通信拓扑尽量让流量分布在多个源目对上。如果交换机支持自适应路由Adaptive Routing可以打开让芯片自己避开拥塞端口。不过自适应路由在有些交换机上会增加时延低延迟场景要测试后再决定。5.3 存储热点与元数据性能瓶颈存储热点问题的典型表现是计算节点CPU利用率不高但作业进度条就是不走多数时间在等待IO。我处理过的一个真实案例是某个课题组把所有中间结果都写到一个共享目录而那个目录的Lustre条带数默认是1结果所有文件都堆在一个OST上。查的命令是lfs df lfs getstripe /project/fei_medium一眼就能看到某个OST的Used已经90%其他可能才50%。解决方法是把新目录的条带策略扩大并重新迁移热点文件lfs setstripe --stripe-count 4 /project/fei_medium/new_result lfs migrate -c 4 /project/fei_medium/hotfile.dat这里还有一个日常容易被忽略的点元数据服务器MDS的负载。大量小文件操作会让MDS成为瓶颈因为不管文件多小都要先过元数据这一关。处理办法是把小文件挪到本地SSD或专门的并行文件系统目录别让它们和万亿大文件混在一起。5.4 问题速查表从症状到动作下面这份速查表是我在集群运维群里经常分享的遇到性能问题先对着它快速定位症状可能原因快速排查优化动作新节点空闲但不接活Weight或分区配置不对scontrol show node调整Weight或Partition节点全部100%但作业很慢任务本身资源争抢、IO排队pidstat、iostat查看限制单节点并发任务数某个网络端口流量异常高ECMP哈希碰撞sFlow/NetFlow看流分布调整哈希字段或启用自适应路由存储个别OST打满文件条带数不够lfs df getstripelfs setstripe / migrate小文件操作卡顿MDS过载查看元数据处理延迟小文件单独目录或换本地盘应用运行中明显等待长尾进程应用内计算负载不均查看每进程CPU占用改动态调度、任务队列最后分享一个我做集群调优时养成的习惯每次调整完调度权重、网络哈希或存储条带后都先跑一个小规模、能快速结束的验证任务确认改动确实有效再放量跑大作业。负载均衡是一个持续逼近最优的过程不要指望一次配置就能一劳永逸。集群规模一扩、应用一换前面的参数很可能就要重新推倒再调一遍。这活儿没有终局但每次把运行时间缩短、把资源利用率拉高那种“榨干每一核”的满足感是这份工作最让人上瘾的地方。
返回列表