如何计算 Azure Subscription 中每个 Service Bus Namespace 的成本?
结论
这个公式可以用于内部成本分摊,但不是 Azure 官方提供的单个 Namespace 计费公式。
Service Bus Standard 的 base charge 按 Subscription 收取,Azure 不会自动将它归入某个具体的 Namespace。Cost Management API 会将这笔费用记录在 $system resource ID 下。因此,单个 Namespace 的“总成本”需要按自定义规则计算:
Namespace allocated cost
= Direct cost attributed to the Namespace
+ Allocated share of the $system base charge
如果所有 Standard Namespace 在整个账期内始终存在,并且希望采用简单的平均分摊方式,可以使用以下公式:
Allocated base charge
= $system base charge / Number of Standard Namespaces
这只是一种管理会计规则。如果各 Namespace 的创建、删除或 tier 变更时间不同,直接按数量平均分摊并不准确,更适合按 Standard namespace-hours 分摊。
为什么无法直接取得单个 Namespace 的完整成本
Cost Management 中有两类相关费用:
- 可以关联到具体 Namespace 的费用,例如部分 operations costs,会记录在实际 Namespace 的 resource ID 下。
- 无法关联到具体资源的 Subscription 级 base charge,会记录在:
/subscriptions/<subscription-id>/resourceGroups/$system/providers/Microsoft.ServiceBus/namespaces/$system
因此,按真实 Namespace 的 resource ID 查询时,只能得到直接归属于该 Namespace 的费用。$system 下的费用不是某个隐藏 Namespace 的实际用量,也不能全部计入任意一个 Namespace。
Basic Namespace 不会产生 Standard base charge,因此不应计入 Standard Namespace 的数量或使用时长。
推荐的分摊方法
情况一:所有 Standard Namespace 全月有效
如果账期内共有 N 个 Standard Namespace,并且它们在整个账期内都保持 Standard tier,可以平均分摊:
AllocatedBaseCost_i = SystemBaseCost / N
TotalCost_i = DirectCost_i + AllocatedBaseCost_i
例如,$system 下确认属于 Service Bus Standard base charge 的费用是 $10,账期内有 4 个全月有效的 Standard Namespace:
AllocatedBaseCost = $10 / 4 = $2.50
如果其中一个 Namespace 的直接 operations cost 是 $6.20,其内部核算成本为:
TotalCost = $6.20 + $2.50 = $8.70
情况二:Namespace 只在部分账期内为 Standard
这种情况应按各 Namespace 处于 Standard tier 的有效小时数分摊:
AllocatedBaseCost_i
= SystemBaseCost
× StandardNamespaceHours_i
/ Sum(StandardNamespaceHours)
再计算:
TotalCost_i = DirectCost_i + AllocatedBaseCost_i
例如:
namespace-a: 720 Standard namespace-hours
namespace-b: 360 Standard namespace-hours
SystemBaseCost: $10
分摊结果为:
namespace-a = $10 × 720 / 1080 = $6.67
namespace-b = $10 × 360 / 1080 = $3.33
这种方法可以处理月中创建、删除和 tier 变更等情况。
计算步骤
- 使用 Cost Management Query API 查询完整 Billing Period,不要只查询单个 Namespace。
- 按
ResourceId、Meter、ChargeType等可用维度汇总费用。 - 提取每个实际 Namespace 的直接费用。
- 从
$systemresource ID 的记录中筛选 Service Bus Standard base charge。 - 确定账期内每个 Namespace 处于 Standard tier 的有效时间。
- 按选定的规则分摊
$system费用。 - 将分摊费用与各 Namespace 的直接费用相加。
- 检查所有 Namespace 的分摊金额之和是否等于原始
$systembase charge。
不能直接把 $system resource ID 下的所有费用都用于 Service Bus 分摊。$system 还可能包含其他无法关联到具体资源的 Subscription 级费用,需要结合 ServiceName、MeterCategory、MeterName、Product 等实际返回字段进行筛选。
Python 计算示例
下面的示例假设已经从 Cost Management API 中整理出各 Namespace 的直接费用和 Standard 有效小时数,也已确认 $system 中属于 Service Bus Standard base charge 的费用:
from decimal import Decimal
system_base_cost = Decimal("10.00")
namespaces = {
"namespace-a": {
"direct_cost": Decimal("6.20"),
"standard_hours": Decimal("720"),
},
"namespace-b": {
"direct_cost": Decimal("1.80"),
"standard_hours": Decimal("360"),
},
}
total_standard_hours = sum(
item["standard_hours"] for item in namespaces.values()
)
result = {}
for namespace, item in namespaces.items():
if total_standard_hours == 0:
allocated_base_cost = Decimal("0")
else:
allocated_base_cost = (
system_base_cost
* item["standard_hours"]
/ total_standard_hours
)
result[namespace] = {
"direct_cost": item["direct_cost"],
"allocated_base_cost": allocated_base_cost,
"total_cost": item["direct_cost"] + allocated_base_cost,
}
for namespace, costs in result.items():
print(
namespace,
{
key: str(value.quantize(Decimal("0.01")))
for key, value in costs.items()
},
)
输出结果类似:
namespace-a {'direct_cost': '6.20', 'allocated_base_cost': '6.67', 'total_cost': '12.87'}
namespace-b {'direct_cost': '1.80', 'allocated_base_cost': '3.33', 'total_cost': '5.13'}
实际计算时应保留完整精度,只在展示结果时四舍五入。否则,各 Namespace 的分摊金额之和可能与 $system 总额相差几分钱。
注意事项
- 只有当所有 Standard Namespace 的生命周期相同时,才适合平均分摊。其他情况应按 Standard 有效小时数分摊。
- 也可以按 operations 数量、业务流量或成本中心权重分摊,但这些都属于内部核算策略,不会改变 Azure 账单。
- operations 的免费额度和阶梯价格可能在 Subscription 或计费范围内统一应用,不能分别对每个 Namespace 套用定价表后再相加。账单对账应以 Cost Management 返回的实际费用为基础。
- 所有数据应采用相同的 Billing Period、币种和成本口径。例如统一使用
ActualCost,不要混用ActualCost、AmortizedCost或不同日期范围的数据。 - 月中创建、删除、暂停使用或从 Basic 切换到 Standard,都要计入有效小时数。
- Basic Namespace 只统计直接归属费用,不参与 Standard base charge 的分摊。
- 分摊完成后应满足:
Sum(AllocatedBaseCost_i) = SystemBaseCost
因此,问题中的公式只有在“所有 Standard Namespace 全月有效,并采用平均分摊策略”这一前提下才成立。若要更准确地核算单个 Namespace,应将分母从 Namespace 数量改为所有 Standard Namespace 的累计有效小时数。
备注:内容仅供参考。