计费与配额:Bella OpenAPI 的资源管理机制
引言:AI 能力的精细化管理
在企业级 AI 应用场景中,如何有效管理 API 资源、控制成本、实现合理计费是技术团队面临的重要挑。Bella OpenAPI 通过其精心设计的资源管理机制,提供了一套完整的解决方案,实现了从密钥分级、配额控制到使用统计的全流程管理。本文将深入分析 Bella OpenAPI 的资源管理架构,揭示其如何在开放 AI 能力的同时,确保资源使用的可控性与可计量性。
API Key 层级化结构的设计思路
Bella OpenAPI 设计了精巧的 API Key 层级化结构,为企业资源管理提供了灵活而强大的基础框架。
1. 父子密钥关系
通过分析 ApikeyService 的源码,我们可以看到系统实现了严格的父子密钥关系:
@Transactional
public String createByParentCode(ApikeyCreateOp op) {
ApikeyInfo apikey = EndpointContext.getApikey();
// 验证当前用户是否有权限创建子密钥
if(!apikey.getCode().equals(op.getParentCode())) {
throw new ChannelException.AuthorizationException("没有操作权限");
}
// 验证子密钥配额不超过父密钥
Assert.isTrue(op.getMonthQuota() == null ||
op.getMonthQuota().doubleValue() <=
apikey.getMonthQuota().doubleValue(), "配额超出 ak 的最大配额");
// 验证安全级别约束
Assert.isTrue(op.getSafetyLevel() <= apikey.getSafetyLevel(),
"安全等级超出 ak 的最高等级");
// 创建子密钥...
}
这种设计使用户可以:
- 实现多级资源分配,从公司到部门再到团队或个人
- 控制分配给每个单元的资源上限
- 追踪各级组织的资源使用情况
2. 配额继承与约束
子密钥的月度配额受到父密钥的严格约束,这确保了层级化管理的完整性:
这种设计确保了资源分配的合理性,防止某个下级单位占用过多资源,影响整体业务运行。
3. 资源隔离与共享
通过父子密钥关系,系统巧妙地平衡了资源隔离与共享的需求:
- 资源隔离:每个子密钥拥有独立的配额和使用统计,确保业务边界清晰
- 资源共享:父密钥可以灵活调整子密钥配额,实现资源的动态分配
- 总量控制:所有子密钥的使用总量受父密钥总配额的约束,确保企业整体成本可控
配额控制与计费系统的实现
Bella OpenAPI 实现了精细化的配额控制与计费系统,是企业级 AI 应用的重要保障。
1. 月度配额管理
系统通过 MonthQuotaInterceptor 实现了严格的配额控制:
// ApikeyService.java
@Value("${apikey.basic.monthQuota:200}")
private int basicMonthQuota;
// 创建基础密钥时设置默认配额
db.setMonthQuota(op.getMonthQuota() == null ?
BigDecimal.valueOf(basicMonthQuota) : op.getMonthQuota());
// 创建子密钥时验证配额约束
Assert.isTrue(op.getMonthQuota() == null ||
op.getMonthQuota().doubleValue() <=
apikey.getMonthQuota().doubleValue(), "配额超出 ak 的最大配额");
@Component
public class MonthQuotaInterceptor extends
HandlerInterceptorAdapter {
@Autowired
private ApikeyService apikeyService;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
// 异步请求跳过检查
if
(Boolean.TRUE.equals(request.getAttribute(ASYNC_REQUEST_MARKER)))
{
return true;
}
ApikeyInfo apikey = EndpointContext.getApikey();
// 非子 ak 或已指定额度的子 ak
if(apikey.getParentInfo() == null ||
apikey.getMonthQuota().doubleValue() > 0) {
BigDecimal cost =
apikeyService.loadCost(apikey.getCode(),
DateTimeUtils.getCurrentMonth());
double costVal = cost.doubleValue() / 100.0;
if(apikey.getMonthQuota().doubleValue() <= costVal) {
String msg = "已达每月额度上限, limit:" +
apikey.getMonthQuota() + ", cost:" + costVal;
throw new
ChannelException.RateLimitException(msg);
}
}
// 父 ak 的总额度不能超出
if(apikey.getParentInfo() != null) {
BigDecimal quota =
apikey.getParentInfo().getMonthQuota();
BigDecimal cost =
apikeyService.loadCost(apikey.getParentCode(),
DateTimeUtils.getCurrentMonth());
double costVal = cost.doubleValue() / 100.0;
if(quota.doubleValue() <= costVal) {
String msg = "主 ak 的总额度已达上限, limit:" + quota
这种设计实现了双重配额保障:
- 单个密钥的配额控制,防止单点资源过度使用
- 父密钥总量控制,确保整体成本可控
2. 高效的计费记录系统
系统通过 ApikeyCostRepo 实现了高效的计费记录:
@Transactional
public void insert(String akCode, String month) {
ApikeyMonthCostRecord rec = APIKEY_MONTH_COST.newRecord();
rec.setAkCode(akCode);
rec.setMonth(month);
rec.setAmount(BigDecimal.ZERO);
db.insertInto(APIKEY_MONTH_COST).set(rec)
.onDuplicateKeyIgnore()
.execute();
}
@Transactional
public void increment(String akCode, String month, BigDecimal
cost) {
db.update(APIKEY_MONTH_COST)
.set(APIKEY_MONTH_COST.AMOUNT,
APIKEY_MONTH_COST.AMOUNT.add(cost))
.where(APIKEY_MONTH_COST.AK_CODE.eq(akCode))
.and(APIKEY_MONTH_COST.MONTH.eq(month))
.execute();
}
这种设计具有以下优势:
- 原子操作:使用数据库事务确保计费数据的一致性
- 幂等设计:避免重复记录,确保计费准确性
- 增量记录:使用增量更新而非完全替换,提高并发性能
3. 多层缓存优化
为确保高并发环境下的性能,系统实现了多层缓存策略:
@Cached(name = "apikey:cost:month:", key = "#akCode + ':' +
#month", expire = 31 * 24 * 3600,
condition =
"T(com.ke.bella.openapi.utils.DateTimeUtils).isCurrentMonth(#month)")
@CachePenetrationProtect(timeout = 5)
public BigDecimal loadCost(String akCode, String month) {
BigDecimal amount = apikeyCostRepo.queryCost(akCode, month);
return amount == null ? BigDecimal.ZERO : amount;
}
这种设计极大提升了系统性能:
- 条件缓存:当月数据使用缓存,历史数据直接查询
- 缓存穿透保护:防止高并发下对数据库的冲击
- 长效缓存:31 天的缓存时间确保月度数据的高效访问
资源使用的监控与统计
Bella OpenAPI 提供了完善的资源监控与统计功能,为企业管理决策提供数据支持。
1. 使用量实时查询
系统支持实时查询当前使用量,便于用户了解资源消耗情况:
这使用户可以:
- 实时监控资源使用情况
- 及时调整资源分配策略
- 预防配额超限导致的服务中断
2. 历史账单查询
系统支持查询历史账单记录,便于分析长期使用趋势:
public BigDecimal queryCost(String akCode, String month) {
return db.select(APIKEY_MONTH_COST.AMOUNT)
.from(APIKEY_MONTH_COST)
.where(APIKEY_MONTH_COST.AK_CODE.eq(akCode))
.and(APIKEY_MONTH_COST.MONTH.eq(month))
.fetchOneInto(BigDecimal.class);
}