跳到主要内容
版本:Dev

成本归属标签

成本归属标签让组织按自己的维度归属用量和成本,例如部门、事业部、子公司、项目或成本中心。组织先声明标签键,再在调用方 API Key、团队和成员上设置 key=value。每个请求按其运行时解析出的标签值归属。之后可以在 Cost Analysis 页面按这些值拆分支出,用标签预算为其封顶,并让限流策略按标签匹配和拆分流量。

标签在 AISIX Enterprise 和 AISIX Cloud 中的行为一致。

前提条件​

开始之前,请准备以下内容:

  • 声明标签键需要组织的 owner 或 admin 角色,或拥有 tag_keys 写权限的自定义角色。在某个资源上设置标签,需要该资源的写权限。
  • 每个需要归属的环境都使用会在用量上记录标签的网关。1.6.x 及更早版本的网关不会记录,参见网关版本要求。
  • 使用 Admin API 示例时,需要控制面地址和具有写权限的 Admin Token:
# AISIX_CP 包含 /api,末尾不带斜杠。
# 本地 AISIX Enterprise 快速入门使用 http://localhost:8080/api。
export AISIX_CP="YOUR_AISIX_CONTROL_PLANE_API_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export TEAM_ID="YOUR_TEAM_ID"
export ENV_ID="YOUR_ENVIRONMENT_ID"

声明标签键​

标签键必须先在组织中声明,资源才能带上它。预先声明可以统一用词,避免 department 同时被写成 dept 或 Department。

  1. 在组织导航中打开 Tag Keys,选择 New tag key。
  2. 输入 Key,例如 department。
  3. 可以填写 Display name 和 Description。
  4. 选择 Declare key。

通过 Admin API 声明标签键:

curl -sS -X POST "${AISIX_CP}/tag_keys" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"key": "department",
"display_name": "Department",
"description": "Cost center the usage is charged to."
}'

标签键遵循以下规则:

  • 以小写字母开头,只包含小写字母、数字和下划线,最多 63 个字符:^[a-z][a-z0-9_]{0,62}$。
  • 声明后不能修改键本身。显示名称和描述可以随时编辑。
  • 每个组织最多声明 32 个键。超出时返回 400,错误码为 TAG_KEY_LIMIT;声明已存在的键返回 409。
  • 所有成员都可以读取已声明的键,写入需要 tag_keys 写权限。

删除标签键​

只要有预算或限流策略在使用某个标签键,删除就会被拒绝,返回 409,错误码为 TAG_KEY_IN_USE。错误信息会列出这些预算或策略,请先移除它们。

否则,删除会把该键从所有带有它的调用方 API Key、团队和成员上移除,之后的请求不再归属到它。已记录的用量保留当时的标签,因此已删除键的值仍会出现在已存的历史数据中。只要所选时间范围内的用量带有该键,Cost Analysis 就会继续提供它,并标记为 Deleted。

在 API Key、团队和成员上设置标签​

可以在三类资源上设置标签。每个资源只带自己的标签,形式为标签键到标签值的对象:

资源控制台Admin API
调用方 API Key环境 API keys 下 Key 的创建和编辑表单中的 Cost-attribution tags 部分POST /environments/{environment_id}/api_keys 和 PATCH /environments/{environment_id}/api_keys/{api_key_id}
团队Teams 下团队的创建和编辑表单POST /teams 和 PATCH /teams/{team_id}
成员Members 中成员行的 Tags 面板,以及 AISIX Enterprise 中的 Create user 表单POST /members 和 PATCH /members/{user_id}

控制台提供已声明的键供选择,并提示组织中该键已在使用的值。同样的建议值也可以通过 GET /tag_keys/{key}/values 获取,它列出调用方 API Key、团队和成员当前设置的最多 500 个去重值。只出现在已记录用量中的值不会列出。

标签值遵循以下规则:

  • 值是 1 到 128 个字符的自由文本。
  • 值不能包含换行等控制字符,也不能以空白字符(包括不换行空格和全角空格)开头或结尾。控制面会以 400 拒绝这样的值。
  • 资源 tags 中的每个键都必须已在组织中声明。

在 Admin API 中,PATCH 会整体替换 tags 对象,请发送要保留的完整集合。发送 null 或 {} 清空所有标签,不传 tags 则保持不变。例如,以下请求为团队设置两个标签:

curl -sS -X PATCH "${AISIX_CP}/teams/${TEAM_ID}" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"tags": {
"department": "rnd",
"subsidiary": "emea"
}
}'

成员的标签属于其在本组织中的成员资格,而不属于其账号。admin 可以修改成员的标签;修改成员角色仍然需要 owner。通过邀请、单点登录或 SCIM 目录同步加入的成员一开始没有标签。由目录同步管理的成员,其标签也可以在控制台和 Admin API 中编辑。目录同步既不读取也不写入标签,因此标签不会从身份提供方同步。

请求如何解析标签​

请求通过身份认证时,网关根据认证所用的调用方 API Key 解析其标签。对每个标签键,取最近的值:

  1. 调用方 API Key 自己的值。
  2. 否则,取该 Key 绑定的团队上设置的值。
  3. 否则,取拥有该 Key 的成员上设置的值。

只有 Key 自己的团队绑定和成员绑定会参与解析,成员所属的其他团队不提供任何标签。每个请求的每个标签键只有一个值,不同的键可以组合,所以一个请求可以从 Key 取 department、从团队取 business_group、从成员取 subsidiary。请求不能自带标签,网关从不从请求头或请求体中读取标签。

例如,组织声明了 department、business_group 和 subsidiary,并做了如下设置:

资源标签
团队 platformdepartment=infra、business_group=cloud
成员 Alicedepartment=rnd、subsidiary=emea
Key K1,绑定到 platform,所有者为 Alicedepartment=ml
Key K2,绑定到 platform,所有者为 Alice无
Key K3,所有者为 Alice,没有团队无

请求解析出的标签如下:

Keydepartmentbusiness_groupsubsidiary
K1ml,来自 Keycloud,来自团队emea,来自成员
K2infra,来自团队cloud,来自团队emea,来自成员
K3rnd,来自成员未设置emea,来自成员

归属在请求运行时确定​

网关会把解析出的标签和 Key 的团队记录在该请求的每条用量事件上,包括重试、故障转移以及网关自己的拒绝。控制面随事件一起存储它们,并按记录的内容归属成本。

因此,标签的变更只影响之后的请求。修改 Key、团队或成员的标签,把 Key 绑定到其他团队,或删除标签键,都不会重新归属已经记录的用量。在设置标签之前记录的用量,以及不记录标签的网关上报的用量,在该标签上都没有值,显示为 Not set。

按标签分析成本​

组织级的 Cost Analysis 页面一次按一个维度,对组织内所有环境的用量分组。页面分为两部分:Filter 选定要分析的用量,Statistics 对其进行拆分。建议按这个顺序操作:先筛选用量,再对剩下的用量分组,然后下钻。例如,先筛选 business_group=cloud,再按 department 标签分组,查看该业务组的花费在各部门之间如何分布。

Filter 部分在前:

  • 时间范围:最近 24 小时、7 天、30 天,或自定义范围。页面按整点小时读取,开始时间向下取整,结束时间向上取整。
  • 筛选条件:环境、团队、成员、模型,以及任意多个标签 key=value 筛选。不同标签键的筛选必须同时满足,同一个键的多个值满足其一即可。从 API Key 行下钻时,会把该 Key 加为筛选条件。每个生效的筛选条件都以标签块的形式显示在控件下方,Clear filters 可一次清除全部筛选。

Statistics 部分随后对筛选后的用量进行拆分:

  • 分组方式:标签键、团队、成员、API Key、模型、环境或日期。按日期分组时显示按天的柱状图,其他分组显示横向条形图。
  • 排序依据:成本、总 Token、输入 Token、输出 Token、请求数或成功请求数,分组按从大到小排列。
  • 刷新:重新加载数据,同时重新加载标签键以及团队、成员和环境的名称。

选择某一行即可下钻:该行的分组会成为筛选条件,页面随后选择筛选尚未固定的下一个分组方式。表格上方的面包屑可以回到之前的任意一步。Not set 行汇总在该分组上没有值的用量,不能下钻;日期行也不能下钻。表格最多列出 50 个分组,其余的汇总在 Other N groups 行中,因此列出的分组加上该行等于合计。

按团队或标签键分组时,Budget (current period) 列显示对应团队预算或标签预算的本期已花费和额度。按 API Key 分组时,每个 Key 行都可以跳转到该 Key 所在环境的请求日志,并已按该 Key 筛选。

分组方式、标签筛选和下钻中提供的标签键,是组织已声明的键,加上所选时间范围内用量带有、但当前已不再声明的键。后者是在这些用量记录之后被删除的键,会标记为 Deleted,仍然可以用于分组和筛选。取值建议来自当前带有该键的调用方 API Key、团队和成员,因此已删除的键没有取值建议:请手动输入值,或从分组行下钻。如果一个标签键都没有,分组方式和筛选的下拉框会显示提示,并链接到标签键设置页,标签筛选在声明标签键之前不可用。

团队、成员、API Key 或环境在其用量记录之后被删除,仍会单独成行。分组行、图表标签、面包屑和筛选标签块会显示其 ID 的前 8 个字符,并带有 Deleted 徽标;已不在组织中的成员显示 Removed。选择徽标可以查看完整 ID 并复制。Name unavailable 徽标表示控制台无法确认该资源是否仍然存在,例如团队列表加载失败,并不代表该资源已被删除。

控制面升级后,在升级前记录的用量补入期间,页面显示与 Usage 视图相同的回填提示,回填完成前数据并不完整。成本使用组织币种。

所有有用量读取权限的成员都可以打开 Cost Analysis。自动化可以通过 GET /usage_analysis 读取相同的数据,并通过 GET /usage_analysis/tag_keys 读取某个时间范围内用量带有的标签键(包括已删除的键),参见 AISIX Cloud Admin API 参考。

按标签设置预算​

标签预算为组织内所有环境中归属到某个标签值的支出封顶。在预算视图中选择 Tag 范围,再选择标签键并填写值。在 Admin API 中,将 scope 设为 tag,scope_ref 设为 <key>=<value>,例如 department=rnd。键必须已声明,值为第一个 = 之后的全部内容。limit_cents 以组织币种的最小单位计。

curl -sS -X POST "${AISIX_CP}/budgets" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"display_name": "R&D monthly",
"scope": "tag",
"scope_ref": "department=rnd",
"limit_cents": 50000,
"period": "month",
"hard_stop": true
}'

标签预算的周期、到达限额即阻断(hard stop)和告警规则与其他预算相同,每个标签值只能有一个预算。支出按每个请求用量上记录的标签计入。达到限额的阻断型标签预算会以 429 拒绝之后解析出同一标签值的请求,错误码为 budget_exceeded,其中 scope 为 tag,scope_ref 为该 key=value。

只要组织任一环境中注册的网关运行的是不记录标签的版本(即 1.6.x 及更早版本),创建标签预算就会被拒绝,返回 422,错误码为 DP_INCOMPATIBLE,因为这类网关的用量不会计入该预算。

按标签限流​

条件式限流策略在条件维度和 group_by 中都接受 tag:<key>,键必须已声明。例如,以下策略为每个部门分别设置每分钟 600 个请求的限额:

curl -sS -X POST "${AISIX_CP}/environments/${ENV_ID}/rate_limits" \
-H "Authorization: Bearer ${AISIX_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "per-department-rpm",
"group_by": ["tag:department"],
"limits": { "rpm": 600 }
}'

解析出 department=rnd 的两个调用方 API Key 共用一个计数器,解析出 department=sales 的 Key 有自己的计数器。请求在该标签上没有值时,既不命中针对它的条件,也不命中取反后的条件;按该标签分组的策略也不约束它。

只要该环境中有注册的网关运行 1.6.x 及更早版本,保存使用 tag: 的策略就会被拒绝,返回 422,错误码为 DP_INCOMPATIBLE,因为这些版本无法加载它。

在用量事件和请求日志中读取标签​

每条用量事件都带有 tags(请求解析出的标签)和 team_id(调用方 API Key 绑定的团队),为空时省略。可观测性导出器会把它们发送到外部系统,请求日志在行详情和导出中显示它们。各导出器中的字段名见将事件归因到团队和标签。标签不会成为 Prometheus 指标标签。

网关版本要求​

标签由网关解析并记录。1.6.x 及更早版本的网关会忽略它们:

  • 它能加载带标签的调用方 API Key、团队和成员,但会忽略 tags 字段。控制台会为这些网关显示部分兼容提示。
  • 它的用量不带标签,也不带 team_id,因此在 Cost Analysis 中显示为 Not set。
  • 它会丢弃使用 tag: 的限流策略。

如上所述,只要注册了这类网关,控制面就会拒绝保存标签预算和标签限流策略。这项检查只能看到保存预算或策略时已经注册的网关。

已知缺口

如果有网关回滚到 1.6.x,或者在标签限流策略或标签预算保存之后又有 1.6.x 网关加入,那么标签限流在这台网关上不生效,它的用量也不会计入标签预算。控制台的 rejected-resources 报告会显示这一情况。将该网关升级即可恢复限流和计数。

下一步​

使用预算和预算告警与通知为标签支出封顶并进行监控。要将带标签的用量与环境级合计对照,参见用量上报。