ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AWS五大服务预留实例购买系统:从成本优化到自动化实践

AWS五大服务预留实例购买系统:从成本优化到自动化实践 很多人以为预留实例Reserved InstanceRI就是在 AWS 控制台上挑几个套餐点购买然后把账单折扣挂上去。但真正到了企业级环境事情远没有这么简单。尤其是当你的账号里同时跑着 EC2、RDS、Redshift、ElastiCache、OpenSearch 这五类服务财务要成本预测运维要资源保障开发又不断在改实例规格的时候靠人肉去控制台一个个买 RI几乎一定会买错、买漏或者买贵。我大概在两年前开始着手做这套“五大服务预留实例购买系统”目标很直接把 RI 从查询、筛选、决策到最终下单购买的完整链路自动化同时把成本归属和利用率追踪一并纳入。这套系统上线后RI 覆盖率从最初的 40% 出头稳定提升到 85% 以上每月的账单浪费明显下降。这篇文章就把整个实现过程拆开讲清楚包括核心 API 的调用逻辑、购买链路的状态机设计、以及那些文档里不会写的坑。如果你正在考虑做类似的内部 FinOps 工具或者只是想把 RI 购买这件事从“拍脑袋”变成“有依据”这篇文章应该能帮你节省大量试错时间。1. 先搞清楚 RI 的“游戏规则”它买的不是机器是一张折扣券这个话题必须放在最前面因为我在实际推进项目时发现团队里一半以上的争议都源于对 RI 本质的理解不一致。很多人一听到“预留实例”第一反应是“我预定了机器所以 AWS 会专门给我留出资源”。这是错的。RI 本质上是一张账单折扣券。你承诺在未来 1 年或 3 年内为特定规格的实例付费AWS 给你对应的折扣价仅此而已。它不会真的预留在某个可用区等着你启动实例也不保证你随时能拿到足够多的 vCPU。你该开机器还是正常开只是账单上的每小时单价变了。理解了这一点后面所有设计都能顺理成章地展开。因为你买的不是“资源”而是“账单抵扣资格”。所以系统真正要做的不是帮你去抢机器而是帮你算出“哪些正在运行的实例值得未来一年继续跑”然后按规格去买对应的抵扣券。1.1 五大服务的 RI 覆盖范围差异AWS 的 RI 并不是所有服务都支持至少在购买系统这个维度上目前最主要的五类服务是服务购买入口 API归属维度特殊说明EC2PurchaseReservedInstancesOffering可用区或区域级最灵活支持 Standard 和 ConvertibleRDSPurchaseReservedDBInstancesOffering可用区或区域级多 AZ 部署时按单实例扣减RedshiftPurchaseReservedNodeOffering区域级按节点类型购买固定规格ElastiCachePurchaseReservedCacheNodesOffering可用区或区域级只覆盖单节点无集群概念OpenSearchPurchaseReservedInstanceOffering区域级支持数据实例和 Ultrawarm按实例小时扣减从 API 命名就能看出来每个服务的 RI 购买入口是独立的参数也略有差异。但核心流程一致查询可购买报价Offering→ 筛选规格与条件 → 下单购买 → 等待状态变为 active。1.2 Standard 与 Convertible 的核心区别在 EC2 里面RI 还分 Standard 和 Convertible 两类。Standard RI 便宜但买定离手不能改规格Convertible RI 贵一点但可以在生命周期内修改实例族、操作系统、租期等属性。我做系统时的策略是按需属性较高的负载用 Convertible稳定的常驻服务用 Standard。比如核心数据库和长期运行的 API 服务跑三年基本不太会动Standard 最划算但如果是测试环境或者未来可能换代的业务Convertible 更稳妥。这个逻辑同样适用于 RDS 和 ElastiCache不过这两者的 Convertible 支持力度不如 EC2。记住一个关键点RI 的折扣是按“实例小时”维度计算的。比如你有一台m5.large的 EC2 在跑买了 1 个m5.large的 RI那么这台机器的每小时费用按折扣价计算你有两台的m5.large在跑但只买了 1 个 RI那么其中一台按全价计费。系统不可能替 AWS 决定哪台机器享受折扣所以你需要通过标签、实例 ID 去核对覆盖率。2. 系统整体架构设计别用“脚本”用“工单流”思维最开始我倾向于写一个 Python 脚本把查询和购买串起来跑一遍。但很快发现两个问题一是查询报价的接口特别慢动辄几十秒甚至几分钟二是购买 RI 是涉及资金承诺的操作如果脚本误触发财务部门会直接找你谈话。所以最终版本做成了带人工审批环节的自动化系统整体分四层数据采集层定时从 AWS 拉取各服务当前运行实例、已有 RI 清单、账户级容量信息。推荐计算层根据运行实例的规格、时长、利用率生成“该买什么、买多少”的推荐清单。审批执行层推荐清单生成后进入审批流审批通过后调用购买 API 下单。追踪校准层购买完成后持续监控 RI 利用率、覆盖率以及成本分摊明细。2.1 为什么必须要有“报价缓存”DescribeReservedInstancesOfferings这个 API 是查询可购买 RI 报价的核心接口。但它的响应非常慢尤其在多区域、多服务的场景下全量拉取可能分页多达几十页一页一页翻下来时间开销和 API 调用配额都很可观。我做了两层缓存内存缓存在同一个执行批次内同一个服务、同一个 region 的报价查询结果共享。Redis/数据库缓存把全量报价按实例类型、区域、期限、付款方式存下来设置 1 小时 TTL。因为 RI 报价本身不会频繁变化1 小时刷新完全够用。这个缓存层带来的收益非常明显。原本一次推荐计算需要 5 到 10 分钟拉数据现在基本 30 秒内完成因为大多数报价直接命中缓存。2.2 数据模型设计一张购买需求表打天下我用的数据模型不复杂但字段设计上花了一些心思CREATE TABLE ri_purchase_orders ( id BIGSERIAL PRIMARY KEY, service_type VARCHAR(20) NOT NULL, -- ec2/rds/redshift/elasticache/opensearch region VARCHAR(30) NOT NULL, instance_family VARCHAR(40) NOT NULL, -- m5.large, cache.m5.large 等 offering_id VARCHAR(128) NOT NULL, -- 选定的报价 ID duration_years INT NOT NULL, -- 1 或 3 payment_option VARCHAR(20) NOT NULL, -- All Upfront / Partial Upfront / No Upfront scope VARCHAR(20) NOT NULL, -- Region / Availability Zone count INT NOT NULL, status VARCHAR(20) DEFAULT pending, -- pending/approved/executing/purchased/failed/cancelled approval_note TEXT, created_at TIMESTAMP DEFAULT now(), executed_at TIMESTAMP, reserve_instances JSONB -- 购买结果详情 );这个表是整个系统的核心状态机容器。每次推荐计算产出的购买建议都先写入这张表然后等待审批。审批通过后执行模块读取对应记录调用各服务的购买 API并更新状态。所有购买操作都有迹可循出了问题也好回溯。2.3 最小权限设计别给 Mark 一个能买 RI 的 Root 账号这套系统在 IAM 权限上我踩过一次坑。早期图省事直接在管理员账号里跑脚本。后来为了收敛权限专门创建了独立的执行角色只授予以下权限ec2:DescribeReservedInstancesOfferingsec2:DescribeReservedInstancesec2:PurchaseReservedInstancesOfferingrds:DescribeReservedDBInstancesOfferingsrds:PurchaseReservedDBInstancesOfferingredshift:DescribeReservedNodeOfferingsredshift:PurchaseReservedNodeOfferingelasticache:DescribeReservedCacheNodesOfferingselasticache:PurchaseReservedCacheNodesOfferinges:DescribeReservedInstanceOfferingses:PurchaseReservedInstanceOffering注意Purchase类 API 属于高危操作建议在代码里单独封装一层审批逻辑不能和查询逻辑混在同一个函数里。我的做法是查询接口走只读角色购买接口走另外一台独立服务只有工单状态变为approved时才会调用。3. 查询模块的完整实现从“有哪些报价”到“哪些值得买”查询模块是整个系统里调用最频繁的部分也是所有推荐判断的依据。它要做的事有两件一是拉取所有可购买报价二是拉取当前已有的 RI 和运行中的实例做匹配计算。3.1 报价查询的 API 参数组合以 EC2 为例核心调用是describe_reserved_instances_offerings。这个 API 支持非常详细的筛选条件我实际使用的参数组合如下import boto3 ec2 boto3.client(ec2, region_nameus-east-1) response ec2.describe_reserved_instances_offerings( InstanceTypem5.large, OfferingClassstandard, # 或 convertible ProductDescriptionLinux/UNIX, OfferingTypeAll Upfront, # No Upfront / Partial Upfront Duration31536000, # 1 年31536000 秒3 年94608000 秒 ScopeRegion, # Region 或 Availability Zone MaxResults100, Filters[ {Name: instance-type, Values: [m5.large]}, {Name: scope, Values: [Region]}, ] )这里有个特别容易踩坑的点Duration的单位是秒不是月。1 年 315360003 年 94608000。很多人在写代码时下意识传了1或者12结果什么都查不到。ProductDescription也很有意思EC2 里常见的取值有Linux/UNIX、Red Hat Enterprise Linux、SUSE Linux等。如果你的实例跑的是 Windows记得用Windows相关描述否则推荐的 RI 完全无法匹配账单。3.2 各服务报价查询的差异对照五大服务的查询 API 结构基本相似但参数细节不太一样。我整理过一张对照表服务API 名称筛选维度主要差异点EC2DescribeReservedInstancesOfferingsInstanceType / Scope / OfferingClass支持 AZ 级规格粒度最细RDSDescribeReservedDBInstancesOfferingsDBInstanceClass / MultiAZ / Engine需要指定数据库引擎例如 mysql/postgresRedshiftDescribeReservedNodeOfferingsNodeType / OfferingClass只能按节点类型买Region 级ElastiCacheDescribeReservedCacheNodesOfferingsCacheNodeType / OfferingClass需要指定引擎redis/memcachedOpenSearchDescribeReservedInstanceOfferingsInstanceType / OfferingClass支持 UltraWarm 节点Region 级例如 RDS 的查询rds boto3.client(rds, region_nameus-east-1) response rds.describe_reserved_db_instances_offerings( DBInstanceClassdb.r5.large, Duration31536000, MultiAZTrue, OfferingTypeAll Upfront, ProductDescriptionpostgres, MaxResults100 )注意MultiAZ这个字段它不是一个可选筛选条件而是会影响价格本身。同样的db.r5.large单 AZ 和多 AZ 的 RI 价格完全不同。所以系统在推荐 RDS RI 时必须先去判断目标数据库实例是否开启了多 AZ 部署。3.3 推荐计算不止是“按需实例数减去已有 RI 数”简单做法是统计当前 EC2 按需实例数量减去已有 RI 数量差额就是需要购买的 RI 数量。这个逻辑在单实例规格、单账号的简单场景下够用但到大企业里根本跑不通原因有两点按需实例列表里包含很多随时可能终止的临时机器比如数据处理任务、CI 构建节点。如果把这些全部纳入 RI 覆盖会造成大量 RI 闲置。假设你有 20 台m5.large按需实例在跑其中 8 台是 24 小时常驻的生产服务12 台是白天启动晚上销毁的测试机器。无脑购买 20 个 RI晚上那 12 个 RI 就全部浪费了。EC2 的 RI 匹配规则是按“实例大小灵活度Size Flexible”的。一个m5.2xlarge的 RI可以抵扣两个m5.xlarge或四个m5.large的小时账单。如果只看单规格数量会低估或高估实际可覆盖率。我最终采用的推荐逻辑分三层常驻实例识别通过最近 30 天的 CloudWatch 监控数据筛选出 CPU 利用率长期大于 5% 且运行时长超过 70% 天的实例。规格归一化把所有常驻实例按 vCPU 和内存归一化成“基准单位”再映射到 RI 可抵扣的规格组合。购买优先级排序按“每单位折扣金额 × 预计运行时长”从高到低排序优先购买长期稳定且折扣力度最大的规格。3.4 已有 RI 的现状核对一个很容易被忽略的步骤在生成购买建议之前还有一个前置动作查询当前账号下已经生效的 RI。API 是describe_reserved_instances返回结果里有State字段取值可能是active、retired、payment-pending、pending。response ec2.describe_reserved_instances( Filters[ {Name: state, Values: [active, payment-pending]} ] ) for ri in response[ReservedInstances]: print(ri[InstanceType], ri[InstanceCount], ri[End])这里必须注意RI 的状态是active才代表当前正在抵扣账单。pending或者payment-pending状态不要计入“已有RI”里否则会重复购买。另外End字段能告诉你 RI 的到期时间这部分信息在生成“是否续费”判断时非常重要。很多团队只看数量不看到期时间结果 RI 过期了两周才发现那两周的账单全部按全价计费白白损失。4. 购买执行模块从“报价 ID”到“订单确认”的完整链路购买是整套系统里最敏感、最不可逆的操作。虽然 AWS 在特定时间内允许在控制台退订部分 RI但对 EC2 这种核心服务退订条件非常苛刻基本默认是不可撤销的资金承诺。所以购买执行模块我做了非常严格的状态控制和异常兜底。4.1 购买前的三重确认在真正调用PurchaseReservedInstancesOffering之前系统必须通过三重检查报价一致性检查确认当前调用的报价 ID 对应的规格、期限、付款方式与工单记录完全一致。余额覆盖检查查询当前账号的账单余额和安全组配额避免购买完成后出现付款失败事实上 AWS 是按小时抵扣账期所以这个检查更多是兜底防止账户被冻结。重复提交防护检查同一 Offering ID 是否已经在近 24 小时内有成功的购买记录。AWS 的购买 API 没有内建幂等机制重复调用会真的买两张券这个问题必须由应用层自行解决。4.2 EC2 购买代码示例import boto3 ec2 boto3.client(ec2, region_nameus-east-1) response ec2.purchase_reserved_instances_offering( ReservedInstancesOfferingIda1b2c3d4-5678-90ab-cdef-EXAMPLE11111, InstanceCount2, PurchaseDateNone # 可选一般不传 ) print(response[ReservedInstancesId])这个 API 返回的是ReservedInstancesId但拿到这个 ID 不意味着购买已经生效。ReservedInstancesOfferingId和ReservedInstancesId是两回事前者是报价标识后者是购买后的预留实例实例标识。从提交到真正可用中间会经历payment-pending→active的过程通常需要几十秒到几分钟不等。4.3 异步状态确认的正确姿势由于购买是异步的系统必须主动轮询确认订单结果。我采用的策略是import time def wait_ri_active(reserved_instance_id, region, timeout300): ec2 boto3.client(ec2, region_nameregion) elapsed 0 while elapsed timeout: resp ec2.describe_reserved_instances( ReservedInstancesIds[reserved_instance_id] ) state resp[ReservedInstances][0][State] if state active: return True elif state in (retired, failed): return False time.sleep(10) elapsed 10 return False这里有一个经验轮询间隔不要设置太短10 秒一次完全够用。因为 RI 状态变更本来就不频繁而且频繁调用describe_reserved_instances在高并发场景下容易触发 API 限流。如果一次购买多个 RI我更建议用批量查询的方式一次MaxResults拉回全部结果再做匹配。4.4 购买后的成本标签与归属标记纯买 RI 不够你还需要知道这些 RI 覆盖了哪些业务线、哪个成本中心。AWS 的 RI 本身不直接支持自定义标签但有一个变通方案RI 会归属于购买它的账号而如果做了组织级 RI 共享还可以在 Cost Explorer 里按标签维度拆分。我的做法是购买成功后自动打上三类标签finance:cost-centerteam:ownerpurchase:systemri-auto这些标签不会影响 RI 本身的折扣匹配但会在 Cost Explorer 和账单报表里帮助你把“RI 摊销成本”拆到具体业务方。没有这一层RI 的成本会全部挂在购买账号名下财务在做内部结算时根本分不清哪条业务线用了多少 RI 折扣。4.5 组织级共享 RI 的注意事项如果你所在的企业用的是 AWS Organizations并且希望让所有子账号共享 RI 折扣可以开启 RI 共享功能ec2:EnableReservedInstancesSharing。但这里有一个容易被忽略的细节RI 共享必须是整个组织层面的选择它会把所有子账号的 RI 池合并计算折扣。这听起来很好但一旦开启你无法单独指定“只共享给 A 账号、不给 B 账号”。所以我在实际系统里做了配套逻辑RI 购买账本保留在每个子账号但共享开关统一由主账号控制。同时为了追踪跨账号的 RI 使用情况我会定期从 Cost Explorer 拉取lineItem级别的数据按lineItem/ResourceId和reservation/ReservationARN做关联分析。这套机制能精准看到每张 RI 实际覆盖了哪台实例。5. 五大服务购买流程的差异化实现每个服务的购买流程主体一致但细节差异很大。处理不好这些差异轻则购买报错重则买了完全无法匹配的券。5.1 RDSMultiAZ 和数据库引擎是硬门槛RDS 的 RI 购买除了要指定DBInstanceClass之外还必须在MultiAZ和ProductDescription上做精确匹配。比如你有一个db.r5.large的单 AZ PostgreSQL 实例和一个db.r5.large的多 AZ PostgreSQL 实例两者的 RI 是不同的报价。系统里我强制要求工单字段必须包含engine和multi_az并在购买前用describe_reserved_db_instances_offerings二次校验。另外RDS 的 RI 购买 API 是PurchaseReservedDBInstancesOffering它跟 EC2 一样返回一个ReservedDBInstancesId状态变化同样需要轮询。5.2 Redshift只能按 NodeType 买不能按 Cluster 买Redshift 的 RI 逻辑比较特殊。它没有实例规格的灵活度你买一个dc2.large的 RI就只能抵扣dc2.large节点的账单。集群里如果用dc2.8xlarge底层有多个节点实际抵扣时是按“节点”维度来算的。我在设计 Redshift 模块时没有直接按集群数来买 RI而是先通过describe_clusters查看集群的NumberOfNodes和NodeType再按节点数推导需要购买的 RI 数量。redshift boto3.client(redshift, region_nameus-east-1) clusters redshift.describe_clusters()[Clusters] for cluster in clusters: node_type cluster[NodeType] node_count cluster[NumberOfNodes] print(fCluster {cluster[ClusterIdentifier]}: {node_type} x {node_count})然后拿着node_type去查报价offerings redshift.describe_reserved_node_offerings( NodeTypedc2.large, Duration31536000, OfferingTypeAll Upfront )注意 Redshift 的报价查询接口是describe_reserved_node_offerings返回值字段名和 EC2 完全不同做统一封装的时候一定要做字段映射别直接用 EC2 那套模型去套。5.3 ElastiCacheCacheNodeType 与 Engine 都要对齐ElastiCache 的 RI 相对简单它没有大小灵活度必须以节点类型对齐。我的做法是先列出所有 Cache 集群和节点组提取CacheNodeType再结合引擎类型Redis 或 Memcached去查询报价。有个小坑ElastiCache 的CacheNodeType字段是cache.r5.large这种带cache.前缀的写法和 EC2 的r5.large不一样。如果你在统一模块里直接复用 EC2 的实例规格字段很容易匹配不到报价。5.4 OpenSearch别忘了 UltraWarmOpenSearch 的 RI 推出时间比其他服务晚而且支持两种节点类型数据节点和 Ultrawarm 节点。Ultrawarm 是冷热分层架构中的热节点价格和配额都不同。查询报价时也需要指定节点类型es boto3.client(es, region_nameus-east-1) response es.describe_reserved_instance_offerings( ReservedInstanceOfferingTypeALL, # 是 DATA 还是 ALL MaxResults100 )然后购买response es.purchase_reserved_instance_offering( ReservedInstanceOfferingId..., InstanceCount1 )这里需要特别注意OpenSearch 的 RI 是按实例小时计费的并且没有大小灵活度。我的经验是优先对数据节点买 RI因为数据节点是常驻的Ultrawarm 节点通常作为弹性扩展存在买 RI 容易过量。5.5 统一购买调度逻辑虽然每个服务的 API 不同但我在实现时把它们抽象成了统一接口def purchase(service, offering_id, count, region): if service ec2: client boto3.client(ec2, region_nameregion) response client.purchase_reserved_instances_offering( ReservedInstancesOfferingIdoffering_id, InstanceCountcount) elif service rds: client boto3.client(rds, region_nameregion) response client.purchase_reserved_db_instances_offering( ReservedDBInstancesOfferingIdoffering_id, DBInstanceCountcount) elif service redshift: client boto3.client(redshift, region_nameregion) response client.purchase_reserved_node_offering( ReservedNodeOfferingIdoffering_id, NodeCountcount) elif service elasticache: client boto3.client(elasticache, region_nameregion) response client.purchase_reserved_cache_nodes_offering( ReservedCacheNodesOfferingIdoffering_id, CacheNodeCountcount) elif service opensearch: client boto3.client(es, region_nameregion) response client.purchase_reserved_instance_offering( ReservedInstanceOfferingIdoffering_id, InstanceCountcount) return response字段映射和调用参数虽然不一样但整体控制流是统一的这为后面的工单审批、重试机制和日志追踪省了很多功夫。6. 避坑实录我在这套系统上踩过的五个典型问题这里列几个我在开发过程中遇到并解决的实际问题基本都是文档不会细说、但生产环境一定会碰上那种。6.1 报价 ID 的有效期比想象中短RI 报价 ID 是有时效性的。同一个规格、同一个期限、同一个付款方式的报价可能今天有效明天就换了一个新的 IDAWS 内部可能会调整折扣率或生成新批次。所以系统必须做到先查报价、拿 ID、立即购买中间不要停顿太久。如果用户在审批流里卡了两天审批完成后系统再拿旧的报价 ID 去下单很可能直接报InvalidReservedInstancesOfferingId。我最终的方案是工单审批通过后执行模块不会直接用数据库里存的offering_id而是重新查询一次最新报价然后自动匹配最优折扣的那个 ID。如果匹配不到完全一致的条件工单自动置为failed并触发告警。6.2 付款方式字段名的“同义词陷阱”五大服务在描述付款方式时用了不同的字段值。EC2 叫OfferingType取值是All Upfront、Partial Upfront、No UpfrontRDS 和 ElastiCache 也类似但 Redshift 的字段叫OfferingTypeOpenSearch 是PaymentOption。表面上看起来差不多但字符串匹配时必须精确空格和大小写都不能错。更坑的是Feasibility 接口返回的数据里某些平台的OfferingType可能是Heavy Utilization这种老式叫法。如果你在做跨服务统一封装建议建一张映射表统一字段EC2RedshiftOpenSearch全预付All UpfrontAll UpfrontALL_UPFRONT部分预付Partial UpfrontPartial UpfrontPARTIAL_UPFRONT无预付No UpfrontNo UpfrontNO_UPFRONT不然你的通用解析逻辑会在某个冷门节点的兼容性测试里崩掉。6.3 查询报价时的区服隔离不同 region 的 RI 报价和折扣是彼此独立的。你在us-east-1买的 RI 不能覆盖ap-southeast-1的实例账单。所以系统里所有查询和购买调用都必须带region_name参数并且购买前还要从工单记录里再核对一次 region防止配置错位。为了管理多区域我在系统里维护了一个regions.yaml配置文件regions: - us-east-1 - us-west-2 - ap-southeast-1 - eu-central-1然后所有扫描任务都按区域列表并发执行同时用ThreadPoolExecutor控制并发上限为 4避免触发 API 限流。6.4 5 个服务共用一个执行线程池导致的配额竞争最初我把五个服务的扫描任务全丢在同一个线程池里跑结果经常出现 EC2 调用量飙升把 Redshift 的查询请求挤到限流的情况。后来做了按服务划分的独立线程池每个服务最多 2 个并发且每个服务单独设置 API 调用重试和退避。这里有一个关于 boto3 的细节默认的botocore配置里重试次数是 3 次max_attempts也可以通过 Config 调整。但在高并发场景下我倾向不盲目调高重试次数因为 API 配额是共享的每次重试都在消耗配额反而会拉长整体执行时间。更合理的方式是把任务切小多批次调度。6.5 跨账号执行时角色切换的坑如果你的 RI 管理系统跑在中心账号但需要操作各个子账号的 RI必须用到sts:assume_role。这时候环境变量里的AWS_PROFILE和region混用会导致非常诡异的报错尤其在boto3.Session里手动指定region_name时角色切换后的临时凭证可能没有你指定区域的所有权限。我的做法是统一封装一个get_client(service, region, account_id)函数import boto3 def get_client(service, region, account_id, role_nameOrganizationAccountAccessRole): sts boto3.client(sts, region_nameregion) role_arn farn:aws:iam::{account_id}:role/{role_name} assumed sts.assume_role(RoleArnrole_arn, RoleSessionNameRI-Manager) creds assumed[Credentials] return boto3.client( service, region_nameregion, aws_access_key_idcreds[AccessKeyId], aws_secret_access_keycreds[SecretAccessKey], aws_session_tokencreds[SessionToken] )这个函数承担了所有跨账号操作的入口职责。权限验证、日志打印、审计都从这里走不要在每个业务模块里到处裸建 client。7. 成本优化效果与后续扩展方向系统上线三个月后我在内部 FinOps 月会上拉了一版数据总体 RI 覆盖率从 40% 出头提升到 85% 左右每月按需账单费用下降约 20%。这个成绩主要不是因为系统“买得多”而是因为推荐逻辑更精准不再盲目覆盖所有运行实例而是重点买那些真正 24 小时跑着的常驻负载。更关键的是由于系统留下了完整的购买记录和标签财务那边终于能做到按业务线拆分 RI 成本了。之前每季度做账单分析时他们都要花三四天手动拉数据现在直接在内部 BI 工具里按标签分组即可。如果你想在现有基础上继续扩展我建议接下来做两件事一是自动续费提醒。根据describe_reserved_instances返回的End时间在 RI 到期前 30 天、14 天、7 天分别发通知避免因过度聚焦新购而遗漏续费导致折扣中断。二是RI 利用率异常告警。通过 Cost Explorer 的reservation维度数据实时监控每个 RI 的利用率。如果某张 RI 连续 7 天利用率低于 50%系统自动告警推动运维团队调整实例规格或切换 Convertible RI。对我来说做这套系统最大的收获不是省了多少钱而是把“买 RI”这件事从拍脑袋变成了可追溯、可审计、可持续优化的内部流程。如果你也在企业里做 FinOps 或平台工程相信我这套系统值得投入。
返回列表