公司动态
LLM多租户服务配额与熔断体系:从设计到生产实践
1. 从一次线上告警说起当Token配额耗尽时那天下午我正在和同事讨论一个模型微调的策略突然钉钉群里开始疯狂弹消息。点开一看是监控系统的告警“生产环境LLM服务调用异常率激增多个租户请求失败”。紧接着业务方的电话就打了过来“我们的智能客服怎么突然不回复了用户正在投诉”登录到监控大盘一片飘红。错误信息很明确token plan quota exhausted。翻译过来就是某个租户的Token配额用完了。这还不是最糟的由于我们没有设置有效的熔断机制这个租户的持续重试请求连带影响了共享同一组模型实例的其他租户导致服务整体响应变慢甚至部分请求超时。那一刻我意识到在LLM大语言模型服务走向多租户、规模化生产的路上一个健壮的配额Quota与熔断体系其重要性不亚于模型本身的精度。我们构建的LLM服务平台往往需要同时服务于内部多个业务团队、外部不同的客户企业这就是典型的多租户架构。每个租户可能是一个部门、一个项目组或者一个付费客户。他们共享着底层昂贵的GPU算力和模型API但他们的使用需求、预算和重要性天差地别。如果没有一套精细化的配额管理、用量监控和故障隔离机制那么就会出现资源挤兑某个“土豪”或“疯狂”的租户无限制调用耗尽共享资源导致其他租户服务不可用。成本失控无法准确计量和分摊成本特别是按Token计费的云厂商API调用账单可能瞬间爆炸。故障扩散一个租户的异常行为如高频重试、恶意攻击或配额耗尽引发的连锁反应会像雪崩一样摧毁整个服务。因此LLM多租户Quota工程的核心目标就是要在共享的资源池上为每个租户划定清晰的资源使用边界配额实时监控其用量预警并在边界被触及或出现异常时果断实施隔离熔断从而保障服务的整体稳定性、公平性和成本可控性。这不仅仅是简单的计数器而是一个融合了资源调度、流量治理和成本管理的生产级系统工程。接下来我将结合我们的实践拆解Token配额、用量预警与自动熔断这三个核心环节的设计与实现。2. Token配额体系的设计不止是简单的总数限制提到配额很多人的第一反应是“给每个租户设一个每月/每天的总Token调用上限不就行了” 在实际生产中这种粗放的设计远远不够它无法应对复杂的场景也缺乏灵活性。一个生产可用的Token配额体系应该是多维度和分层次的。2.1 配额的多维度建模我们至少需要从以下几个维度来定义配额时间维度这是最基础的。通常包括周期配额如每月、每周、每日、每小时的Token上限。用于控制长期和短期的资源消耗总量对应成本预算。瞬时速率Rate Limit如每秒TPS、每分钟TPM的Token上限或请求数上限。用于防止突发流量打垮服务保障服务平稳性。例如限制单个租户每秒不超过10000个Token的生成量。资源维度模型级别配额不同模型的成本价格/Token和算力消耗不同。一个租户对GPT-4的配额可能远小于对GPT-3.5-Turbo的配额。需要为每个租户在不同模型上设置独立的配额。API端点级别配额/v1/chat/completions对话和/v1/embeddings嵌入的消耗模式和成本也不同可能需要区别对待。算力配额可选但重要对于自研模型除了Token还需要考虑GPU显存占用时长、计算单元消耗等。可以将Token作为代理指标也可以建立更复杂的资源评分模型。业务维度基础配额与弹性配额每个租户有一个保证可用的基础配额。在整体资源有富余时可以允许其临时“借用”或“超量”使用弹性配额并在后续周期中扣除或按更高费率计费。优先级配额为高优先级租户如VIP客户、核心业务预留配额确保他们的服务在任何情况下都优先得到满足。这通常需要配合配额调度算法实现。在我们的系统中一个租户的配额配置最终可能是一个复杂的JSON结构存储在配置中心如Nacos、Apollo或数据库中{ tenant_id: biz_team_a, quotas: [ { model: gpt-4, limits: { monthly_tokens: 10000000, daily_tokens: 500000, hourly_tokens: 50000, tokens_per_minute: 10000, requests_per_minute: 30 }, priority: 1 }, { model: text-embedding-ada-002, limits: { monthly_tokens: 5000000, daily_tokens: 300000, tokens_per_minute: 20000 }, priority: 2 } ], enable_burst: true, // 是否允许突发弹性配额 burst_multiplier: 1.5 // 突发系数允许瞬时超过速率限制的倍数 }2.2 配额的计算与扣减策略当收到一个LLM API请求时配额服务需要执行以下逻辑Token计数首先需要准确计算本次请求消耗的Token数。这包括输入TokenPrompt Tokens用户发送的消息内容。输出TokenCompletion Tokens模型生成的回复内容。总Token两者之和。对于像OpenAI的API响应头里会直接返回这些计数。对于自研模型需要在服务端集成类似tiktoken用于OpenAI模型或sentencepiece用于开源模型的Tokenizer进行估算。这里有一个坑估算必须准确特别是对于中文等非英语语言不同分词器的结果差异可能很大会直接影响计费的公平性。配额校验与扣减这是一个原子操作必须保证在高并发下的准确性。我们采用了“令牌桶Token Bucket”算法和“滑动窗口Sliding Window”算法的结合。对于速率限制如TPM使用滑动窗口日志或滑动窗口计数器。例如检查过去60秒内该租户消耗的Token总数是否已超限。Redis的ZSET有序集合是实现滑动窗口的利器将每次请求的时间戳作为scoreToken数作为value可以方便地统计任意时间窗口内的总和并清理过期数据。对于周期配额如日配额使用计数器。在Redis中为每个租户-模型-周期如tenant:biz_team_a:model:gpt-4:daily:20240515设置一个键使用INCRBY进行累加并设置合适的TTL如48小时自动过期。扣减操作必须使用Redis的MULTI/EXEC事务或Lua脚本确保“检查-扣减”的原子性防止超卖。伪代码如下-- Lua脚本示例检查并扣减滑动窗口配额 local key KEYS[1] -- 例如 rate_limit:tenant:a:model:gpt-4:minute local now tonumber(ARGV[1]) local window tonumber(ARGV[2]) -- 窗口大小秒 local limit tonumber(ARGV[3]) -- 限制数 local tokens tonumber(ARGV[4]) -- 本次请求Token数 -- 移除窗口外的记录 redis.call(ZREMRANGEBYSCORE, key, 0, now - window) -- 计算当前窗口内总量 local current redis.call(ZCARD, key) -- 获取当前总量如果ZSET的value存储了token数 -- 更常见的做法是每次添加一个带权重的成员这里简化表示 if current tokens limit then return 0 -- 配额不足 else -- 添加本次请求记录score为当前时间戳member唯一如UUID redis.call(ZADD, key, now, ...) -- 设置整个key的过期时间避免无用数据堆积 redis.call(EXPIRE, key, window 10) return 1 -- 扣减成功 end注意分布式一致性挑战。在大型分布式系统中配额服务本身可能是多实例部署的。如果每个实例独立计数就会导致配额超限。因此必须将配额计数中心化到一个共享存储中如Redis Cluster。所有网关或业务服务实例都向这个中心发起配额扣减请求。这带来了新的问题网络延迟和中心存储的压力。为了缓解可以采用“预扣”“异步核对”的折中方案即本地缓存一小部分配额定期与中心同步但这会牺牲一定的精确性适合对配额精度要求不是极端严格的场景。3. 用量监控与分级预警让问题暴露在发生之前配额是硬性边界而预警则是软性的缓冲区和提醒机制。它的目的是在租户用量接近配额边界时提前通知租户和管理员以便采取行动如申请增加配额、优化使用方式避免服务被突然熔断造成业务中断。一个有效的预警系统应该是实时、分级且可行动的。3.1 预警指标与阈值设定预警的核心是监控指标。除了最直接的“已用配额百分比”我们还需要关注一些衍生和关联指标它们能更早地揭示问题使用速率趋势监控租户最近1小时、6小时的Token消耗速率Token/Hour。如果发现速率急剧上升即使离配额上限还远也可能预示着异常脚本运行或业务量激增需要提前关注。配额耗尽预测时间基于当前周期剩余配额和近期的平均消耗速率动态预测配额将在多少小时后耗尽。例如“您的日配额预计将在4小时后用完”。这是一个非常直观且 actionable 的指标。错误率关联当出现大量4xx如配额不足429 Too Many Requests或5xx错误时预警系统需要能关联到具体的租户并分析是其自身配额问题还是被其他租户影响。成本消耗速率将Token用量乘以模型单价实时监控成本消耗速度对财务控制尤为重要。阈值设定需要结合业务敏感性。一个常见的三级预警体系如下提醒级70%当用量达到配额的70%时通过内部通讯工具如钉钉、企微或邮件通知租户联系人。内容温和如“您的本月GPT-4用量已使用70%请知悉。”警告级90%当用量达到90%时升级通知频率并抄送管理员。提示语需更强烈并附带配额详情和预测耗尽时间。严重级100% 或 预测即将耗尽当用量达到100%或预测将在短时间内如30分钟耗尽时触发严重告警。除了通知可能还会自动触发一些预定义的动作如限制其非关键功能的调用。3.2 实时监控与告警通道的实现技术实现上预警系统依赖于一个高吞吐、低延迟的数据流水线数据采集在每个LLM API网关或业务服务中埋点记录每一次请求的详细信息租户ID、模型、输入输出Token数、时间戳、响应状态、耗时等。这些数据可以通过日志文件输出但更高效的方式是直接发送到消息队列如Kafka或实时流处理平台。流式处理与聚合使用流处理框架如Flink、Spark Streaming或时间序列数据库如VictoriaMetrics、Thanos的实时聚合能力对流入的数据按租户、模型、时间窗口1分钟、5分钟、1小时进行快速聚合计算累计用量、当前速率等指标。规则判断与告警触发将聚合后的指标与存储在规则引擎或配置库中的预警阈值进行实时比对。一旦触发规则立即生成告警事件。这里推荐使用Prometheus Alertmanager的组合或夜莺、Elasticsearch Watcher等成熟方案。它们支持灵活的规则表达式和强大的告警路由、去重、静默功能。告警分发与行动告警事件通过不同的渠道钉钉、短信、电话、PagerDuty发送给不同的接收人租户、运维、研发。关键点在于告警信息必须包含足够的上文租户名、触发的指标、当前值、阈值、相关的Dashboard链接、以及可能的处理建议如“请登录控制台申请临时增加配额”。实操心得避免告警疲劳。预警系统最怕“狼来了”。如果阈值设置不合理或者短暂的业务峰值频繁触发警告又自动恢复会导致接收人麻木。我们的经验是设置告警恢复通知当用量从预警阈值以上回落到正常水平时发送一个“已恢复”的通知形成闭环。引入告警延迟Pending Duration例如要求“用量持续5分钟超过90%”才触发告警过滤掉瞬时尖刺。分级静默对于非核心时段如深夜或已知的营销活动期可以临时调高阈值或静默特定租户的告警。定期回顾告警规则每季度审视一次告警触发频率和有效性优化阈值。4. 自动熔断机制故障隔离的最后防线预警是“防患于未然”而熔断则是“断臂求生”。当租户的配额真的耗尽或者其行为异常如超高频错误请求时熔断机制必须迅速、果断地将其隔离防止其单个点的故障扩散成整个系统的雪崩。在微服务架构中Hystrix、Sentinel等组件广为人知。在LLM多租户场景下熔断的设计需要更有针对性。4.1 熔断的触发条件Circuit Breaker Conditions熔断器通常有三种状态关闭Closed、打开Open、半开Half-Open。状态转换由一系列条件触发配额耗尽熔断这是最直接的触发条件。当校验发现租户某项配额如日Token总量完全用尽时应立即触发熔断。后续该租户对该资源的所有请求在下一个配额周期开始前都应被快速失败Fast Fail返回明确的错误信息如429 Quota Exhausted而不再向后端模型服务转发。这节省了无效的资源消耗和网络开销。异常比例/慢调用熔断即使配额未耗尽租户的行为也可能异常。例如错误率熔断在滑动时间窗口内如最近10秒该租户请求的失败率如HTTP 5xx或超时超过阈值如50%。这可能是因为租户的Prompt构造有问题总是触发模型的内容过滤策略或者其客户端存在bug。慢调用比例熔断在滑动窗口内请求耗时超过设定阈值如10秒的比例超过一定限度如50%。这可能是因为租户总是请求生成极长的文本占用了过长的GPU时间影响了其他租户。并发数熔断限制单个租户同时进行的请求数量防止其用大量并发连接拖垮服务。手动熔断运营或运维人员通过管理后台可以对特定租户进行手动熔断操作用于紧急情况下的干预。4.2 熔断策略与恢复机制熔断不是永久性的需要有一套恢复策略熔断开启后的行为一旦熔断器进入Open状态所有后续请求会立即被拒绝并返回一个友好的错误如“服务暂时不可用请稍后重试”。同时可以触发一个告警通知管理员。休眠期与探测恢复熔断器会设置一个休眠时间如5秒。在此期间所有请求都被拒绝。休眠期过后熔断器进入Half-Open状态。半开状态与试探在半开状态下熔断器允许有限数量的请求如3个通过去尝试调用真实的后端服务。这些请求被称为“探测请求”。如果这些探测请求全部成功则认为下游服务已恢复熔断器关闭Closed恢复正常流量。如果仍有部分探测请求失败则熔断器再次打开Open并进入一个新的、可能更长的休眠期通常采用指数退避算法如5秒、10秒、20秒…。配额熔断的特殊性对于因配额耗尽触发的熔断其恢复条件很明确下一个配额周期开始如次日零点。因此这类熔断器可以在周期切换时自动重置无需经过半开探测。4.3 基于网关的熔断实现熔断逻辑的最佳位置是API网关如Kong, Apache APISIX, Spring Cloud Gateway。网关是所有流量的入口在这里实现熔断可以做到对后端业务服务无侵入。我们以集成Sentinel到Spring Cloud Gateway为例说明关键步骤定义资源与规则将每个“租户模型API端点”的组合定义为一个Sentinel资源。例如POST:/v1/chat/completions:tenant_biz_team_a:model_gpt-4。然后为这个资源配置熔断规则grade: 熔断策略0: 慢调用比例 1: 异常比例 2: 异常数。count: 阈值如慢调用时间5000ms异常比例0.5。timeWindow: 熔断恢复的休眠时间单位秒。minRequestAmount: 触发熔断的最小请求数目。statIntervalMs: 统计时长滑动窗口大小。在网关过滤器中集成编写一个自定义的Gateway Filter在PRE阶段从请求头或JWT Token中解析出tenant_id和model信息拼接成资源名。然后调用Sentinel的SphU.entry(resourceName)方法进行流量控制。如果被限流或熔断会抛出BlockException此时过滤器可以直接返回429或503状态码的响应。动态规则配置熔断和流控规则不应硬编码。需要将其持久化到外部配置源如Nacos, ZooKeeper并通过Sentinel Dashboard或自研管理后台进行动态推送和更新。这样当某个租户配额耗尽时后台系统可以自动向网关集群推送一条针对该租户的“异常比例熔断”规则将失败率阈值设为0%使其立即熔断。配额耗尽与熔断的联动这是设计的精髓。配额服务在发现某个租户配额耗尽后不应仅仅返回一个错误码。它应该同时调用网关的管理API或向配置中心写入一条规则动态地为该租户添加一个熔断规则。这样后续请求在网关层就被拦截根本到达不了配额校验和模型服务实现了最快速、最彻底的隔离。踩坑实录熔断规则的雪崩效应。我们曾经遇到过在业务高峰期由于底层模型服务集群出现短暂抖动导致大量租户的请求变慢或失败。这触发了每个租户资源上的慢调用熔断规则。短时间内网关向配置中心写入了成千上万条熔断规则。配置中心不堪重负规则同步出现延迟和丢失导致部分网关节点规则不一致有的还在放行已经该熔断的流量进一步加剧了后端压力。教训是熔断规则的动态推送要谨慎尤其是自动化推送。可以考虑设置一个全局的、粗粒度的系统保护规则如整体QPS限流先保护住系统。对租户级别的熔断规则推送做聚合和延迟避免瞬时海量操作冲击配置中心。确保配置中心和网关有足够高的可用性和性能。5. 生产环境下的架构设计与考量将Token配额、用量预警、自动熔断这三个模块有机结合起来并部署到生产环境需要一个清晰、稳固的架构。下图勾勒了我们当前系统的核心组件与数据流注此处用文字描述架构图因禁止使用Mermaid整个系统可以分为数据面和控制面。数据面快速路径用户请求首先到达API 网关集群如Kong。网关的认证/鉴权插件从请求中提取租户身份如API Key。网关的配额/熔断过滤器携带租户和模型信息向配额服务集群发起一次轻量的RPC调用或使用Redis Lua脚本进行配额校验和扣减。配额服务连接Redis Cluster作为配额计数中心执行原子化的检查与扣减逻辑。如果配额通过请求被转发至后端的LLM 模型服务集群或第三方API代理。模型服务处理完成后将响应含Token使用量返回给网关网关再返回给用户。同时模型服务或网关会将本次请求的详细日志含Token数异步发送到消息队列Kafka。控制面管理/异步路径流处理引擎如Flink Job消费Kafka中的用量日志进行实时聚合计算各租户的实时用量、速率并写入时序数据库如Prometheus/VictoriaMetrics和业务数据库用于报表和计费。监控告警系统如Prometheus Alertmanager从时序数据库读取指标根据预设的预警规则用量达到80%、90%等触发告警并通过钉钉、邮件等通道发送。管理后台提供界面供管理员查看所有租户的配额配置、实时用量、告警历史并支持手动调整配额、手动触发/解除熔断。当配额服务检测到配额耗尽或监控系统触发严重告警时可以通过配置管理服务或直接调用网关API向所有API网关实例动态下发针对该租户的熔断规则。配置中心如Nacos负责存储和同步所有动态的配额规则、熔断规则到网关和配额服务。关键生产考量性能与延迟配额校验位于关键路径上必须极快。Redis的内存操作和Lua脚本的原子性是关键。平均延迟应控制在1-2毫秒内。可以考虑在网关上缓存“未超限”租户的名单短期内跳过配额校验但需谨慎处理数据一致性。一致性配额计数必须准确。在分布式环境下强一致性往往以性能为代价。我们的选择是最终一致性。对于周期配额如日配额我们接受在极端情况下如网关实例和Redis主节点同时宕机可能有微小超限0.1%因为成本是可追溯和可调整的。对于速率限制我们使用滑动窗口其本身在窗口边界就存在微小误差业务上可以接受。容错与降级配额服务或Redis不可用怎么办我们的策略是故障降级当配额服务连续多次调用失败或超时网关会切换至“降级模式”。在此模式下对于已识别的、重要的内部租户允许其继续访问记录日志以备后续核对对于外部或低优先级租户可以返回一个保守的限流值或直接拒绝并记录告警。这确保了核心业务在极端情况下的可用性。数据持久化与对账所有配额扣减记录和请求日志都必须持久化到业务数据库或数据仓库。每天/每月需要运行对账任务将Redis中的计数与持久化日志进行核对发现并修复因系统故障可能导致的计数偏差确保计费准确无误。6. 进阶话题配额调度、成本优化与未来演进基础的配额、预警、熔断三板斧搭建完毕后系统可以稳定运行。但要追求更优的资源利用率和业务体验还有一些进阶问题值得思考。6.1 配额调度与超卖在资源池固定的情况下如何让配额分配更灵活我们引入了配额调度的概念。想象一下飞机的超售我们的GPU算力或API调用额度也可以“超卖”因为并非所有租户都会在同时刻用满配额。弹性配额池我们划出一部分资源作为弹性池。当租户A的请求超过其基础配额但系统整体资源有富余时可以从弹性池中临时分配额度给它。这部分额度可能收费更高或者需要在系统资源紧张时被优先回收。优先级与抢占式调度为配额设置优先级。高优先级租户的请求永远优先满足。当资源不足时低优先级租户的请求可以被延迟处理排队或直接拒绝被抢占。这需要网关或配额服务实现一个带有优先级的请求队列。基于预测的动态调整通过分析历史用量数据预测未来一段时间如下一小时各租户的用量。在预测用量低的时段可以自动放宽某些租户的速率限制在预测高峰时段则提前收紧限制或引导非紧急任务错峰运行。6.2 从Token配额到成本优化配额管理的终极目标之一是控制成本。特别是使用按Token计费的云厂商API时。成本感知的配额在配额配置中直接体现成本。例如为租户设置“月度预算1000元”而不是“月度Token 1000万”。系统需要根据各模型实时价格可能浮动动态地将预算折算成各模型的Token配额。这要求配额系统能与成本计算服务紧密联动。智能模型路由在网关层可以根据请求的内容、复杂度以及各模型的成本、性能进行智能路由。例如简单的分类任务可以路由到便宜的gpt-3.5-turbo而复杂的创意写作则路由到gpt-4。这需要在配额体系中支持“通用配额”的概念即一个配额池可以用于多个模型但消耗的“成本点数”不同。用量分析与优化建议系统可以定期为租户生成用量分析报告指出其Token消耗最多的场景、Prompt是否过于冗长、是否有重复调用等并提供具体的优化建议帮助租户节省成本。6.3 面向Agent与长上下文的新挑战随着AI Agent的普及和模型上下文窗口的不断增大如128K、1M Token配额系统面临新挑战。Agent的链式调用一个Agent任务可能包含多次LLM调用、工具使用和自身循环。如何定义一次“Agent任务”的配额是按子步骤单独计费还是打包成一个“事务”我们需要在配额服务中引入“会话”或“任务”的概念对一个逻辑任务进行整体的配额管理和成本核算。长上下文的成本爆炸处理一个包含10万Token上下文的请求其计算成本和API费用远高于10个1万Token的请求。简单的Token总数配额可能不够公平。可能需要引入基于“上下文窗口占用时长”或“计算复杂度加权Token”的配额单位。流式输出的配额预扣对于流式响应Server-Sent Events模型是一个Token一个Token地返回。如果等到流结束再扣减配额就无法在过程中进行限制。一种做法是在流开始时根据请求的max_tokens参数预扣一个估计值流结束后再根据实际用量进行多退少补的调整。这增加了系统的复杂性。7. 总结与个人体会构建LLM多租户的Quota管理系统是一个典型的“业务驱动技术”的工程实践。它开始于一个简单的需求——“别让某个用户把资源用光了”但深入下去你会发现它牵连着资源治理、流量控制、成本管理、体验保障和系统稳定性等方方面面。从我自己的踩坑经历来看有几点体会特别深刻第一设计之初就要考虑“可观测性”。配额系统本身不能是一个黑盒。你需要为它建立完善的监控指标配额校验的延迟、成功率、Redis的内存使用率、各租户的配额使用水位线、熔断规则的触发次数……这些指标是系统健康度和公平性的眼睛。没有它们你就是在盲人摸象。第二“快速失败”和“优雅降级”是稳定性的基石。配额耗尽或服务异常时一定要在网关层就快速返回明确错误避免无效流量冲击下游。同时系统各个组件如配额服务、配置中心都要有降级方案确保在部分组件失效时核心链路不至于完全瘫痪。第三没有银弹只有权衡。在强一致性与高性能之间在配额精度与系统复杂度之间在功能丰富性与上线速度之间永远存在权衡。我们的选择是基于业务现状做出最合理的折中。例如对于内部测试环境配额可以宽松甚至不做限制对于外部SaaS客户则必须严格、精确。最后这是一个持续迭代的过程。业务在变从简单对话到复杂Agent模型在变从GPT-3.5到GPT-4o计费模式也可能变。今天的配额系统设计需要为明天的扩展留好接口。我们目前就在将配额引擎从单纯的“Token计数器”向更通用的“资源信用点”系统演进以更好地适应多模型、多资源类型的混合调度场景。这套体系的搭建绝非一蹴而就但一旦建成它将成为LLM服务规模化、商业化道路上最可靠的后勤保障。当再次面对开篇那种“配额耗尽”的告警时你将不再慌张因为系统已经自动触发了预警、执行了熔断、并通知了相关人员。你需要的只是从容地打开Dashboard分析一下用量趋势然后决定是给这个租户临时增加配额还是建议他优化一下自己的Prompt。