PAYATHON 2026

如何计算 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 变更等情况。

计算步骤

  1. 使用 Cost Management Query API 查询完整 Billing Period,不要只查询单个 Namespace。
  2. 按 ResourceId、Meter、ChargeType 等可用维度汇总费用。
  3. 提取每个实际 Namespace 的直接费用。
  4. 从 $system resource ID 的记录中筛选 Service Bus Standard base charge。
  5. 确定账期内每个 Namespace 处于 Standard tier 的有效时间。
  6. 按选定的规则分摊 $system 费用。
  7. 将分摊费用与各 Namespace 的直接费用相加。
  8. 检查所有 Namespace 的分摊金额之和是否等于原始 $system base 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 的累计有效小时数。

备注:内容仅供参考。