生图API 怎么做多租户隔离?一个密钥服务多个店铺的用量拆分(nano-banana2)

我们给几十个商家做 SaaS,每家都要用生图。上游是一个该服务 密钥,下游是几十个租户

问题随之而来:某个商家批量刷图,把并发占满,其他家全都变慢——而且月底账单是一整笔,分不清谁用了多少

两件事要解决

一、用量归属。 每次调用要能算到具体租户头上。 二、资源隔离。 一家刷爆不能影响其他家。

用量归属:在自己这层记账

上游给的是总量,拆分只能自己做。每次调用落一条记录:

async function genForTenant(tenantId, params) {
  const t0 = Date.now();
  let ok = false;
  try {
    const r = await callGenApi(params);
    ok = true;
    return r;
  } finally {
    await db.usage.insert({
      tenantId,
      model: params.model,
      // 不同模型成本不同,只记次数月底对不上账
      units: costUnits(params.model),
      costMs: Date.now() - t0,
      ok,
      at: new Date(),
    });
  }
}

finally 里记,不是 then 里记。 失败的调用也可能产生消耗,只记成功的会导致自己这边的统计低于上游账单,月底对不上。

按模型折算 units,别只记次数。nano-banana-pronano-banana2 的成本差好几倍,混在一起算等于让用便宜模型的租户补贴用贵模型的。

资源隔离:按租户限流 + 全局限流

两层都要。

class TenantLimiter {
  constructor({ perTenant = 2, global = 8 }) {
    this.perTenant = perTenant;
    this.global = global;
    this.running = new Map();   // tenantId -> 正在跑的数量
    this.total = 0;
  }
  canRun(tenantId) {
    return this.total < this.global
      && (this.running.get(tenantId) || 0) < this.perTenant;
  }
  acquire(tenantId) {
    this.total++;
    this.running.set(tenantId, (this.running.get(tenantId) || 0) + 1);
  }
  release(tenantId) {
    this.total--;
    const n = (this.running.get(tenantId) || 1) - 1;
    if (n <= 0) this.running.delete(tenantId); else this.running.set(tenantId, n);
  }
}
  • 单租户上限保证一家占不满
  • 全局上限保证总量不超过上游能扛的并发

只有全局限流的话,一个租户塞几百个任务照样能把队列占死;只有单租户限流的话,租户一多总并发还是会爆。两层缺一不可。

配额:软限 + 硬限

我们给每个租户配了两个阈值:

  • 软限(比如月度额度的 80%)→ 继续服务,但发通知
  • 硬限(100%)→ 拒绝新请求,返回明确的错误码
const used = await db.usage.sumUnits(tenantId, thisMonth);
if (used >= tenant.quotaHard) {
  throw Object.assign(new Error('本月额度已用完'), { code: 'QUOTA_EXCEEDED' });
}
if (used >= tenant.quotaSoft) notifyQuotaWarning(tenantId, used);

错误码要明确。 返回一个笼统的"生成失败",商家会以为是系统故障来找客服;返回 QUOTA_EXCEEDED 并带上剩余额度,他自己就知道该充值了。

密钥要不要一家一个

理论上一家一个密钥最干净,用量上游就分好了。但实际上:

  • 密钥管理成本高,几十个租户就是几十个密钥要存要轮换
  • 上游的并发是按密钥算的,拆开之后每家的并发反而变小,高峰期更容易堵

我们最后选的是共用一个密钥 + 自己这层记账和限流。该服务的并发给得比较宽,共用一个池子在整体利用率上更划算——某家闲着的时候,容量可以给到忙的那家。

代价是记账逻辑必须自己写严,尤其是失败调用的处理。这部分省不掉。


接口服务:甜甜圈API(dashengfenshen.cn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值