上周二晚上,我经历了入职以来最漫长的一夜。
事情是这样的:我们公司做了一个AI写作平台,接入了多家大模型的API,用户可以选择不同的模型生成内容。为了应对大模型厂商的价格战,我们做了一个智能路由功能,自动选择当前最便宜的可用模型。结果这个功能出了一个Bug,导致线上服务异常,我排查了整整一夜。
这篇文章,我想把这次排查的过程完整地记录下来,从发现问题、排查思路到最终定位根因,聊聊大模型时代的运维踩坑经验。希望能给做类似系统的朋友一些参考。
问题出现
那天晚上10点多,我正准备睡觉,手机突然响了,是运维群里的告警:API错误率飙升,从平时的0.1%涨到了15%。
我一下子清醒了,赶紧打开电脑登录监控系统。错误率确实在涨,而且主要集中在AI生成接口。用户反馈也来了:"生成内容失败""一直转圈""选了模型但没反应"。
我先看了一下服务状态,服务本身是正常的,CPU和内存都不高,数据库也没问题。那问题出在哪里呢?
我查了一下错误日志,发现大部分错误是超时错误,调用大模型API的时候超时了。还有一部分是价格计算的错误,返回了异常的价格。
超时这个还好理解,可能是某个大模型服务商的接口不稳定。但价格计算错误就奇怪了,这个功能一直很稳定,怎么会突然出错?
我先做了紧急处理:把智能路由功能关掉,强制用户只能手动选择模型。这样虽然体验差一些,但至少服务能恢复正常。关掉之后,错误率果然降下来了,用户反馈也少了。
但问题的根源还没找到,智能路由是我们的核心功能,不能一直关着。我开始了漫长的排查。
第一轮排查:以为是模型服务商的问题
一开始,我以为是大模型服务商的接口出了问题。
因为最近大模型价格战打得很激烈,几家厂商轮流降价,API的调用量暴增,服务商的服务器可能扛不住了。我查了一下各个模型的调用情况,发现确实有几家的响应时间比平时长了不少。
但价格计算错误怎么解释呢?价格计算是我们自己的逻辑,不依赖服务商的接口。除非是服务商返回的价格信息有问题。
我查了一下价格同步的逻辑。我们的系统会定时从各个服务商的API获取最新的价格,存在本地缓存里,智能路由根据这个缓存的价格来选择最便宜的模型。
我看了一下缓存里的价格数据,发现了一个奇怪的现象:有几个模型的价格变成了0,还有几个变成了负数。价格为0或者负数,智能路由就会优先选这些模型,但实际上这些模型的接口可能不可用或者有其他问题,导致调用失败。
为什么价格会变成0或者负数呢?我查了一下价格同步的日志,发现最近一次同步的时候,有几家服务商返回的价格数据格式变了。
原来,大模型价格战期间,有几家服务商调整了API的计费方式。之前是按token计费,返回的是每1000token的价格。现在有几家改成了按次计费,或者按输入输出分别计费,返回的字段也变了。我们的价格同步脚本还是按照旧的格式来解析,解析失败的时候,就把价格设成了默认值0。
还有一家更坑,他们把价格的单位从"美元/1000token"改成了"美元/1M token"(也就是100万token),但字段名没变。我们的脚本直接拿过来用,没有做单位转换,导致价格变成了原来的千分之一,几乎等于0。
找到这个原因之后,我赶紧修复了价格同步脚本,加上了新的计费方式的支持,也加了单位转换。然后手动把缓存里的价格数据修正了。
本以为问题解决了,结果重新打开智能路由功能之后,错误率又涨了。看来还有其他问题。
第二轮排查:发现了并发问题
价格的问题修复之后,超时的问题还是存在。
我仔细看了一下超时的请求,发现一个规律:超时的请求,都是调用同一个模型的。这个模型因为价格被错误地设成了0,被智能路由大量选中,调用量暴增,超过了我们在该服务商那里的并发限制,导致大量请求排队超时。
原来如此!价格错误导致路由偏向了这个模型,这个模型的调用量瞬间翻了几十倍,超过了并发限制,后面的请求就都超时了。
我赶紧调整了这个模型的并发限制,同时给智能路由加了一个保护机制:每个模型的调用量不能超过并发限制的80%,超过之后就自动切换到下一个便宜的模型。
加了这个保护之后,超时的问题缓解了一些。但还是有少量错误,而且我发现了一个新的问题:有些请求的价格计算还是不对,虽然不是0或者负数了,但和实际价格有偏差。
我又查了一下,发现是缓存的问题。价格同步脚本修复之后,新的价格数据写入了缓存,但缓存有过期时间,旧的错误数据还没过期,新的数据没写进去。而且我们用的是分布式缓存,有多个节点,数据同步有延迟,有些节点还是旧数据。
我把缓存全部清掉,强制重新同步了一次价格。这次价格数据终于正确了。
第三轮排查:还有一个隐藏的Bug
价格和并发的问题都解决了,我以为终于可以睡觉了。结果重新打开智能路由之后,又出现了新的错误:有些请求返回了"模型不存在"的错误。
这就奇怪了,模型列表是从服务商的API获取的,怎么会不存在?
我查了一下,发现有一家服务商,在价格战期间下线了几个旧的模型,推出了新的模型。但我们的模型列表缓存还是旧的,里面包含了已经下线的模型。智能路由在选择的时候,可能选到了已经下线的模型,调用的时候就报错了。
还有一家服务商,把模型的名字改了。比如原来叫"gpt-4-turbo",现在改成了"gpt-4.1",但旧名字还能用一段时间。我们的系统里存的是旧名字,调用的时候虽然能成功,但价格是旧价格,和新价格不一样。
这些问题,本质上都是因为大模型价格战期间,服务商的变化太频繁了:降价、改计费方式、上下线模型、改模型名字,而我们的系统没有及时跟上这些变化。
我又花了几个小时,把模型列表的同步逻辑也重构了一下:增加了模型状态的检查,下线的模型自动标记为不可用;增加了模型别名的映射,旧名字自动映射到新名字;增加了变化检测,服务商的模型列表和价格有变化的时候,自动告警通知运维人员。
全部改完之后,已经是早上6点多了。我重新打开智能路由功能,观察了半个小时,错误率降到了正常水平,用户也没有新的反馈了。
根因分析
排查完之后,我做了一个根因分析,发现这次故障的根本原因不是某一个Bug,而是一系列问题叠加的结果。
第一个原因是,对大模型服务商的变化缺乏应对机制。价格战期间,服务商频繁调整价格、计费方式、模型列表,而我们的系统还是按照之前稳定时期的逻辑来设计的,没有考虑到这些快速变化的情况。
第二个原因是,数据同步的容错性不够。价格同步脚本解析失败的时候,直接把价格设成了0,而不是保留上一次的正确价格或者标记为异常。一个错误的价格数据,直接导致了整个路由系统的异常。
第三个原因是,智能路由缺少保护机制。路由只考虑了价格,没有考虑并发限制、模型可用性、服务质量等因素。一个模型价格异常低,就会被大量调用,导致雪崩。
第四个原因是,缓存策略不合理。缓存的过期时间太长,数据更新不及时;分布式缓存的同步延迟,导致不同节点的数据不一致。
第五个原因是,监控和告警不够完善。价格数据异常的时候,没有及时告警,等到用户反馈、错误率飙升的时候才发现。如果能在价格数据变成0的时候就告警,就能在故障发生前处理掉。
后续改进
这次故障之后,我们做了一系列的改进,避免类似的问题再次发生。
第一,重构了价格和模型同步系统。不再是简单的定时拉取,而是增加了数据校验、异常检测、容错处理。解析失败的时候保留上一次的正确数据,同时告警。价格为0、负数、异常波动的时候,自动标记为不可用并告警。
第二,完善了智能路由的算法。不再只看价格,而是综合考虑价格、响应时间、成功率、并发限制、模型可用性等因素,给每个模型打分,选择综合得分最高的。同时增加了熔断机制,某个模型的错误率超过阈值的时候,自动熔断一段时间。
第三,优化了缓存策略。缩短了价格和模型数据的缓存时间,增加了主动更新机制(服务商有变化的时候通过webhook通知)。分布式缓存增加了一致性校验,确保各个节点的数据一致。
第四,完善了监控和告警。增加了价格数据异常告警、模型可用性告警、调用量异常告警、并发限制告警。关键指标有异常的时候,及时通知运维人员,不要等到用户反馈。
第五,建立了服务商变更跟踪机制。安排专人关注各大模型服务商的动态,价格调整、模型上下线、API变更等,提前做好准备。同时和服务商建立了直接的沟通渠道,有变化的时候能提前通知。
第六,做了混沌工程演练。模拟各种故障场景(价格异常、模型下线、服务商宕机、并发超限等),测试系统的容错能力,发现问题及时修复。
一些经验和教训
这次通宵排查,让我对大模型时代的系统运维有了一些新的认识。
第一个教训是,不要假设外部依赖是稳定的。大模型服务商还在快速发展和变化中,价格、模型、API都可能随时变。系统设计的时候,要假设外部依赖会变,做好容错和降级。
第二个教训是,数据质量是系统的生命线。智能路由这种系统,输入数据错了,输出肯定错。一定要做好数据校验,异常数据不能直接用,要有兜底机制。
第三个教训是,保护机制比功能更重要。一个功能再好用,如果没有保护机制,出问题的时候就是灾难。限流、熔断、降级、超时,这些机制一个都不能少。
第四个教训是,监控要覆盖全链路。不只是监控服务的CPU和内存,还要监控业务数据(价格、模型列表)、外部依赖(服务商API状态)、用户体验(错误率、响应时间)。越早发现问题,损失越小。
第五个教训是,复杂系统要有灰度发布的能力。智能路由这种核心功能,更新的时候要灰度发布,先给一小部分用户用,观察没问题再全量。这次如果有灰度,就不会影响所有用户了。
第六个教训是,故障处理要有预案。平时要做好故障演练,遇到问题的时候知道怎么紧急处理、怎么降级、怎么恢复。这次我能快速关掉智能路由恢复服务,就是因为之前做过降级预案。
写在最后
那次通宵排查之后,我睡了一整天。醒来之后,看到系统稳定运行,用户没有再反馈问题,觉得这一夜的辛苦还是值得的。
大模型价格战还在继续,服务商的变化还会不断出现。作为技术人员,我们能做的就是把系统做得更健壮、更有弹性,在变化中保持稳定。
每一次线上故障,都是一次学习的机会。这次故障让我对分布式系统、数据质量、容错机制、监控告警有了更深的理解。这些经验,比任何书本上学到的都更深刻。
如果你也在做大模型相关的系统,希望我的经历能给你一些参考。如果你也有类似的踩坑经验,欢迎在评论区交流。
最后说一句:运维不易,且行且珍惜。希望大家都能少值班、少通宵,系统稳定运行。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录