服务器资源别只会加不会减:用 Python 搭建自动化闲置资源检测与回收系统
作者:Echo_Wish
做运维时间长了,应该都有过这样的经历:
某个项目上线,申请了 10 台服务器。业务高峰过去了,项目也逐渐稳定,原来申请的服务器却一直留在那里。
开发环境的虚拟机,几个月没人登录;测试环境的数据库,早就没有业务访问了;Kubernetes 集群里,一些 Deployment 副本还在运行,但实际流量早就归零;云平台上挂着一堆没人使用的云盘、弹性 IP 和快照。
这些资源每天都在产生费用,有些甚至还占着宝贵的计算和存储容量。
更有意思的是,当业务部门再次申请资源时,大家第一反应往往还是:资源不够了,再买一点。
这就形成了一个很尴尬的局面:
一边是资源闲置,一边是资源不足;一边在花钱扩容,一边却没人知道哪些资源可以回收。
我一直觉得,资源管理不能只关注资源申请和分配,还应该关注资源生命周期的最后一个环节:什么时候该释放。
今天就聊聊,如何用 Python 设计一套自动化资源闲置检测与回收系统,让资源管理从被动盘点变成主动治理。
一、资源闲置,不是看 CPU 为零就能判断
设计系统之前,首先要解决一个问题:
什么样的资源才算闲置?
很多人第一反应就是看 CPU 使用率。
比如,一台服务器连续 7 天 CPU 使用率低于 5%,那是不是就可以认定它闲置了?
还真不一定。
假设有一台数据库服务器,平时 CPU 使用率只有 2%,但每天凌晨都会执行一次重要的数据同步任务。
如果仅仅因为 CPU 使用率低,就把服务器回收了,可能第二天早上业务人员就会找上门来。
再比如:
- 开发环境服务器:可能连续几天没有访问,但项目还在开发。
- 备份服务器:平时 CPU 很低,但每天定时执行备份。
- 负载均衡器:CPU 使用率不高,但仍然承担着业务流量。
- Kubernetes 节点:当前负载不高,但可能是为了应对突发流量而预留的容量。
所以,我认为资源闲置检测不能只依赖单一指标,而应该综合判断。
可以从以下几个维度进行分析:
| 检测维度 | 判断依据 | 作用 |
|---|---|---|
| CPU 使用率 | 近 7~30 天平均值 | 判断计算资源是否被使用 |
| 内存使用率 | 长期平均及峰值 | 判断内存资源是否过剩 |
| 网络流量 | 入站、出站流量 | 判断是否存在实际通信 |
| 磁盘 I/O | 读写次数及吞吐量 | 判断存储是否活跃 |
| 业务访问 | 请求量、连接数 | 判断是否承担业务 |
| 资源归属 | 项目、负责人、环境 | 判断是否允许回收 |
| 生命周期 | 创建时间、过期时间 | 判断资源是否需要续期 |
这里还有一个非常重要的设计原则:
检测到资源低负载,不等于资源可以回收。
系统应该区分三个概念:
- 低利用率:资源使用率比较低。
- 疑似闲置:多个指标长期满足闲置条件。
- 可回收:经过业务归属、保护策略和审批检查后,确认允许释放。
这三个状态千万不要混为一谈。
二、整体架构:先检测,再确认,最后回收
我不建议一上来就开发一个能够自动删除服务器的系统。
资源回收和普通的数据清理不一样,一旦判断错误,影响的可能是整个业务系统。
比较稳妥的方式是采用分阶段设计。
整个系统可以拆分成六个核心模块:
1. 资源采集模块
负责获取云服务器、虚拟机、云盘、弹性 IP、Kubernetes 工作负载等资源信息。
数据来源可以包括:
- Prometheus:采集 CPU、内存、网络等监控指标。
- 云厂商 API:获取云资源状态、创建时间和费用信息。
- Kubernetes API:获取 Pod、Deployment、PVC 等资源。
- CMDB:获取资源归属、负责人、环境和业务标签。
2. 闲置检测模块
根据不同资源类型配置不同的判断规则,识别疑似闲置资源。
3. 风险评估模块
检查资源是否属于生产环境,是否存在业务依赖,是否设置了禁止回收标签。
4. 通知与审批模块
向资源负责人发送通知,等待确认、续期或者申请回收。
5. 自动回收模块
审批通过后,调用云平台 API 或 Kubernetes API 执行回收。
6. 审计与报表模块
记录检测结果、审批记录、回收操作以及节省的资源成本。
整个流程可以理解为:
资源采集
|
v
指标分析
|
v
闲置规则检测
|
v
风险评估
|
+---- 不满足条件 ----> 保留资源
|
v
生成闲置资源清单
|
v
通知资源负责人
|
v
审批确认
|
+---- 不通过 --------> 继续保留
|
v
执行回收
|
v
记录审计日志
|
v
统计资源节省情况
这里最关键的是,检测和回收必须解耦。
检测模块只负责告诉我们哪些资源可能存在浪费,回收模块才负责执行实际操作。
这样即使检测规则出现问题,也不会直接导致资源被删除。
三、Python 实现:构建一个闲置资源检测引擎
接下来看看核心代码怎么写。
为了方便理解,我们先不绑定具体云厂商,假设已经通过 Prometheus 或云平台 API 获取到了资源监控数据。
每台服务器的数据结构大致如下:
resources = [ { "instance_id": "i-001", "name": "test-server-01", "environment": "test", "owner": "developer-a", "cpu_avg": 2.3, "memory_avg": 8.5, "network_avg": 12.5, "disk_io_avg": 0.2, "idle_days": 15, "protected": False }, { "instance_id": "i-002", "name": "prod-server-01", "environment": "prod", "owner": "ops-team", "cpu_avg": 1.5, "memory_avg": 12.0, "network_avg": 0.5, "disk_io_avg": 0.1, "idle_days": 20, "protected": True }]
这里需要注意,示例中的指标是为了演示检测逻辑而构造的,并不代表真实监控数据。
1. 定义闲置检测规则
我们先定义一组基础规则:
- CPU 平均使用率低于 5%。
- 内存平均使用率低于 15%。
- 网络平均流量低于设定阈值。
- 磁盘 I/O 长期处于低水平。
- 连续 7 天以上满足条件。
只有这些条件同时满足,才将资源标记为疑似闲置。
def detect_idle_resource(resource): if resource.get("protected"): return False if resource.get("environment") == "prod": return False conditions = [ resource["cpu_avg"] < 5, resource["memory_avg"] < 15, resource["network_avg"] < 20, resource["disk_io_avg"] < 1, resource["idle_days"] >= 7 ] return all(conditions)
这个实现比较简单,但已经体现了一个重要思想:
不要只看 CPU,而是综合多个维度判断。
另外,生产环境这里直接排除了,只是一个保守的演示策略。真实场景中,生产资源应该进入更严格的专用评估流程,而不是简单套用测试环境规则。
2. 批量扫描闲置资源
有了检测函数,就可以对资源列表进行批量扫描。
def scan_resources(resources): idle_resources = [] for resource in resources: if detect_idle_resource(resource): idle_resources.append({ "instance_id": resource["instance_id"], "name": resource["name"], "owner": resource["owner"], "idle_days": resource["idle_days"], "status": "PENDING_REVIEW" }) return idle_resourcesidle_list = scan_resources(resources)for item in idle_list: print(item)
执行之后,系统就可以得到一份疑似闲置资源清单。
这里我特意使用了 PENDING_REVIEW 状态,而不是直接标记为 READY_TO_DELETE。
为什么?
因为资源检测只是技术判断,是否回收还需要结合业务实际情况。
比如某个测试环境服务器虽然 15 天没有使用,但开发人员可能下周就要进行版本回归。
如果系统直接删除,反而会给团队制造麻烦。
四、风险评估:不要让自动化变成自动闯祸
资源回收系统最重要的不是检测有多准确,而是回收过程是否足够安全。
我认为至少应该加入以下几种保护机制。
第一,生产资源默认禁止自动回收。
生产环境资源即使连续一个月没有明显负载,也应该进入人工审批流程。
尤其是数据库、核心业务服务、消息队列等关键组件,不能仅凭监控指标判断是否闲置。
第二,支持资源保护标签。
例如:
resource = { "instance_id": "i-001", "tags": { "Environment": "test", "Owner": "developer-a", "AutoRecycle": "true", "ExpireDate": "2026-11-30" }}
可以通过标签控制资源回收权限。
例如:
AutoRecycle=true:允许进入自动回收评估。AutoRecycle=false:禁止自动回收。Protected=true:永久保护,除非人工解除。Owner=xxx:指定资源负责人。
第三,回收前必须二次检查。
这点非常重要。
假设系统昨天检测到一台服务器闲置,今天已经进入回收审批流程。
但就在今天上午,开发人员重新启动了业务服务。
如果系统仍然按照昨天的检测结果执行删除,显然是不合理的。
所以,真正执行回收之前,必须重新获取资源状态,再次判断是否满足回收条件。
可以设计一个简单的检查函数:
def can_recycle(resource): if resource.get("protected"): return False, "资源处于保护状态" if resource.get("environment") == "prod": return False, "生产环境禁止自动回收" if resource.get("status") != "APPROVED": return False, "资源尚未审批通过" if resource.get("idle_days", 0) < 7: return False, "闲置时间不足" return True, "允许进入回收流程"
实际生产环境中,还应该检查资源版本、当前运行状态、业务依赖关系以及审批是否过期。
第四,支持回收冷静期。
例如,检测到资源闲置后,先通知负责人,给予 3~7 天确认时间。
在这个时间段内,负责人可以选择:
- 立即回收。
- 延长使用期限。
- 标记为长期保留。
- 提交特殊用途说明。
我个人比较喜欢这种方式。
因为它既能让自动化系统发挥作用,又不会把资源管理变成一场谁都不敢碰的冒险。
五、真正执行回收:先从云服务器开始
前面解决了资源识别和风险判断,接下来就是执行回收。
不同云平台的 API 不一样,这里以 Python 调用云资源管理接口的方式演示。
假设我们已经封装好了云平台客户端:
def recycle_instance(client, instance_id): try: # 再次检查资源状态 instance = client.describe_instance(instance_id) if instance is None: return False, "资源不存在" if instance.get("protected"): return False, "资源受到保护" if instance.get("status") != "STOPPED": return False, "资源未处于允许回收的状态" # 执行释放操作 client.release_instance(instance_id) return True, "资源回收请求已提交" except Exception as e: return False, f"回收失败:{str(e)}"
这里的 client 是需要根据实际云平台封装的客户端,并不是所有云平台都支持相同的接口。
还有一点必须强调:
停止服务器和释放服务器不是一回事。
停止实例通常只是停止计算资源运行,云盘、固定公网 IP 等资源可能仍然产生费用。
真正的资源回收应该考虑整个资源关联关系:
- 云服务器实例。
- 云盘及快照。
- 弹性公网 IP。
- 负载均衡监听器。
- 安全组及相关配置。
- 其他关联资源。
但也不能简单地把所有关联资源一起删除。
例如,云盘可能保存着需要长期保留的数据,弹性 IP 也可能已经被其他系统依赖。
所以回收流程应该先分析依赖关系,再按照明确的资源释放策略执行。
另外,建议为每次回收生成唯一任务 ID,记录执行状态。对于超时、重复提交等情况,采用幂等控制,避免同一资源被重复处理。
六、别忽略 Kubernetes:集群里的闲置资源也不少
如果说云服务器闲置比较容易发现,那么 Kubernetes 中的资源浪费往往更加隐蔽。
例如:
一个 Deployment 设置了 5 个副本,但实际业务流量长期很低。
某个测试 Namespace 已经几个月没有使用,但里面的 Pod、PVC、Service 仍然存在。
还有一些 Job 执行完成之后,没有及时清理历史资源。
这些都会占用集群容量。
可以先通过 Kubernetes Python Client 获取 Deployment 信息:
from kubernetes import client, configconfig.load_kube_config()apps_api = client.AppsV1Api()deployments = apps_api.list_deployment_for_all_namespaces()for deployment in deployments.items: namespace = deployment.metadata.namespace name = deployment.metadata.name replicas = deployment.spec.replicas or 0 available = deployment.status.available_replicas or 0 print({ "namespace": namespace, "name": name, "replicas": replicas, "available": available })
但这里有个容易踩坑的地方:
Deployment 副本数量和实际资源使用率并不是一回事。
副本数量为 5,不代表这 5 个副本都在浪费资源。
真正判断是否需要调整,还要结合:
- Pod CPU 和内存使用情况。
- HPA 自动伸缩策略。
- 业务请求量。
- 工作负载的重要程度。
- PDB(PodDisruptionBudget)配置。
- 是否存在定时任务和突发流量。
对于 Kubernetes,我更建议将资源治理拆成两类:
一类是资源回收,例如清理过期 Job、无人使用的测试 Namespace。
另一类是资源优化,例如调整 Deployment 的 requests 和 limits,或者通过 HPA 合理控制副本数量。
两者不要混为一谈。
尤其是 PVC 和 Namespace,必须有明确的归属关系和数据保留策略,不能因为长时间没有 Pod 就直接删除。
七、资源回收系统还应该算一笔账
做运维自动化,不能只关注执行了多少次任务。
如果一个系统每天检测 1000 台服务器,最后只回收了 2 台资源,那么它究竟创造了多少价值?
我认为资源治理至少应该关注三个指标:
1. 资源回收率
统计检测出的疑似闲置资源中,最终成功回收的比例。
2. 资源节省成本
统计释放资源前后的实际成本差异。
3. 误回收率
统计被回收后,因为判断错误而需要恢复的资源数量。
其中,我认为误回收率比回收数量更加重要。
因为资源回收本身是为了节约成本,如果因为一次错误回收导致业务故障,可能省下来的费用还不够支付事故成本。
我们可以设计一个简单的成本统计函数:
def calculate_saving(hourly_cost, hours): return round(hourly_cost * hours, 2)# 假设每小时资源成本为 0.8 元# 回收后统计 720 小时saving = calculate_saving(0.8, 720)print(f"预计节省成本:{saving} 元")
这里计算的是假设资源持续计费情况下的理论节省金额。
真实的节省金额还要考虑云平台计费规则、资源释放时间、云盘和公网 IP 等关联费用,以及是否存在最低计费周期。
如果能够把这些数据接入报表,就可以清晰地看到:
- 本月检测到多少闲置资源。
- 有多少资源通过审批。
- 实际回收了多少资源。
- 节省了多少计算和存储成本。
- 哪些部门长期存在资源闲置。
- 哪些资源被多次申请、闲置和回收。
这时候,资源治理就不再是运维部门单方面的工作,而是能够帮助企业进行成本管理的一项基础能力。
八、我的一些思考:资源管理真正难的不是回收,而是建立责任机制
写到这里,我想聊一个比代码更值得思考的问题。
为什么很多企业明明知道存在资源浪费,却一直没有真正解决?
我觉得很大一部分原因是资源申请和资源回收之间缺少责任闭环。
申请资源的时候,通常需要填写申请人、使用部门、资源规格和用途。
但是资源申请成功之后,可能就没人再关心它了。
项目结束了,服务器还在;测试完成了,云盘还在;人员离职了,原来申请的资源还在。
时间一长,资源就变成了没有人认领的公共资产。
所以,我认为一套真正有价值的资源闲置检测与回收系统,不能只是一套 Python 定时脚本。
它应该从资源创建时就建立生命周期管理机制。
比如:
资源申请时: 必须绑定负责人、项目、环境和预计使用期限。
资源使用时: 持续采集资源指标,分析实际利用率。
资源临近过期时: 自动提醒负责人确认是否续期。
资源长期闲置时: 自动进入风险评估和回收审批流程。
资源回收之后: 记录操作日志,统计成本节省情况。
这样才能形成完整闭环。
另外,我还有一个比较坚持的观点:
不要把资源回收率当成运维团队的唯一考核指标。
如果只考核回收数量,可能会导致运维人员为了完成指标而过度回收资源。
更合理的考核方式应该同时考虑资源利用率、实际成本节省、业务影响和误回收率。
自动化的目的不是为了让系统删除更多资源,而是让每一份资源都能被合理使用。
写在最后
过去我们做运维,更多关注的是服务器有没有宕机、磁盘有没有爆满、CPU 有没有跑满。
这些当然重要,但随着云资源和容器化环境越来越复杂,资源治理也应该成为运维体系中的重要一环。
一台服务器长期闲置,可能看起来只是几十块钱的事情。
但当企业拥有几百台、几千台服务器,以及大量云盘、容器和其他基础设施时,这些零散的浪费累积起来,就可能是一笔相当可观的成本。
我更希望未来的运维系统不仅能够告诉我们:
哪里出了问题?
还能够进一步告诉我们:
哪些资源没有被合理使用?哪些资源可以安全释放?哪些成本其实根本没有必要支出?
当然,自动化不是万能的。
检测规则可以不断优化,算法可以越来越智能,但涉及生产业务和重要数据的回收操作,始终应该保留必要的安全边界。
毕竟,省钱很重要,但不能为了省钱,把业务也一起省没了。
这才是资源自动化治理真正应该追求的目标。