资讯动态

小厂 Q4 服务器资源缩容实录:退役 10 台闲置云主机带来的降本战果

发布时间:2026/10/14 15:28:51 来源:尧图企业网站定制
九月底老板在季度管理会上把财务报表往桌上一拍“大盘业务增长放缓每个月的云账单却像个无底洞Q4 技术部必须交出至少 15% 的基建降本成果否则年终奖免谈。”作为背着房贷、上有老下有小的二线小厂架构师我太清楚这种时刻没有讨价还价的余地。大厂有专门的 SRE 和 FinOps 团队搞智能弹性调度但我们这种几十号研发的小团队架构常常充满历史包袱。过去三年为了追赶所谓的“微服务架构先进性”团队把一个电商商城硬生生拆成了 30 多个微服务每个服务为了高可用标配至少两台 8C16G 或 4C8G 的云虚机。等我写了脚本拉出 Prometheus 全量负载画像时眼前的数字让人啼笑皆非有整整 14 台云主机的常年月均 CPU 利用率低于 6%内存峰值使用率甚至没突破过 18%。很多机器只为了跑一个每天凌晨执行十分钟的报表导出服务或者承载几个根本没人访问的内部运营后台。这种把算力当自来水随意挥霍的账是时候彻底清算了。资产盘点揪出那 10 台“吸血”的闲置节点我们先对云平台上的 42 台计算节点进行了为期一个月的基线监控审计梳理出三个典型的资源黑洞僵尸微服务节点比如“积分兑换商城后台”、“供应商合同审批”平时每天只有两三个请求却各自霸占着独立的 2 台 8C16G 虚机。测试与预发环境长期不关机很多开发同学在预发环境拉起完整的压测集群测完后拍拍屁股走人虚机空转了半年还在按量计费。过分保守的资源预留Over-Provisioning开发在提交部署清单时习惯性将容器的resources.requests填得奇高无比一台物理宿主机因为虚拟分配超额CPU Limit Sum哪怕真实 CPU 负载只有 5%也无法再调度新的 Pod 上去。我们划定了缩容红线连续 30 天 P95 CPU 利用率低于 15%、内存空闲大于 70% 的非核心承载节点列入退役清退名单。最终锁定 10 台高配云主机8C16G单台月费约 1200 元作为首期绞杀目标。核心战术一打破盲目微服务冷门应用回归单体在小厂微服务拆得过细是导致服务器成本暴增的罪魁祸首。每个微服务都要有一套独立的进程开销、运行时 GC 开销、日志采集 Daemon、链路追踪探针。一个最简单的 Go 基础进程常驻就要吃掉 60MB 内存如果用 Java SpringBoot 那更是起步 800MB。我们将 6 个冷门的内部管理、定时对账微服务代码重新打包合并为一个“综合内部运营服务”。得益于 Go 1.27.1 对小对象内存分配的改良小于 80 字节对象分配开销降低 30%以及优秀的并发机制合并后的单个单体进程常驻内存仅有 180MB并发吞吐反而比原来跨网络 RPC 调用提升了 3 倍。核心战术二容器精准混部与 Request/Limit 水位下调原来各个虚机上的应用各占山头我们利用现有的 Kubernetes 主力集群推行容器混部真实用量对齐 Request利用监控回溯将原本动辄申请cpu: 2000m, memory: 4Gi的非核心 Pod压实到cpu: 200m, memory: 512Mi。节点超卖与 QoS 调度设置合理的 Limit 上限并通过BestEffort与Burstable级别进行服务分级混部。让白天的用户下单服务与夜间的报表计算服务错峰使用同一批宿主机算力。为了在缩容混部后防止突发任务打崩节点我们用 Go 编写了一个极轻量的轻度混部看门狗服务挂在宿主机上实时监测内核 cgroup 状态并自动做低优任务的流控package cgroupwatch import ( context fmt os strconv strings syscall time ) // NodeHealthWatcher 监控本地节点 cgroup 内存压力防止多服务混部导致 OOM 连锁反应 type NodeHealthWatcher struct { memPressureThreshold float64 // 内存压力告警水位 lowPriorityPIDs []int // 低优先级后台任务 PID 列表 } func NewNodeHealthWatcher(threshold float64) *NodeHealthWatcher { return NodeHealthWatcher{ memPressureThreshold: threshold, lowPriorityPIDs: make([]int, 0), } } // RegisterLowPriorityJob 注册可以随时挂起或降级的离线批处理任务 func (w *NodeHealthWatcher) RegisterLowPriorityJob(pid int) { w.lowPriorityPIDs append(w.lowPriorityPIDs, pid) } // MonitorLoop 周期性检测宿主机内存压力 func (w *NodeHealthWatcher) MonitorLoop(ctx context.Context) { ticker : time.NewTicker(3 * time.Second) defer ticker.Stop() for { select { case -ctx.Done(): return case -ticker.C: ratio, err : w.calculateHostMemUsage() if err ! nil { continue } // 如果宿主机真实内存水位超过 85%立刻向混部的低优离线任务发 SIGSTOP 暂停执行优先保在线交易 if ratio w.memPressureThreshold { w.pauseLowPriorityJobs() } else if ratio (w.memPressureThreshold - 0.15) { w.resumeLowPriorityJobs() } } } } func (w *NodeHealthWatcher) calculateHostMemUsage() (float64, error) { data, err : os.ReadFile(/proc/meminfo) if err ! nil { return 0, err } var memTotal, memAvailable float64 lines : strings.Split(string(data), \n) for _, line : range lines { fields : strings.Fields(line) if len(fields) 2 { continue } if fields[0] MemTotal: { memTotal, _ strconv.ParseFloat(fields[1], 64) } else if fields[0] MemAvailable: { memAvailable, _ strconv.ParseFloat(fields[1], 64) } } if memTotal 0 { return 0, fmt.Errorf(invalid meminfo) } return (memTotal - memAvailable) / memTotal, nil } func (w *NodeHealthWatcher) pauseLowPriorityJobs() { for _, pid : range w.lowPriorityPIDs { // 发送 SIGSTOP 临时挂起进程不占 CPU让出主干通道 _ syscall.Kill(pid, syscall.SIGSTOP) } } func (w *NodeHealthWatcher) resumeLowPriorityJobs() { for _, pid : range w.lowPriorityPIDs { // 发送 SIGCONT 恢复任务继续计算 _ syscall.Kill(pid, syscall.SIGCONT) } }缩容实施与退役复盘实打实的降本账单我们按照“灰度切流 - 隔离观察 7 天 - 停机保留快照 3 天 - 彻底退订销毁”的标准流程将这 10 台闲置云主机上的业务无缝迁移至现有 Kubernetes 集群中。降本成效收益清单直接资金节省退订 10 台 8C16G 高配虚机每台月单价 1200 元每个月实打实节省 12,000 元全年折合节约 14.4 万元。集群整体利用率提升主力 Kubernetes 节点的 CPU 月均利用率从原来的 11% 提升到了稳健的 42%内存利用率从 24% 提升到 58%依然保有充裕的安全应急冗余。运维人效大幅提升减少了 10 台虚机的系统补丁更新、日志采集探针维护和漏洞扫描工单团队整体的维护精力更加集中。在小厂过日子技术人员最大的价值绝不是堆砌华而不实的新词汇而是能用硬核的工程手段把每一分算力榨出最大价值。1.2 万元在巨头眼里可能连一天的零头都算不上但对于一个自负盈亏的小团队这笔钱足够覆盖两个初级实习生的一年薪资或者给兄弟们大促后发一份实打实的奖金。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑