2. 云账单数据解剖

做云成本分摊与Showback,第一步不是写分摊规则,而是把账单“读对”。三大公有云的原始账单在结构、粒度、字段命名和交付方式上差异很大:AWS CUR 是列式明细、Azure Cost Details 是行式明细、GCP Billing Export 是带标签的宽表。如果对字段含义理解偏差,后续按标签、按项目、按资源的分摊结果就会整体失真。本节先建立“账单解剖”的统一视角,再逐家拆解关键字段与常见数据质量问题。

一、先建立统一视角:账单的四个维度

无论哪家云,账单明细都可以用四个维度来定位一条记录:时间维度(计费周期、使用起止时间)、资源维度(资源ID、资源类型、区域)、归属维度(账号、订阅、项目、标签)、金额维度(用量、单价、费用、币种、抵扣)。分摊工程真正依赖的是“归属维度”和“金额维度”的交叉:只有把每条费用准确挂到某个成本中心或业务单元,Showback 才有意义。

需要特别区分三类金额:List Cost(标价)、Effective Cost(实际成本)、Amortized Cost(摊销成本)。标价是未打折的目录价;实际成本是扣除折扣、优惠券、私有定价后的应付金额;摊销成本则把一次性预付(如 Reserved Instance、Savings Plan、CUD)按使用周期摊到每一天。做内部 Showback 时,通常应使用摊销成本,否则会出现“买预留的月份成本暴涨、后续月份成本为零”的失真现象。

三大云账单明细结构对照与字段映射 AWS CUR(列式明细) 交付:S3 + Athena / Data Exports 粒度:按小时 / 按资源 lineItem/UsageStartDate lineItem/UnblendedCost lineItem/ResourceId product/ProductName resourceTags/user:CostCenter reservation/EffectiveCost savingsPlan/SavingsPlanEffectiveCost 常见问题 • 标签缺失 → 归入“未分配” • 同一资源跨小时产生多行 • 抵扣行与使用行需配对 • 币种混用需统一换算 Azure Cost Details(行式明细) 交付:Storage 导出 / Cost Management API 粒度:按天 / 按计量 Date / BillingPeriodStartDate CostInBillingCurrency ResourceId / ResourceType MeterCategory / MeterName Tags(JSON 字符串) PricingModel(OnDemand/Reservation) BenefitId / BenefitName 常见问题 • Tags 为 JSON,需解析展开 • 大小写不一致导致标签分裂 • 预留与按需行需合并摊销 • 导出延迟约 4–24 小时 GCP Billing Export(宽表) 交付:BigQuery 数据集 粒度:按天 / 按 SKU usage_start_time / usage_end_time cost / currency project.id / resource.name service.description / sku.description labels(数组结构) credits(抵扣明细) cost_type(regular/tax/adjustment) 常见问题 • labels 为数组,需 UNNEST • credits 需从 cost 中扣除 • 项目迁移导致归属漂移 • 导出表按天分区,注意时区

二、AWS CUR:列式明细与摊销成本

AWS 的 Cost and Usage Report(CUR)以 Parquet 或 CSV 形式投递到 S3,通常配合 Athena 或 Data Exports 查询。它的核心特征是“一行一计量”,同一资源在同一小时内可能产生多行:使用行、抵扣行、税费行、退款行。关键字段包括 lineItem/UsageStartDate、lineItem/UnblendedCost、lineItem/ResourceId、product/ProductName,以及标签列 resourceTags/user:CostCenter。

做摊销时,不能直接用 UnblendedCost。正确做法是:对按需资源取 lineItem/UnblendedCost;对 RI 覆盖的资源取 reservation/EffectiveCost;对 Savings Plan 覆盖的资源取 savingsPlan/SavingsPlanEffectiveCost。这三者相加才是该资源当天的真实摊销成本。示例:某 EC2 实例当天按需部分 12.00 美元,RI 覆盖部分 EffectiveCost 为 8.50 美元,则摊销成本为 20.50 美元,而不是按需账单上显示的 12.00 美元。

三、Azure Cost Details:行式明细与标签解析

Azure 的 Cost Details 通过 Cost Management 导出到 Storage Account,字段以行式组织,一行代表某天某计量的一次费用。核心字段有 Date、CostInBillingCurrency、ResourceId、MeterCategory、Tags、PricingModel。其中 Tags 是 JSON 字符串,例如 {"CostCenter":"CC-1024","Env":"Prod"},在入库前必须解析展开,否则无法按标签聚合。

Azure 的常见坑是标签大小写不一致:CostCenter 与 costcenter 会被视为两个不同标签,导致同一成本中心被拆成两行。建议在 ETL 阶段统一转为小写并做映射表。另外,PricingModel 为 Reservation 的行需要与按需行合并,按实际使用量做摊销,否则预留购买当月会出现成本尖峰。

四、GCP Billing Export:BigQuery 宽表与抵扣处理

GCP 的 Billing Export 直接写入 BigQuery 数据集,表按天分区,字段是嵌套结构。核心字段包括 usage_start_time、cost、currency、project.id、service.description、sku.description、labels、credits、cost_type。其中 labels 是数组,需要用 UNNEST 展开;credits 是抵扣明细数组,必须从 cost 中扣除才是净成本。

一个典型查询片段如下,用于按成本中心汇总净成本:

SELECT
  l.value AS cost_center,
  SUM(b.cost) + SUM(IFNULL(c.amount, 0)) AS net_cost
FROM `project.billing.gcp_billing_export_v1_XXXX` b
LEFT JOIN UNNEST(b.labels) AS l
  ON l.key = 'cost_center'
LEFT JOIN UNNEST(b.credits) AS c
  ON TRUE
WHERE b.usage_start_time >= '2024-06-01'
GROUP BY cost_center;

注意 credits.amount 通常为负值,直接相加即可完成抵扣。若忽略 credits,GCP 成本会被系统性高估。

五、跨云数据质量检查清单

在把三家账单接入分摊引擎前,建议先跑一遍数据质量检查。以下清单可直接作为 ETL 验收项:

检查项AWS CURAzure Cost DetailsGCP Billing Export
时间字段是否完整UsageStartDate 非空Date 非空usage_start_time 非空
金额字段是否可加总UnblendedCost + EffectiveCostCostInBillingCurrencycost + credits.amount
标签是否可解析resourceTags 列存在Tags JSON 可解析labels 可 UNNEST
未分配占比< 5% 为健康< 5% 为健康< 5% 为健康
币种是否统一检查 currency 列BillingCurrencycurrency
抵扣是否已扣除RI/SP 行已合并BenefitId 已处理credits 已 JOIN
建议在分摊引擎入口处设置“未分配成本”看板:每天统计无标签、标签为空或标签值不在成本中心字典中的费用占比。该比例超过 5% 时,先治理标签,再谈分摊精度。
不要混用标价与实际成本做 Showback。若用 List Cost 展示,业务方会看到远高于实际账单的数字;若用 UnblendedCost 而不做摊销,预留购买月会出现异常尖峰。统一使用摊销成本是跨云一致性的前提。