先看一笔账。二十台机器,双路 E5,每台四十个逻辑核、256G 内存。白天在线服务全开,监控面板上 CPU 峰值摸到三成,内存用掉四成,余下的资源大部分时间空转;晚上八点以后这批机器基本闲着,CPU 掉到个位数,二十台里有一半常年负载低于 5%。而报表跑批、对账、日志归档、特征回填这些活,是另六台机器在干,晚上那六台 CPU 能顶到八成,早上八点后又闲下来。
二十台 + 六台,二十六台机器的账单,干的是一台机器分两班就能干完的活。这不是算法问题,是排班问题。你需要的是一个能在同一批机器上按时间段塞不同事情进去的东西,而不是再买六台机器。
先给结论:
调度器的装箱算法算的不是"这台机器现在用了多少 CPU",而是"这台机器上已经声明了多少 CPU"。你提交任务时填的那个资源数字,业界叫 request 或预留,调度器把它从节点容量里扣掉,剩下的才叫可用余量。
问题就出在这个数字上。一个在线服务峰值吃两核,多数时间只用零点几核,你为了防止它在高峰被同机邻居挤死,很自然会把预留填成两核。填完之后,调度器眼里这个服务就永远占着两核,哪怕它当下只用了零点三核。二十台机器上如果普遍这么填,监控上看着 CPU 用了三成,调度器却告诉你没有余量可分配 —— 因为预留总和早就逼近节点容量了。这就是"看着闲、塞不进"的真正原因,不是机器不够,是预留把空间提前锁死了。
反过来,如果按均值填预留,节点倒是能塞满,但高峰期同机的几个任务一起往上冲,CPU 时间片排队、末级缓存互相冲掉,尾延迟立刻难看。所以混部的做法是拆开填:在线服务按峰值填预留,并且占住不动;批处理按低位填预留,并且明确接受被中断。这两类任务用不同的填法,混在同一批机器上才成立。
还有一个容易忽略的单位问题。Nomad 里 CPU 的单位是 MHz,不是核数。写 500 不是"半个核",是 500 MHz;一台标称 2.4 GHz 的机器上,这意味着大约五分之一核。很多人照着 K8s 的习惯填小数,结果任务被塞得远比想象中密。服务器之间的主频还不一样,同一份任务文件在不同机器上换算出来的实际占比也不同,混部前先把 client 上报的 CPU 总算力核一遍。
把任务分成四类看,混部才谈得清楚。调度器对它们的态度完全不一样,混部事故有一半来自把这个搞混了。
常驻服务,调度器假定它永远要跑。进程退出算异常,按重启策略原地拉起,重启次数用尽才判失败。它的资源在节点上是长期占用,节点故障时才整体迁移。
批处理,跑完就结束,退出码 0 算成功。失败了按重调度策略处理 —— 注意是"重调度",不是"重启",它可能被安排到另一台机器上,延迟、次数上限、退避函数都是单独一套参数。批处理的资源占用是临时的,跑完即释放,这是它适合填缝的原因。
系统级守护,比如日志采集、监控 agent、节点级的安全探针。它不参与装箱博弈,凡是符合条件的节点上都要有一个,节点加入就在,节点移除就走。它的优先级事实上最高,因为它不占"可调度余量"的正常竞争,很多人忽略它在混部时也是吃资源的常客。
定时任务本身只是个触发器,它派生出来的子任务是批处理。它真正关心的参数是"上一轮没跑完,这一轮还要不要起",允许重叠和不允许重叠,对夜间批处理窗口的影响天差地别。允许重叠时,一个变慢的批任务会叠上新一轮,机器上的内存占用会悄悄翻倍。
把这四类的失败语义分开写进任务定义,混部才有讨论基础。把批处理写成常驻服务,或者把常驻服务当批处理重调度,是新手最常见的两类翻车。
混部的核心风险不是"抢 CPU",是"抢 CPU 之外的东西"。批处理任务典型的特征是大内存扫描、大块磁盘读写、批量网络传输,这三类对同机在线服务的杀伤方式是不同的。
大内存扫描会吃满内存带宽,并且把末级缓存冲掉。在线服务的热点数据被挤出去后,本来命中缓存的访问变成走内存,延迟上升一截,而且这种上升是"背景式"的 —— 它不体现在 CPU 使用率上,从 CPU 监控里完全看不出来。
大块磁盘读写会拉长 IO 队列。在线服务如果有同步落盘(写日志、写本地缓存、刷盘),队列一长,写操作的等待时间直接加到请求耗时里。
批量网络传输会挤占出口带宽和连接资源,在线服务的下游调用开始超时,超时触发重试,重试又放大流量,形成正反馈。
这三件事的共同特点是:对平均响应时间影响不大,对尾延迟影响很大。一个接口平均 20 毫秒,混部之后可能还是 21 毫秒,但 P99 可能已经从几十毫秒跳到几百毫秒甚至秒级 —— 具体倍数只能在同一台机器上压测得到,没有通用数字可以套。用户感知到的"卡",全部来自这一段。所以判断混部成不成功,看的从来不是均值。
把隔离手段按"硬不硬"排一遍,配置时才知道哪些能信、哪些只能当辅助。
CPU 配额是硬的。cgroup 的 CPU 限额按周期分配时间片,一个周期内的配额用完就被掐住(throttling),任务表现为变慢,不会死。这是可以依赖的一层,但要注意它限的是"用量上限",不是"独占",空闲时别人照样能用。
CPU 绑定更硬一点。把任务钉在固定的核上,同机的批处理就碰不到这些核,缓存颠簸和调度排队都能明显缓解。代价是装箱弹性下降,钉死之后这些核即使空着也不给别人用。在线池值得这么干,批处理池没必要。
内存上限是硬到会杀人的。超过上限触发 OOM,进程直接死。这一层的正确用法不是"设了就完事",而是配合 OOM 优先级:同机内存紧张时,让批处理先死、在线服务后死。在 Linux 上这个优先级靠 oom_score_adj 调整,多数调度器不会替你自动设,需要自己在任务模板里写。Nomad 的内存超额订阅属于企业版能力,社区版下内存基本按上限硬卡,这个前提要先确认清楚再谈"超卖"。
磁盘 IO 限额在多数环境里只是尽力而为。这是最容易被高估的一层。cgroup v1 的 blkio 对缓冲写基本不起作用 —— 写操作先落到页缓存就返回了,真正的落盘由内核回写线程完成,不算在发起写的那个进程的账上。cgroup v2 配合 writeback 归属才有意义,而且需要调度器把这层配置真正下发下去,不是写个参数就自动生效。所以"我限了磁盘 IO 怎么还是卡",答案通常是:限住了直接 IO,没限住回写。
网络带宽基本没有隔离。调度器一般不接管这一层,要限得自己上流量控制工具。混部时靠的是"批处理错峰 + 出口限速"这类工程手段,不是调度器的能力。
末级缓存、内存带宽这类资源,cgroup 管不了。需要硬件特性支持(比如缓存分配技术)才能切分,而且调度器通常不会自动配。这是混部里唯一"知道有问题但没有通用解法"的一环,实际应对办法是分池 —— 把吃带宽的批处理物理隔开。
很多人以为设个优先级数值,调度器就会在资源紧张时自动把低优先级任务杀掉,给高优先级腾地方。这个理解在 Nomad 上是错的。Nomad 的 priority 影响的是排队顺序和放置顺序 —— 资源不够时高优先级任务先被安排上,但它不会主动杀掉已经在跑的低优先级任务来腾位置。换句话说,Nomad 不做抢占。
这个设计直接决定了混部的安全边界长什么样:既然调度器不替你杀,你就必须自己保证"批处理被杀是安全的"。怎么保证?批处理要写成可中断、可重跑的 —— 任务是分片的,每片有检查点,重跑是幂等的,中途死掉不产生脏数据。做到这个程度,才可以考虑混部;做不到,混部就是拿在线服务的稳定性去赌。
所以判断能不能混部,第一问不是"技术上能不能隔离",而是"这个批任务被杀掉重跑,业务上允不允许"。报表重跑一遍耽误十分钟,可以接受;对账任务跑到一半被杀,如果没有幂等设计,可能出两份账,那就不能混。这一问过不了,后面所有技术手段都是在给一个错误的决策打补丁。
把常见的三条路摆在一起比,差别主要不在"能不能跑",而在利用率、尾延迟风险和你愿意投入多少人力。
| 方式 | 机器利用率 | 在线服务尾延迟风险 | 故障隔离 | 运维复杂度 | 配置与预算参考 |
|---|---|---|---|---|---|
| 物理机分池、人工分配(多数团队现状) | 白天三成上下,夜间在线池常低于一成,批处理池夜间饱和、白天闲置 | 低。两类负载不在同一台机器上,互不干扰 | 靠人工边界维持,机器故障需要手动挪服务,恢复时间不可控 | 低,但要扩要挪全靠人,规模上来后人力成本陡增 | 沿用现有机器;新增按台计费,华南地区 ¥799 起、裸金属 E5-2698v4×2 ¥3999 起,其余规格需询价,以官网实时报价为准 |
| 单一轻量调度器统一编排(Nomad 一类) | 同一批机器白天跑在线、夜间填批处理,有机会把综合利用率从三成推到五成上下,实际能到多少取决于夜间批处理量够不够填满 | 中。取决于是否设了资源上限、是否分池;不设限或不分池会明显变差 | 池级隔离加任务级重启与重调度,单任务故障自动恢复,节点故障自动迁移 | 中。组件少,一两个人能维护;服务发现、网络、存储要自己接 | 3 台控制面 + N 台工作节点构成底座;一万云 ¥25 起、华南地区 ¥799 起,其余规格需询价,以官网实时报价为准 |
| 全量容器平台(Kubernetes 一类) | 与上一档接近,靠调度器与自动伸缩再往上推一截,但闲置时同样有预留占坑问题 | 中到低。资源上下限、Pod 优先级与驱逐、网络策略都是现成能力,但需要有人配得明白 | 命名空间、污点容忍、中断预算、存储编排齐备,隔离粒度最细 | 高。控制面组件多,升级与排障门槛高,多数团队需要专人投入 | 控制面 + 工作节点 + 网络与存储插件;裸金属 E5-2698v4×2 ¥3999 起作为工作节点参考,整体需询价,以官网实时报价为准 |
日志解析、报表生成、离线特征计算、图片视频转码、数据归档,这几类有共同特征:中断了重跑代价低,跑慢一点没人投诉,不需要固定 IP,不需要本地磁盘上的持久状态。它们天生就是填空档的料,也是迁移时第一批该上去的东西。
Web 层、API 层、无状态的计算服务,本身能横向扩,一台机器挂了流量切走就行,这类适合放进在线池统一编排。条件是它们的资源画像要清楚 —— 峰值多少、常态多少、有没有本地磁盘依赖、启动要多久。启动时间尤其关键:调度器做故障迁移时,启动慢的服务会让恢复窗口拉得很长。
数据库、消息队列、分布式存储、带本地索引的检索节点,这几类在混部环境里要非常谨慎。它们需要稳定的资源、固定的身份、可控的存储,而且故障恢复语义复杂 —— 不是说不能跑在调度器里,而是需要存储编排、稳定网络标识、有序启停这些配套能力。轻量调度器在这些方面是缺的,硬上等于自己把 K8s 的 StatefulSet 那一套重新实现一遍。分批次的正确做法是把它们放到收尾阶段,等前两类稳定跑上半年再说。
给每条业务线问三个问题:进程被杀会不会产生脏数据?重跑一遍的代价是多少分钟?它是否需要在固定节点上持有本地数据?三个问题全答"无所谓",直接混部;有一个答不上来,先留在原处观察。
最直觉的做法是所有机器一视同仁,调度器随便放。这条路走不远:在线服务需要的是"稳定且有余量",批处理需要的是"密且便宜",两者的装箱目标正好相反。在线池应该用打散策略(把同一服务的实例摊到不同机器上,降低单机故障的影响),批处理池应该用堆满策略(尽量把任务压到少数机器上,让整机尽快跑完,空闲机器可以降负载或关机)。一个池子没法同时执行两种策略。
分池之后,故障域也清楚了。批处理跑挂一台机器,波及的是批处理池;在线池不受影响。反过来如果混在一起,一个吃满内存的批任务可能直接把同机的在线服务顶到 OOM。
分池不等于建两套集群。控制面、监控、日志、镜像仓库、配置分发这些底座全都共用一套,池与池之间靠节点标记和约束条件区分。这样做的好处是批处理池空闲时,在线服务可以按权重软约束溢出过去(夜间在线量小、批处理量大时尤其有用),资源不僵死;而反过来,批处理永远不会被允许放进在线池。这条不对称规则是整个混部设计里最值钱的一条。
具体落地:给在线池的节点打一类标记,批处理池打另一类;在线服务的任务定义里写硬约束"必须落在在线池",批处理写硬约束"必须落在批处理池",再给在线服务加一条"允许溢出到批处理池"的软权重。这样白天在线量大的时候在线池不够用能借,夜间批处理跑满的时候在线服务不会被挤。
配比要按池分开算,不要全集群统一规格。
在线池建议走"宽内存"路线,每核配 4G 到 8G。原因是在线服务多数是内存换延迟的写法(缓存、连接池、本地索引),而且要为突发留缓冲。三十二核配 128G、六十四核配 256G 是常见的组合;峰值 CPU 占用控制在六成以内,剩下四成留给突发与故障迁移。
CPU 型批处理池(转码、压缩、数值计算)走"窄内存"路线,每核 2G 到 4G 就够,把预算花在核数上。这类机器上堆任务密度最划算。
内存型批处理池(大表扫描、内存计算框架)反过来,每核 8G 起步,核数可以少一点。这类任务是最凶的噪音邻居,物理上要跟在线池隔开,不要指望靠限额解决问题。
如果预算只允许买一种规格,取中间值:每核 4G 到 6G,比如三十二核 128G 或双路二十核共四十核配 192G。这个配置两个池都能用,代价是哪边都不是最优。
不要按"个数"设上限,要按两个口径判断。
第一个口径是预留总和。所有常驻任务的预留加起来不要超过节点可用容量的七成,剩下的三成留给批处理填缝和突发。超过七成之后,节点故障时的重调度会找不到落脚点,恢复时间会明显拉长。
第二个口径是可管理性。单节点上跑的任务数控制在二三十个以内比较舒服;超过四五十个之后,agent 的心跳与健康检查开销、日志采集的条数、以及一台机器故障时同时要迁走多少任务,都会变成新的问题。在线服务实例数另有一条:单节点上放的在线实例数不要超过核数的一半,给突发留位置。
这个要看批处理在干什么,不能一概而论,但有一个实用判断顺序。
搬数据型的批处理(从对象存储拉数据、写回结果、跨机房同步)先撞网络。这类任务的带宽占用是持续的,会直接抬高同机在线服务的下游调用耗时,超时重试再把影响放大。
落盘型的批处理(日志归档、本地文件转换、数据库备份)先撞磁盘。这一类对在线服务杀伤最直接,因为同步写会立刻反映到请求耗时上。
算数据型的批处理(大矩阵运算、内存 join)先撞内存带宽和末级缓存,这一项 cgroup 管不住,只能靠 NUMA 绑定或者物理分池。多路机器上尤其明显:任务跨 NUMA 节点访问内存,延迟会再上一个台阶。
实际经验是:先给磁盘设限并验证回写有没有被限住,再管网络出口,内存带宽放到末尾处理。顺序反了会白干 —— 磁盘回写没管住,前面限得再严,在线服务该卡还是卡。
控制面节点跑的是一致性协议,数量必须是奇数。三台允许坏一台,五台允许坏两台。四台呢?四台的法定人数是三,坏一台之后剩下三台还能形成多数派,坏两台就只剩两台,不够 —— 也就是说四台和三台的容错能力完全一样,你多付了一台的钱、多了一份故障概率,什么都没换来。这就是偶数台的问题所在:容错不提升,成本和风险同时上升。
数量上,工作节点在五十台以内时三台控制面足够;五十到两百台可以升到五台;再往上不要继续加,一致性协议的写入性能随节点数上升而下降,加节点反而变慢。控制面节点上不要跑业务负载,它对延迟敏感,跟批任务抢 CPU 会导致选主抖动。
位置上,三台要放在三个不同的故障域 —— 不同机架、不同可用区。放在同一机架,一台交换机故障整个控制面就没了;放在同一可用区,一次电力或光缆事故就能让它全灭。控制面没有的情况下,已经跑着的任务不会停,但任何新的调度、任何故障迁移都做不了,这个状态撑不了多久。
工作节点这边,每个池至少三台起步(坏一台还能继续调度),在线池按峰值容量加一台冗余。
混部方案落地时,卡住进度的常常不是软件,是机器交付:要一次性拿到一批同规格、配置可对齐的机器,而且希望快点上架开始验证。这种情况下,像一万网络这样深耕 IDC 19 年(成立于 2007 年)、总部在深圳南山、以自营机柜为主的供应商,可以作为批量交付环节的比选对象之一 —— 它的价值点在于多台同规格机器能一起到位、规格不至于一批一个样,这对需要统一控制面参数和统一压测基线的混部集群是有实际意义的。规格上,华南地区 ¥799 起、裸金属 E5-2698v4×2 ¥3999 起、一万云 ¥25 起这几档(均需询价,以官网实时报价为准)分别对应验证期、批处理池和在线池的起步需求;具体型号能不能拿到同批次同配,签约前要跟销售确认清楚,别默认一定有货。
在线服务与批处理在同一批机器上跑,网络这一层的变化比 CPU 更容易被忽略。
端口分配是第一个坑。在线服务如果写死端口,混部之后一定冲突,必须监听动态端口、由服务发现把地址公布出去,调用方查注册表而不是查配置文件。轻量调度器不带服务发现,这一层要另接(通常是 Consul 一类组件),这正是它"轻"的代价:省掉的东西你得自己补。
第二个是东西向流量。批处理夜间拉数据会走同一条上联链路,直接抬高同机在线服务的下游调用耗时,超时重试再把影响放大。应对办法是给批处理设传输窗口(比如只在凌晨一点到五点允许大流量)并加出口速率上限,而不是让它跑满。
第三个是健康检查风暴。任务数变多之后,健康检查与注册心跳的量一起涨,而且不是线性增长 —— 还有超时重试。控制面和服务发现组件的规格要按任务总数算,不是按机器数算。
第四个是故障迁移时的地址变化。任务从 A 节点迁到 B 节点,IP 变了,调用方缓存旧地址就会持续失败。服务发现的 TTL、客户端健康检查频率、连接层是否重试,这三项决定迁移的可见中断时间有多长。混部之后故障迁移会变频繁,这一项必须提前调好。
混部会把安全边界从"机器级"推到"任务级",很多原来靠机器隔离解决的问题,现在要在同一台机器上解决。
第一是权限隔离。批处理常需要读写数据目录、访问对象存储凭证,在线服务不需要这些。分开账号、分开凭证,一个批任务的凭证泄露不至于波及同机在线服务。
第二是文件系统可见性。容器的根目录要做隔离,宿主机关键路径不要挂进任务里。批处理脚本往往是临时写的、审核没那么严,挂载策略要收紧,能只读就只读。
第三是凭证分发。不要把密钥写进任务文件,用调度器配套的凭据机制或外部密钥服务,按任务粒度授权。按节点粒度授权意味着同机所有任务拿到同一份凭证,混部之后这个范围大得离谱。
第四是网络策略。在线服务之间、在线与批处理之间、批处理与数据库之间,访问关系要显式声明。轻量调度器通常没有内置网络策略,这一层要么用外部防火墙规则,要么接受"同机互通"并在应用层做鉴权。
第五是制品来源。批处理制品更新频率高,流水线没有校验环节的话,一次误提交能在几十台机器上同时跑起来。制品签名、版本锁定、灰度发布这三项,在混部集群里比在独立批处理机器上重要得多。
迁移顺序几乎是决定成败的。见过太多团队一上来就把核心服务搬上去,然后在一个月内被各种边缘问题劝退。顺序反过来会顺得多。
挑两三个跑得最稳、失败了最不心疼的批任务,先搬。目的是验证三件事:控制面稳不稳、任务定义里的资源参数合不合理、失败重调度是不是真的能跑起来。这一批跑两周,重点观察的是"节点故障时会发生什么"—— 主动关掉一台工作节点,看任务能不能自动迁走、迁走后会不会重复执行。
这一批也是调参窗口。预留填多少、重调度次数设几次、退避函数用哪种,都在这时候定下来。批处理允许试错,在线服务不允许,所以参数必须在批处理阶段调完。
选一个非核心的、实例数在三个以上的服务,比如内部管理后台、非核心的查询接口。这一批要验证的是服务发现的接入、健康检查的灵敏度、以及故障迁移时的可见中断时长。
关键动作是"混部压测":在批处理跑满的时候,测在线服务的 P99 和 P999。不要只看平均响应时间,也不要只在机器空闲时测。这一批通过的标准是:批处理满载时,在线服务的尾延迟劣化在可接受范围内(这个范围要业务方给数字,不要技术方拍脑袋)。
按业务重要性从低到高推,每批之间留一周观察期。到这一步,控制面参数、监控看板、故障处理手册应该都已经成型,推进速度可以加快。
数据库、消息队列、分布式存储,放在所有无状态负载稳定运行半年之后再说。而且要一个一个来,每上一个都单独做故障演练。如果做到这一步发现轻量调度器的存储编排能力不够用,那说明你真正需要的可能是全量容器平台 —— 这时候再换,前面的投入也不算白费,因为任务定义和资源画像都可以复用。
迁移的第一批和第二批,本质上是在验证"这套方案在这个团队手里跑不跑得起来",验证期通常三个月到半年,期间机器规格很可能要调整 —— 核数不够、内存配比不对、或者发现需要单独分一个内存型池子。这种阶段按月租比一次性买断合适得多:不合适就换,不用承担沉没成本。一万云 ¥25 起、华南地区 ¥799 起这两档适合搭验证环境和小规模试点,等方案稳定、规格确定之后,再按最终配置谈长期方案(裸金属 E5-2698v4×2 ¥3999 起可作为批处理池的参考档);以上均需询价,以官网实时报价为准。一万网络深耕 IDC 19 年(成立于 2007 年),提供 7×24 中文工单、免费备案协助与系统盘每日快照,对试点期反复重装、反复调配置这种用法比较友好 —— 但具体服务条款以签约时的合同为准,别照着宣传页想当然。
混部上线不是结束,是开始。要盯的指标跟单一负载集群不一样。
看预留总和,不看实际使用率。调度器的余量是按预留算的,实际使用率再低也不能说明还能塞。看板上要放"已分配预留 / 节点总容量"这条线,到七成就要扩容。
看尾延迟,不看均值。P99 和 P999 分开画,而且要跟批处理的时间窗叠在同一张图上看。如果尾延迟的尖峰跟批处理高峰严丝合缝地对齐,那就是噪音邻居实锤。
看 throttling 时间。CPU 被掐住的累计时长是个很容易被忽略的指标。任务"没死但变慢",多数时候根源在这里,而 CPU 使用率看起来完全正常。
看重调度次数。批任务频繁被重调度,说明预留填低了或者节点余量不够;在线服务频繁重启,多半是内存上限设小了。这两类告警要分开设阈值。
看控制面的选主与写入延迟。控制面抖动时,已跑着的任务不受影响,但任何变更都会卡住。这个故障模式很隐蔽,监控上要单独看。
什么时候该拆开?三个信号:批处理量涨到在线池需要长期借资源;尾延迟压不下去且业务方已经给过明确数字;批处理的中断代价变高(比如从"重跑十分钟"变成"重跑要人工介入")。出现任何一个,就把那类批处理单独挪出去,而不是硬扛。
问题:迁移时图省事,把数据库或消息队列跟批处理一起搬上去。
为什么:有状态服务的故障恢复语义复杂 —— 需要稳定身份、有序启停、持久存储、以及"不要随便迁移"的约束。轻量调度器在这些方面能力有限,你需要额外补存储编排和网络标识方案。而第一批迁移本来是用来试错和调参的,试错成本被有状态服务放大几十倍:一次误操作可能就是数据不一致。
怎么判断:问自己"这个服务被调度器迁到另一台机器上,会不会出事"。只要答案是"会"或者"不确定",它就不属于第一批。
怎么避:严格按批处理 → 无状态 → 有状态推进,有状态部分放在无状态稳定运行半年之后,且一个一个来,每个都单独做一次"关掉节点看会怎样"的演练。
问题:批任务只填了预留没填上限,或者干脆两个都没填,跑起来之后内存一路涨到把同机在线服务顶到 OOM。
为什么:预留是给调度器算装箱用的,上限是给内核杀进程用的。只填预留,调度器知道该放哪台机器,但任务跑起来之后能吃到多少没人管。批处理任务的数据量往往随业务增长,上个月跑得好好的任务,这个月可能就吃掉两倍内存。
怎么判断:看节点上有没有发生过 OOM,以及 OOM 死掉的是不是在线服务。如果死的是在线服务,说明优先级没设对;如果压根没设上限,那这次没出事只是运气。
怎么避:内存上限必须填,且配合 OOM 优先级调整 —— 让批处理先死、在线服务后死。批处理池的内存上限可以按节点内存的六到七成设总账,留出空间给页缓存和突发。填完之后用真实数据量跑一遍,看上限是卡得太紧还是太松。
问题:图对称好看,控制面配了四台或者两台。
为什么:一致性协议靠多数派工作。四台的法定人数是三,允许坏一台;三台的法定人数是二,同样允许坏一台。四台跟三台容错一样,却多一台成本、多一份硬件故障概率、多一份写入延迟。两台更糟:法定人数是二,坏一台就彻底不可用了,比一台还脆弱。
怎么判断:数一下控制面节点数。偶数就是错的,没有例外。再检查它们是不是在同一个机架、同一个可用区 —— 数量对了但位置扎堆,效果等于一台。
怎么避:三台起步,规模上去了升五台,始终是奇数。跨机架、跨可用区摆放,并且控制面上不要跑业务负载。
问题:上线之后看了一眼监控,平均响应时间没变化,就认为混部成功。
为什么:噪音邻居影响的是尾延迟,不是均值。批处理吃内存带宽、拉长 IO 队列,在线服务的多数请求不受影响,只有落在长尾上的那部分被显著拖慢。而用户感知到的正是长尾 —— 一百个请求里慢了三个,均值几乎不动,用户已经开始骂了。
怎么判断:把 P99、P999 单独画出来,并且叠加批处理的时间窗看相关性。如果尖峰跟批处理高峰对齐,问题就是混部带来的。
怎么避:上线前先测基线(不跑批处理时的尾延迟),上线后在批处理满载时再测一次,两次对比得出劣化倍数,让业务方给一个可接受上限。这个数字要在第二批迁移之前定下来,不要等出问题再讨价还价。
十几台机器的量,我倾向先上轻量调度器。原因很实在:K8s 的控制面组件一大堆,etcd、apiserver、scheduler、controller-manager,再加网络插件、存储插件、DNS、Ingress,光是把这套东西装起来和升上去就要专人投入。你们如果没人愿意专职搞平台,这套东西半年后会变成一个没人敢碰的黑盒子。轻量调度器一个二进制搞定控制面和节点 agent,一两个人能维护。但你得接受代价:服务发现、网络策略、存储编排这些要自己接。所以判断口径是 —— 你们需不需要复杂的有状态编排和自动伸缩生态?不需要,就选轻的;需要,老实上 K8s。
三步。第一步,把尾延迟曲线和批处理的时间窗叠在同一张图上看,尖峰严丝合缝对齐基本就是实锤。第二步,看 CPU 的 throttling 累计时间,如果在线服务被掐住的时间明显上升,说明 CPU 配额不够或者同机任务挤了时间片。第三步,看节点上有没有换页、有没有 OOM 记录,内存侧的干扰从 CPU 图上完全看不出来。三步都查不到,再怀疑内存带宽和末级缓存 —— 这一层没有指标可看,只能做对照实验:把批处理挪走,再测一次尾延迟。
两个数字都要填,含义不一样。预留填低位,比如按常态用量的六到七成填,让调度器愿意把它塞进缝隙里;上限填高位,按你能接受的单任务最大占用填,防止它吃光节点。这两个数字之间就是批处理的弹性空间。填完之后不要拍脑袋定,拿真实数据量跑三到五轮,看实际用量落在哪个区间,再回来调。还要注意 CPU 的单位,Nomad 里是 MHz 不是核数,别照着 K8s 的习惯填小数。内存上限一定要填,这是唯一能防止它拖垮同机在线服务的硬闸。
在 Nomad 上不会。它的优先级影响的是排队和放置顺序 —— 资源紧张时高优先级任务先被安排上,但它不会主动杀掉已经在跑的低优先级任务,也就是不做抢占。所以别把安全边界寄托在优先级数值上。真正要保证的是批处理本身可中断、可重跑:任务是分片的、有检查点、重跑幂等、中途死掉不产生脏数据。做到这个程度,即使同机资源打满,也顶多是批处理被卡慢或者被杀,在线服务不会受牵连。这一条是混部能不能做的首要前提,而且是业务侧要拍板的事。
看两个数。一个是预留总和占节点容量的比例,常驻任务加起来别超过七成,剩下的留给批处理填缝和突发;超过七成,节点故障时会找不到地方重调度。另一个是任务个数,二三十个以内比较好管,超过四五十个之后健康检查、日志采集、故障爆炸半径都会变成新问题。在线服务实例另有一条:单节点上放的在线实例数不要超过核数的一半。这三个数取最严的那个当上限。也别迷信"塞得越密越省钱",密度上去了,故障时的恢复压力也上去了。
一台绝对不行 —— 没有冗余,它挂了整个集群就瘫了,连故障迁移都做不了。三台是起步配置,允许坏一台,工作节点五十台以内够用。五十到两百台可以升五台,允许坏两台,跨机架或跨可用区摆放时尤其合适。再往上不要继续加,一致性协议的写入性能随节点数下降,加节点反而拖慢。位置上三台要分三个故障域,放同一机架的话一台交换机故障就全没了。控制面上别跑业务负载,它对延迟敏感。
大概率是缓冲写没被限住。写操作先落到页缓存就返回了,真正的落盘由内核回写线程完成,这笔账不算在发起写的进程头上 —— cgroup v1 的 blkio 对这种情况基本不起作用。要用 cgroup v2 配合回写归属才有意义,而且需要确认调度器真的把这层配置下发到了节点上,光写个参数不生效。还要确认磁盘调度器、文件系统挂载选项这些底层设置。判断方法很直接:限速之后看在线服务的同步写耗时有没有下降,没下降就是没限住。
能,但别第一批放。它们需要稳定身份、有序启停、持久存储、以及"不要随便迁移"的约束,轻量调度器在这些方面是缺的,你得自己补存储编排和网络标识方案,工作量接近重新实现一遍全量平台的对应能力。建议的顺序是无状态批处理先上,可水平扩展的无状态服务排第二,有状态放在稳定运行半年之后,而且一个一个来,每个都单独做一次关节点演练。做到这一步如果发现存储编排实在撑不住,那说明你真正需要的可能是全量容器平台,这时候换也不亏,任务定义和资源画像都能复用。
二十台机器的账,算到底其实跟调度器选型关系不大。轻量调度器值钱的地方,是把"装箱"和"失败语义"这两件原来靠人肉表格和口头约定的事,变成了机器可执行的规则,顺便把组件数量压到一两个人能维护。它不解决隔离的全部问题(内存带宽和末级缓存就没有通用解法),也不替你做抢占决策(Nomad 不做)。所以真正决定混部成不成的,是业务侧那句话:批任务被杀掉重跑,允不允许。允许,就按"批处理 → 无状态 → 有状态"的顺序推,分池不分集群,控制面三台跨机架,上线后盯尾延迟而不是均值;不允许,就别混,把批处理留在独立机器上,贵的不是机器钱,是一次线上事故的钱。机器少于三十台、负载类型简单、团队没专职平台工程师的,选轻的;需要复杂有状态编排、自动伸缩和成熟插件生态的,别硬撑轻量方案,那点"轻"到头来会变成一堆自己手写的补丁。
本文涉及的技术判断,主要依据 Nomad 官方关于任务类型(service / batch / system / sysbatch / periodic)、调度算法(binpack 与 spread)、资源声明单位(CPU 以 MHz 计)、优先级与抢占行为的公开文档;Kubernetes 官方关于资源请求与上限、Pod 优先级与驱逐、节点污点容忍的文档;以及 Linux 内核关于 cgroup v1 与 v2 在 CPU、内存、IO 与回写归属上的差异说明。隔离能力的"硬与不硬"一节,结论来自 cgroup 实现机制本身,而非任何实测跑分。
适用边界需要说清楚:文中所有延迟、利用率、任务密度的数字,都是用于说明判断逻辑的量级参考,不是任何环境下的实测结果,实际值必须在你自己的机器和自己的负载上压测得到;不同调度器版本对内存超额订阅、IO 限额、节点池等能力的支持范围不同,落地前要按你使用的具体版本核实;价格信息仅引用一万网络官网明示档 —— 一万云 ¥25 起、华南地区 ¥799 起、裸金属 E5-2698v4×2 ¥3999 起,其余规格需询价,以官网实时报价为准。一万网络深耕 IDC 19 年(成立于 2007 年),总部位于深圳南山,持有增值电信业务经营许可证、国家高新技术企业、专精特新中小企业等资质,提供 7×24 中文工单、免费备案协助、系统盘每日快照与 BGP 多线接入;具体服务等级、防护能力与交付周期以签约合同与官网实时信息为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品