多租户配额管理SaaS计费

AI 应用多租户隔离与配额管理实战:SaaS 场景下如何公平分配 API 预算

2026-09-04 · 约 12 分钟阅读

把 AI 能力做成产品时,最容易踩的坑是租户 A 用光了租户 B 的额度,或者一个大客户把整个供应商账号打爆。本文是一篇方法论性的多租户架构指南,从租户隔离、配额分配、限速策略到计量计费,逐层拆解 SaaS 化 AI 应用的设计要点。

一、为什么 AI 应用的多租户比传统 SaaS 更难

传统 SaaS 多租户隔离的重点是数据库行级隔离和RBAC。AI 应用多了两层难题:

1. 供应商侧限速:上游 API Key 的 RPM/TPM 是共享的,一个租户的"突刺流量"会影响所有租户

2. 成本不可预测:一次推理成本随 prompt/output 长度变化,单次调用可能从 ¥0.01 到 ¥1,恶意租户能在 1 小时内烧光你的预算

所以 AI SaaS 的多租户隔离不只是"租户之间数据隔离",还包括"租户之间的资源(API 额度)和成本隔离"。

二、租户级 API Key 体系

最基础的设计是每个租户一个独立的供应商 API Key:

租户A (Acme)         租户B (Beta)         租户C (Gamma)
   │                     │                     │
   ▼                     ▼                     ▼
供应商Key-A           供应商Key-B           供应商Key-C
   │                     │                     │
   └─────────────────────┴─────────────────────┘
                         │
                  中转站 / 自建网关

好处:

  • 一个租户出问题不影响其他租户
  • 可以给大客户独立 Key,单独谈 RPM/TPM 配额
  • 计费清晰——查 Key 用量 = 查租户用量

缺点:

  • 供应商 Key 有数量上限和最小充值
  • 多 Key 管理复杂(key rotation、余额监控)

实际工程上更常见的折中:少量"共享 Key" + 配额隔离:

所有租户 ───▶ 中转站/网关 ───▶ 共享 Key 池 (3-5 个 Key)
                  │
                  ├── 租户A: 100万 TPM 配额
                  ├── 租户B: 50万 TPM 配额
                  └── 租户C: 200万 TPM 配额

三、配额池(Quota Pool)设计

配额池把"上游额度"和"租户可用额度"解耦:

class QuotaPool:
    def __init__(self):
        self.tenant_quotas = {}    # tenant_id -> {rpm, tpm, monthly_tokens}
        self.tenant_usage = {}     # tenant_id -> 当前窗口用量
        self.token_buckets = {}    # tenant_id -> TokenBucket

    def try_consume(self, tenant_id: str, estimated_tokens: int) -> bool:
        quota = self.tenant_quotas.get(tenant_id)
        if not quota:
            return False

        # 检查令牌桶(突发限速)
        bucket = self.token_buckets.setdefault(
            tenant_id,
            TokenBucket(rate=quota["tpm"] / 60, capacity=quota["rpm"]),
        )
        if not bucket.consume(estimated_tokens):
            return False

        # 检查月度上限
        monthly = self.tenant_usage.setdefault(tenant_id, 0)
        if monthly + estimated_tokens > quota["monthly_tokens"]:
            return False

        return True

配额维度的常见组合:

维度用途典型设置
RPM每分钟请求数60 / 600 / 6000(按订阅等级)
TPM每分钟 token 数100K / 500K / 2M
月度 Token 总量包月套餐核心1M / 10M / 100M
并发请求数防止单租户占满5 / 20 / 100

四、限速策略:从令牌桶到分级配额

1. 令牌桶(Token Bucket)—— 限速基础

import time

class TokenBucket:
    def __init__(self, rate: float, capacity: int):
        self.rate = rate          # tokens per second
        self.capacity = capacity  # 最大桶容量
        self.tokens = capacity
        self.last_refill = time.time()

    def consume(self, tokens: int) -> bool:
        now = time.time()
        elapsed = now - self.last_refill
        self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
        self.last_refill = now

        if self.tokens >= tokens:
            self.tokens -= tokens
            return True
        return False

2. 滑动窗口(Sliding Window)—— 月度配额

class SlidingWindowCounter:
    def __init__(self, window_seconds: int):
        self.window = window_seconds
        self.events = []  # [(timestamp, tokens)]

    def add(self, tokens: int):
        now = time.time()
        self.events.append((now, tokens))
        cutoff = now - self.window
        self.events = [(t, v) for t, v in self.events if t > cutoff]

    def total(self) -> int:
        return sum(v for _, v in self.events)

3. 分级配额

按订阅等级给租户不同 RPM/TPM:

plans:
  free:
    rpm: 10
    tpm: 50_000
    monthly_tokens: 500_000
  pro:
    rpm: 60
    tpm: 500_000
    monthly_tokens: 10_000_000
  enterprise:
    rpm: 600
    tpm: 5_000_000
    monthly_tokens: 100_000_000
    custom_upstream_key: true   # 可绑定自有 Key

五、计量(Metering)与计费(Billing)

计量是"用了多少",计费是"按多少收钱"。两者要解耦,因为计费规则会随业务变:

class MeteringService:
    def record(self, tenant_id, usage: Usage):
        # 计量记录存到 ClickHouse / TimescaleDB
        metrics_db.insert({
            "tenant_id": tenant_id,
            "timestamp": usage.timestamp,
            "model": usage.model,
            "prompt_tokens": usage.prompt_tokens,
            "completion_tokens": usage.completion_tokens,
            "latency_ms": usage.latency_ms,
        })

class BillingService:
    def calculate(self, tenant_id, period_start, period_end) -> Bill:
        usage = metrics_db.aggregate(
            tenant_id, period_start, period_end
        )
        plan = plan_service.get_plan(tenant_id)

        # 套餐内 + 超出部分按阶梯计费
        in_package = min(usage.total_tokens, plan.monthly_tokens)
        overage = max(0, usage.total_tokens - plan.monthly_tokens)

        cost = (
            plan.base_price
            + overage * plan.overage_price_per_1k_tokens / 1000
        )
        return Bill(tenant_id=tenant_id, usage=usage, cost=cost)

六、越权防护:租户隔离的"反例"

最容易出问题的 3 类越权:

1. 数据越权:租户 A 通过修改请求参数读取租户 B 的对话历史 → 用中间件做 tenant_id 强制注入

2. 配额越权:租户 A 调高自己的 plan 字段绕过限额 → 套餐信息服务端查库,不接受客户端参数

3. Key 越权:租户 A 直接用供应商 Key 调用,绕开你的计量 → 强制所有请求走网关

@app.middleware("http")
async def tenant_isolation(request, call_next):
    token = decode_jwt(request.headers["Authorization"])
    request.state.tenant_id = token["tenant_id"]

    # 强制使用请求中的 tenant_id 与 token 中的一致
    body = await request.body()
    if b'"tenant_id"' in body and not is_admin(token):
        raise HTTP403("禁止指定 tenant_id")

    return await call_next(request)

七、租户用量可视化与告警

租户需要"看到"自己的用量,建议提供:

1. 实时用量面板:当前 TPM、RPM、本月累计 tokens

2. 预算告警:用量达 80%/95%/100% 时邮件 / Webhook 通知

3. API 查询接口:让租户自助集成到自己的 dashboard

@app.get("/v1/usage/current")
async def current_usage(request):
    tenant_id = request.state.tenant_id
    return {
        "rpm_used": quota_pool.tenant_usage[tenant_id]["rpm"],
        "tpm_used": quota_pool.tenant_usage[tenant_id]["tpm"],
        "month_tokens": metrics_db.month_to_date(tenant_id),
        "month_limit": plan_service.get_limit(tenant_id),
    }

八、中转站在多租户场景的优势

对 SaaS 提供方来说,专业的中转站比"每租户独立供应商 Key"更划算:

方案优势劣势
每租户独立 Key隔离彻底Key 管理复杂,最低充值门槛高
共享 Key + 中转站配额集中计费,统一供应商协议中转站本身可能成为单点
自建网关(One API / New API)完全可控,可二次开发需要运维投入

如果选第三方中转站,建议在 openairouter.net 上对比各家平台的多租户支持能力(是否提供租户级 API Key、用量计量、计费回调等)。

九、3 个常见反模式

1. "所有租户用一个 Key" —— 一个大客户的突刺流量让所有租户一起被限速

2. "客户端传 plan 等级" —— 客户端永远不可信,plan 服务端查

3. "用量数据不可见" —— 租户看不到自己用了多少,月底账单惊讶就跑了

总结

AI SaaS 的多租户隔离核心是资源隔离 + 成本隔离:用配额池+令牌桶做限速,用滑动窗口做包月计量,用服务端鉴权做越权防护。这套架构搭好之后,剩下的就是让租户能"看见"自己的用量,这本身就是减少客诉的最有效手段。

如果你正在评估不同的中转站 / 聚合平台来承载 SaaS 业务,可以参考 openairouter.net 上的平台横向对比,关注它们的限速策略、配额粒度、用量回调接口支持情况。

相关阅读

找到最适合你的 AI API 中转站

收录 125+ 服务商,按价格、模型、标签一键筛选

查看所有中转站 →