混合部署下在线与离线任务的争用,本质是CPU、内存、磁盘IO和网络带宽的分配博弈,核心解法是分层隔离加优先级抢占,单纯靠调参救不了生产环境。
在线任务和离线任务为什么非要挤在一起
云服务器成本年年涨,尤其是GPU机器和高端CPU机型,不少公司把目光投向混合部署,说白了就是让在线任务和离线任务共享同一批物理机,在线任务比如Nginx网关、RPC服务、数据库中间件,要求延迟低、响应快;离线任务比如日志清洗、AI模型训练、数据仓库ETL,对延迟不敏感,只要最终算完就行。
行业共识认为,混部能把资源利用率从15%左右拉到40%以上,听着很诱人,但代价就是两类任务开始抢资源。
问题出在Linux内核的调度机制上,CFS调度器默认按权重分配CPU时间片,在线任务和离线任务如果同一个cgroup里跑,CPU密集型的离线任务会不断抢时间片,在线服务的P99延迟直接飙红。
业内专家指出,争用最严重的往往不是CPU,而是三级缓存和内存带宽,CPU时间片能被内核强制切换,但缓存和带宽这类资源没有硬隔离手段,一旦离线任务把L3缓存打满,在线任务的每次内存访问都要多等几十个周期。
在线任务离线任务争用如何解决:三个层面的隔离手段
第一层:cgroup和内核参数最基础的保命手段
- CPU限额:用
cpu.cfs_quota_us和cpu.cfs_period_us限制离线任务最多使用多少CPU时间片,比如给离线任务只分配4核,那么cfs_quota_us设为400000,period设为100000。 - CPU绑核:把在线任务绑定到物理核心的前几个核心上,离线任务绑定到后面的核心,Linux下用
taskset -c 0-3给在线服务,taskset -c 4-15给离线任务,这种方式简单粗暴但有效,物理隔离了L1/L2缓存。 - 优先级调整:给离线任务设置更高的nice值,让CFS调度器把更多时间片让给在线任务。
这套方案适合中小规模集群,缺点是静态配置不灵活,一旦在线任务的流量高峰过去,离线任务也用不了空闲的CPU,整体利用率还是上不去。
第二层:Kubernetes混合部署优先级方案动态调节的主流手段
Kubernetes已经成为混部的事实标准,核心思路是引入优先级class:
- Guaranteed:给在线任务设置完整的CPU和内存request/limit,保证它们随时能拿到资源。
- Burstable:给离线任务设置较低的资源请求,允许它们在在线任务空闲时使用剩余资源。
- BestEffort:最低优先级,完全使用空闲资源,随时可能被驱逐。
具体操作是在Pod Spec中配置priorityClassName,在线任务用高优先级class,离线任务用低优先级class,同时给离线Pod加descheduler.alpha.kubernetes.io/evict: 'true'注解,让Descheduler在节点资源紧张时优先驱逐离线任务。
Kubernetes官方还提供了static CPU manager策略,可以让在线Pod独占物理核心,离线Pod使用共享核心池,具体的kubelet配置:
--cpu-manager-policy=static
--cpu-manager-policy-options=full-pcpus-only=true
这种方案的优势在于动态调度,节点资源充足时,离线任务把CPU用满;在线任务流量上来时,Kubernetes自动驱逐离线Pod。
第三层:CPU标签和超线程感知调度精细化调优
这是大厂的进阶玩法,美团和字节跳动的混部实践中都提到过给CPU打标签的思路,具体做法是:
- 把物理核心分为在线优先和离线可用两组,通过Node Label标记。
- 要求在线Pod通过nodeSelector绑定到在线优先组,离线Pod默认调度到离线可用组。
- 对于超线程场景,需要关闭同一个物理核心的两个逻辑线程混用,因为超线程共享执行单元,一个逻辑线程跑离线任务,会拖慢同核在线任务的速度,解决方案是让离线任务只能使用某些物理核心的HT0线程,在线任务使用HT1线程。
这类方案已经有开源的实现,比如阿里巴巴的koordinator项目,支持LS(Latency Sensitive)和BE(Best Effort)两级调度,可以直接在Kubernetes里声明koordinator.sh/qosClass,用koordinator的CPU Suppress策略,能根据在线任务的实时负载自动压制离线任务的可分配CPU。
混合部署CPU争用场景下怎么落地:从压测到上线的完整步骤
第一步:摸清业务流量模型
- 拉取一周在线服务的监控数据,找出波峰波谷时间段。
- 统计离线任务的平均运行时长和资源峰值,分清哪些是短时爆发型,哪些是长期稳定型。
- 确认在线任务的延迟敏感度,RPC调用链上的服务延迟要求高,异步消费场景容忍度稍高。
第二步:搭建压测环境,验证争用程度
准备一台与生产配置一致的测试机,部署完整的在线服务和典型的离线任务负载,使用wrk或JMeter对在线服务压测,同时启动离线任务,观察:
| 指标 | 混部前 | 混部后(无隔离) | 混部后(cgroup限额) |
|---|---|---|---|
| P99延迟 | 50ms | 380ms | 70ms |
| 吞吐量 | 10000 QPS | 6400 QPS | 9500 QPS |
| CPU利用率 | 18% | 68% | 52% |
从表格可以看出,如果没有隔离手段,P99延迟翻了数倍,这是不可接受的。
第三步:选择隔离策略并灰度上线
- 先上线cgroup限额,观察在线服务P99延迟恢复情况。
- 如果延迟仍然超标,升级为Kubernetes优先级调度方案。
- 最后用CPU标签绑核进一步压缩延迟。
第四步:建立监控告警闭环
混部后要盯着三个指标:
- 在线任务的P99/P999延迟:超过阈值立即告警,人工介入调整离线任务的资源配额。
- 节点CPU steal time:如果steal时间占比超过5%,说明虚拟化层和宿主机的争用已经到了危险区。
- 内存带宽:可以用
perf stat -e offcore_response.demand_data_rd.llc_miss.local_dram监测LLC miss情况,如果miss率显著上升,说明缓存争用加剧。
等保合规和成本怎么算
混合部署不只是技术问题,国内云服务器租赁还牵扯到合规问题,如果离线任务处理的是敏感数据,而在线任务所属业务有等保三级要求,那么混部方案需要额外考虑数据隔离,近期百度智能云上线了混部集群的专属解决方案,据公开信息显示,这类型方案支持打标签隔离审计域,但价格比普通物理机集群高出约20%-30%。
如果是中小团队,
大量使用「云服务器BCC混部」这类概念的产品,比较划算的路径是先拿几台测试机验证混部收益,再评估生产环境是否值得投入,混部省下的钱,是否能覆盖增加的可观测性监控、调度系统开发和SRE人工成本,需要按团队规模算细账。
- 10台机器以内的集群:混部收益有限,单独跑离线任务即可。
- 50台以上的集群:混部能节省相当可观的机器采购成本,值得投入。
- 100台以上的集群:需要专门的调度平台,普通手工配置会把人拖垮。
在线和离线混合部署彻底解决争用
几年混部实践下来,最深的体会是:解决争用不是让两类任务和平共处,而是让在线任务有绝对优先权,离线任务随时准备让路,从cgroup限额到优先级调度,再到koordinator这类成熟的混部编排系统,解法已经相对成熟。
但如果团队没有足够的底层内核调优能力,也不建议盲目上混部,毕竟保住在线服务的SLA是底线,省下来的机器成本可能还不够赔偿一次P0事故的损失。
混合部署下怎么降低争用影响
问题1:混合部署下在线任务延迟抖动特别严重,有没有快速止血的办法?
先用top和pidstat定位CPU占用最高的离线进程,将它的nice值调到19,然后用cgexec把进程移入限制CPU份额的cgroup控制组中,通常可以短时间内缓解争用,接下来再梳理Pod优先级,逐步过渡到Kubernetes混部方案。
问题2:kubernetes混部配置之后,离线任务老是跑不完,怎么调整?
查看在线任务的实际CPU使用率,如果长期低于50%,说明资源配额给的太保守,调高离线任务的limit,或者把离线Pod的优先级从BestEffort升级到Burstable,并设置合理的内存request,让调度器更愿意把Pod调度到节点上,运行时长和pod规格是正比关系,可以按需调整资源规格。
问题3:混部集群里的离线任务在Kubernetes驱逐之后,运行到一半的进度丢了,怎么处理?
使用checkpoint机制,定期将模型参数或数据处理进度写到持久化存储中,Kubernetes本身也支持PodDisruptionBudget配置,用它保证至少有一定数量的离线Pod不被驱逐,降低重算成本。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/623863.html





