1. 先搞懂“AI服务响应异常”和其他故障到底差在哪
去年秋天的一个凌晨,我正睡得不深,手机连着震了三次——线上告警群炸了:AI服务响应异常,P99延迟从平时的200ms一路冲到了10秒开外,紧接着报错率跟了上来。其实大多数运维或后端工程师面对这种“线上服务响应异常”的第一反应都是差不多的:先看一眼CPU、内存、网络,再翻一下日志,最后祈祷它自己恢复。但AI服务和普通Web服务不一样,同样的“响应异常”,背后的故障逻辑可以千差万别。你拿排查普通接口超时的思路去套AI服务,大概率会踩坑。
AI服务线上响应异常,本质上是一个复合型故障,它可能出在链路任何一个环节:模型推理、网关转发、缓存、向量检索、下游依赖、GPU显存、磁盘IO,甚至是你平时根本不会多看一眼的RAID阵列卡和网络软中断。这类问题的核心难点不像传统服务那样“一个报错对应一个原因”,更像一条流水线,中间任何一个工位出毛病,末端出来的产品都是坏的。而且AI服务的状态通常更“折磨人”——它不像普通接口那样干脆地报500,很多时候是CPU跑满、GPU显存吃紧、请求在队列里慢慢排队,但服务本身“看起来还活着”,只表现出一种让人抓狂的“慢”和“偶尔超时”。
正好最近整理过去大半年的线上故障记录,挑出这个“AI服务线上响应异常故障”主题,把完整的排查思路、实操过程,以及那些常规文档里不会写的坑,一次性说清楚。这篇内容适合正在做AI服务后端、推理平台、RAG应用的人参考,也适合那些只是“负责部署了一个AI模型接口”,但出了问题却不知道从哪里下手的运维和研发朋友。
在动手排查之前,我们要先把AI服务的响应链路画出来:客户端发出请求 → 网关/负载均衡 → 接入层(鉴权、限流) → 业务编排层(可能是Agent或RAG流程) → 模型推理服务(GPU/CPU) → 再往下还可能接向量库、缓存、外部第三方API → 最后原路返回。这条链路上任何一环变慢,都会表现为“AI服务响应异常”。所以排查的第一步永远不是“怀疑模型”,而是先确认真正卡在哪个环节。这也是我和很多同行聊下来,发现最容易犯的错误:一看到AI两个字,就总觉得是GPU或模型的问题,结果查了半天发现是Redis热Key把上游拖死了。
1.1 它比普通Web服务难排查在哪
普通Web接口的响应链路相对固定:请求进来,查个数据库或调个内部服务,拼一下返回值就出去了。数据库慢、接口慢、网络有波动,都能靠链路追踪(Trace)和日志快速定位。但AI服务是你把请求交给一个动辄几亿、几十亿参数的模型,它的处理是不透明的。你说不清它是在做矩阵计算、注意力机制,还是在解码生成token,更麻烦的是它还伴随流式输出、队列批处理、显存调度这些特殊机制。
再叠加一层“耦合性”:AI服务往往不是独立存在的。比如一个RAG问答服务,需要先做向量化,再去向量库里做相似度检索,最后把命中结果交给大模型生成答案。这中间任何一步慢,用户体感都是“AI变笨了、半天没反应”。而线上环境尤其喜欢在这种时候出幺蛾子——比如缓存命中率因为过期策略抖动突然下降、向量库因为写入和查询互相抢IO、GPU显存被其他任务占了导致推理任务排队。你拿传统“看日志+看监控”的排障思路去套,会发现日志里只有“超时”两个字,监控图上全是毛刺,完全不知道从哪一层下手。
另一个和普通服务差别很大的地方是资源瓶颈的动态性。普通服务出现CPU 100%,大概率是死循环、日志刷爆或者流量突增,思路很清晰。AI服务出现CPU 100%,可能是token生成过程中Python层的调度开销过大,也可能是视频抽帧、图像预处理的算法库吃满了CPU,甚至可能是并发进来后,多路视频解码同时跑,把CPU硬生生打满。同样是100%,处理方法完全不一样,这就需要更细粒度的定位手段。
1.2 响应异常现象分级:你的服务到底属于哪一种
“响应异常”这个描述太笼统,真到了线上,你必须在一分钟内判断出故障的“形状”。我习惯把现象分成四类,每一类对应的排查方向完全不同:
- 彻底不可用:服务直接报错、连接被拒、返回500/502/504。这类问题通常很“暴力”,要么是进程挂了、端口没监听,要么是网关层把实例摘掉了。方向:看进程存活、健康检查、依赖的基础组件(比如Redis、数据库)是否正常。
- 大面积超时:服务“活着”但响应极慢,请求堆积,报错率逐步上升。这类往往跟资源耗尽有关,比如CPU跑满、线程池排队过长、连接池耗尽、GPU任务排队。
- 偶发尖刺:大部分请求正常,但每隔一段时间出现一波小规模的超时或报错。这种最隐蔽,常见原因包括:缓存周期性失效导致的缓存穿透、定时任务和业务高峰撞车、GC停顿、网络抖动。
- 语义异常:请求能返回,但结果质量下降、回答变慢、截断、空回复等。这类容易被忽略,但同样属于“响应异常”。它往往和模型推理参数、上下文长度超限、显存不足导致的动态batch被压缩有关。
拿到故障通知后,先别急着开终端敲命令,先在脑子里或者纸上把这四个分类过一遍——现在是什么形状?然后再决定第一步去查什么。这个习惯可以帮你省掉至少一小时的盲目操作。
1.3 一套能用的排查框架:观察、定位、收敛
经过这么多轮“踩坑—熬夜—复盘”,我手里固定的排查框架其实只有四个字:观察、定位、收敛、止损。
- 观察:先描述现象,量化影响面。哪些用户受影响?错误率、延迟、吞吐的曲线是什么样的?故障是从哪个时间点开始的,那前后是否有发布、变更、定时任务?
- 定位:沿着链路逐层缩小范围。入口网关 → 接入层 → 业务编排 → 模型推理 → 基础设施。每层看三个东西:状态(进程/端口)、资源(CPU/内存/GPU/磁盘/网络)、日志与指标。
- 收敛:到了这一步,基本已经锁定了根因所在的组件或资源。接下来就是确认细节,比如是哪个进程、哪段代码、哪个配置、哪块磁盘。
- 止损:别想着先找到完美根因再处理。线上故障第一原则是恢复服务,手段包括切流、扩容、限流、重启异常实例、降级到缓存或兜底逻辑。
这套框架写出来好像很简单,真正难的是每一步的执行细节够不够扎实。下面我就把每一步里最容易踩坑、最多人搞不清楚的技术点逐个拆开讲。
2. 关键指标与核心细节:第一眼要看什么
很多人一接到“线上AI服务响应异常”的通知,第一件事就是跑到服务器上敲top,看CPU是不是100%。这没错,但太粗糙了。你至少得同时把这几类指标收齐:负载与CPU、内存与显存、磁盘与IO、网络、以及应用层指标(QPS、P99、错误率、队列长度、缓存命中率)。缺了任何一块,你都很可能在错误的坑里转圈。
2.1 CPU 100%不是结论,是入口
先说最经典的场景:线上服务器的CPU使用率达到100%了。标题里这个场景我相信很多人都遇到过,而且第一反应就是“是不是代码死循环了”。但放在AI服务的上下文里,原因可以非常多样:
- 推理请求的并发突增:流量峰值直接打满CPU,最典型的就是AI视频制作、批量抽帧、语音转写这类高计算密度任务。
- 热点缓存失效导致的缓存击穿/雪崩:缓存Key到期后,大量请求同时回源去打模型接口,推理开销直接把CPU压爆。这个场景在后面案例里我会重点讲,因为极容易误判成“代码bug”。
- 日志刷屏:业务代码里在高频路径上打日志,流量稍微上来一点,log写盘+格式化把CPU拖垮。
- 多路视频流实时处理:每个请求都在做视频解码、抽帧、编码,几路并发就能吃满一个高核数CPU。
- GC或内存置换:Java服务如果发生频繁Full GC,CPU也会表现得异常高,但实际上是内存管理在作祟。
定位这种问题,我一般直接按四步走:
第一步,top/uptime确认负载。别只看CPU百分比,还要看load average。如果load很高但CPU不高,多半在等磁盘IO或内存换页;如果load和CPU同时高才是真的在算。
第二步,用pidstat或top -Hp <pid>定位到具体线程。拿Python写的AI服务,典型的元凶是线程池里多个工作线程在疯狂执行模型推理;如果是Java服务,看GC线程占比和业务线程状态。
第三步,抓线程栈看热点。Java用jstack,Python用py-spy dump或faulthandler。这一步能把“CPU高”对应到具体代码函数上,比如你发现大量线程卡在image_processing.py某个去噪函数里,那问题就很明确了。
第四步,回到变更和时间线去对照。CPU是突然尖峰还是缓慢爬升?故障节点前是否有部署记录、参数调整、缓存过期策略变化?AI服务的很多CPU故障不是代码性能变差了,而是业务形态或配置变了。
提示:排查CPU问题,永远别只看单机。AI服务很少单机部署,你看到的这台100%,可能只是某个节点被负载均衡随机打到,而瓶颈其实在别处的共享资源上。我吃过一次亏:盯着一台CPU 100%的机器查了半天,最后发现是另外两台实例因为健康检查失败被摘了流,所有流量全压到剩下一台。
2.2 显存、内存和OOM问题
AI服务和普通服务最大的分水岭在GPU显存。GPU显存一旦不够,你的服务不会像普通内存OOM那样直接报错退出,更多时候是推理请求排队、超时,甚至进程直接挂掉,然后负载均衡反复重试,进一步加重故障。
这里先解释一个原理:GPU上的显存分配和释放,有一套“保留优先”的机制。CUDA为每个进程上下文保留显存,多进程共用一张卡的时候,如果其中一个进程显存泄漏或加载了过大的模型,其他进程可能直接拿不到显存。这就是为什么你的服务明明只用了3GB显存,但另外一路服务把整张卡的显存占了之后,你这边突然开始疯狂超时。
排查显存问题,标准动作是nvidia-smi看三块:显存占用、SM利用率(计算核心)、以及是否有进程在“反复申请释放”。SM利用率高但显存不高,说明计算密集,模型推理在做正经事,此时响应慢可能只是并发超了物理算力;SM利用率很低但显存几乎打满,说明模型加载/切换频繁,或者有大模型常驻占坑,大量推理被挤在狭窄的显存空间里反复换入换出——这种其实比单纯的计算瓶颈更伤性能。
如果你是自建推理服务,强烈建议为GPU监控单独配一条告警:显存使用率超过90%、SM利用率持续100%、Xid错误(GPU硬件/驱动错误)出现任意一条,都要立刻告警。很多公司只监控CPU和内存,GPU这块完全是盲区,直到线上炸了才手忙脚乱。
内存这块相对传统,排查思路和普通Java服务没差别:看free、vmstat,确认是否有大量swap换页,dmesg里有没有OOM Killer的记录。但我额外提醒一个AI服务特有的点:很多AI框架(尤其涉及视频、图像处理)会做共享内存或内存映射文件(mmap),模型权重加载时看起来物理内存没涨多少,但虚拟内存空间暴涨,如果容器或cgroup限制了内存上限,直接会被OOM Kill。这类问题常规的内存排查手段基本看不到,需要配合/proc/<pid>/maps和容器层的cat /sys/fs/cgroup/memory.max去看真实约束。
2.3 磁盘、网络与缓存:容易忽略的“慢”根因
资源问题里,最容易被一线工程师忽略的是磁盘IO和网络链路。但线上AI服务响应异常,往往就藏在这些犄角旮旯里。
磁盘这块,AI服务的模型权重文件动辄几GB到几十GB,启动时要加载、热更新时要重新加载,如果磁盘IO能力跟不上,模型从磁盘读入内存/显存的时间会被拉长数倍。更麻烦的是,很多服务器用的还是RAID阵列,你以为是全固态的存储,其实底层是两块机械盘做了RAID0,一旦其中一块盘出现预故障,整阵列的性能会断崖式下跌。
怎么判断磁盘有问题?先看iostat -x 1的%util和await。如果%util接近100%或者await明显高于基准值(SSD通常在几毫秒内),说明磁盘确实顶不住了。再往下定位到具体文件或进程,可以用iotop、lsof,还可以用strace -p <pid> -e trace=read,write看是否有进程在频繁读写大文件。
如果是RAID阵列卡(比如常见的LSI-9361-8i)下挂的RAID0,盘阵里某一块盘“预故障”,系统层面往往只有smartd会发一封邮件,硬件层面的告警却没接入监控。这种最坑,因为系统盘符(/dev/sda、/dev/sdb)和阵列卡里的物理盘槽位(Port)是两层映射关系。你看到系统里某块盘IO错误,要想准确找到是哪块物理盘该换,得用阵列卡的管理工具(storcli之类的)把/dev/sdb对应的Enclosure/Slot信息查出来再去机房换盘。这一整套对应的排查方法,我在后面“案例二”里会完整展开。
网络这块,一个非常典型的线上现象:ping内网或者外网地址,返回“一般故障(General Failure)”。这个问题在Windows系统上见得多,但Linux服务器上也有类似的现象。它根本不是什么玄学,核心原因通常是三层:网卡驱动异常导致的收包丢包、多条路由表冲突引起报文没有匹配出口、ARP解析出问题。排查思路依次是:用ip addr和ethtool看链路层是否UP、有没有错包;再ip route看路由表,检查是不是出现了多条默认路由;最后arp -n看看能否解析到网关MAC地址。这类问题对AI服务的杀伤力在于,它不直接报错,而是表现为“请求偶尔超时、重传增多”,如果你不抓tcpdump只看应用日志,很可能会以为是模型推理慢。
再单独说说缓存。线上缓存是AI服务性能的生命线,也是最容易在故障时“落井下石”的一环。前面提到的热点缓存失效,一旦发生,回源流量可能把模型推理服务直接打挂。我见过不止一次:前面做的一层针对“热门问题”的回答缓存,因为设置了统一的过期时间,结果在同一秒内集体失效,所有用户的查询同时打到推理服务,QPS暴增几十倍,服务瞬间响应异常。排查这类问题,要看缓存命中率曲线、热点Key分布,以及回源量突增的那一瞬间对应的是不是某个缓存Key批量过期。
3. 实操过程:一次完整的线上AI服务响应异常排查
理论说再多,不如真刀真枪走一遍流程。这里我挑一个真实度很高的典型场景:一次AI视频生成服务的线上故障,完整复盘排查过程。为什么选视频生成?因为它比纯文本AI服务复杂得多,涉及文件读写、视频编解码、GPU推理、缓存等多层组件,基本把能踩的坑都踩了一遍。
3.1 故障现象:P99从200ms飙到10s
那天下午三点多,业务方反馈“AI视频生成页面很卡,提交任务后一直转圈”,紧接着监控告警弹出:视频生成服务的P99延迟从200ms直接飙到10秒以上,错误率上升到8%,而且还在持续爬升。这个服务本来支持用户上传一段素材,后台做抽帧、风格化推理,再把结果合成视频返回。
从现象看,属于前面分类里的“大面积超时+偶发报错”混合形态。我们当时的部署形态大致是:Nginx做入口负载均衡 → 网关层做鉴权和限流 → 业务微服务A负责任务编排和素材存储 → 推理服务B(GPU节点,挂着风格化模型)接收A转发的任务并跑推理 → 任务结果回写对象存储,再通知前端轮询。
3.2 逐步收敛:top→线程栈→缓存热点→推理队列
拿到告警后的第一步,我们同时做了三件事:看监控大盘的整体曲线、看网关的QPS和错误率、看推理服务B所在GPU节点的资源状况。这一步很快发现两个线索:第一,网关层QPS并没有明显突增,排除流量洪峰;第二,推理服务B的CPU使用率冲到100%,但GPU的SM利用率只有30%不到,显存也没满。
这两个线索放在一起很反常——如果真是推理请求过多,GPU算力应该也高才对。现在CPU高、GPU闲,意味着瓶颈不在模型计算,而是CPU在做跟推理无关的工作,或者在调度上卡住了。
接下来我们做了两件事:一是用pidstat和py-spy抓推理服务进程的线程栈,看看CPU到底烧在哪个函数上;二是去业务微服务A的日志里查任务提交的耗时分布。线程栈的结果很有意思:大部分线程并不在模型推理代码里,而是卡在了一个叫video_decode的函数上,同时有大量线程阻塞在cache_get的Redis查询上。
顺着这两条线往下挖。“cache_get”对应的是一层“视频风格效果预览”的缓存,用于存放用户每次预览生成的中间结果。正常情况下命中率超过90%,但那天下午刚好有一个批量任务脚本在扫描并刷新所有素材的预览缓存,把所有Key的过期时间戳都集中到了同一批。缓存失效率瞬间从不到10%涨到70%以上,大量请求直接穿透缓存去打后端推理。
至于CPU烧在video_decode上,则是因为缓存失效后,所有请求都需要现场读取原始视频素材并抽帧,而那段素材正好是一段4K高码率视频,CPU编解码开销极大。平时有缓存挡住,解码只会发生一次;缓存失效后,每个请求都把解码逻辑重复执行一遍,CPU不炸才怪。这个场景完美解释了为什么“CPU 100%但GPU很闲”——根因根本不是模型推理,而是缓存穿透导致CPU承担了过量的视频解码任务。
3.3 止损与恢复:限流、扩容、热点缓存预热
根因清楚了,接下来就是止损。当时我们没有选择立刻改代码,而是按“恢复优先”的原则分四步操作:
- 第一步,临时调高网关层对视频生成接口的限流阈值,把这个接口的并发数压到正常峰值的80%,让服务先缓一口气,避免继续被穿透流量碾轧。
- 第二步,把推理服务B的CPU密集任务(视频解码)暂时切换成独立的一组低优先级的Worker节点,并把任务提交改为异步队列处理,短时间内允许任务排队而不是直接打爆CPU。这一步属于“换姿势顶住”。
- 第三步,手动触发热点缓存预热。将失效时间段内的高频素材Key,用一个脚本提前从对象存储拉取并生成中间结果,重新写回Redis缓存,并设置了合理的过期抖动(加随机秒数),避免下次再出现集体失效。
- 第四步,将异常批次任务脚本暂停,等业务低峰期再跑,并改成小批量分批执行。
整套操作做完大约花了二十分钟,P99从10秒回落到800ms左右,错误率归零。之后我们再花了一整天去优化代码逻辑:给视频解码层增加按素材内容哈希的本地磁盘缓存,避免同一条素材反复解码;给Redis缓存Key增加随机过期时间和逻辑过期时间双重保障;给批量刷新任务增加分布式锁,禁止在业务高峰时段执行。
这个案例里最值钱的一条经验是:AI服务的CPU 100%,未必是AI在算。下次你再看到类似现象,先确认一下CPU烧在哪个函数、GPU累没累到,再做结论。否则你会花两个小时去优化模型推理性能,结果发现完全是白忙。
3.4 高可用兜底:集群故障转移与自动切换
一次性的故障处理完了,但线上服务绝对不能建立在“下次碰运气”的基础上。AI服务要想稳定,必须有集群故障转移和自动切换机制兜底。这里多说一嘴“故障转移”的常见实现逻辑,因为它和各种防火墙IPS/WAF设备的“自动切换”流程是互相关联的。
常规负载均衡层的故障转移,靠的其实是“健康检查+摘流”这套机制。举个例子:你有三台推理节点,前面挂了负载均衡,负载均衡每几秒去探测每台节点的健康检查接口(/healthz)。如果某台节点因为GPU显存不足、进程卡死等原因连续几次探测失败,负载均衡会自动把它从转发列表里摘掉,流量只打到健康节点上。这个过程看起来是“自动切换”,原理其实就是健康检查的超时和失败次数阈值。
但这里有个极容易被忽略的坑:AI服务的健康检查接口,好多人写得过于简单,比如只返回一个{"status": "ok"},甚至直接返回200。这会导致什么后果?节点已经处于“半死”状态——进程还活着,端口也还通,但推理线程全部卡死或者请求都已排队超时。负载均衡探测它还是200,于是继续把流量打进来,用户看到的故障非但没有转移,反而因为请求堆积变得更加严重。
正确的健康检查姿势,是在/healthz里真正做一次最小化的依赖探测,至少要检查四个东西:
- 进程本身是否存活;
- 推理服务是否还能在几百毫秒内完成一次最基本的推理(比如一个空白输入);
- GPU显存是否还有余量;
- Redis、对象存储这些下游依赖是否可连通。
只有这样的健康检查,才能让负载均衡的“故障转移”在真正出问题时生效。我自己在给多个推理服务做高可用改造时,把这三个检查全部落进去之后,后续的故障自动切换才算是真正能用的。这也是很多“看起来配了高可用,但故障时依然全挂”的团队的共同盲区。
至于防火墙上IPS/WAF设备的高可用切换,原理上也是双机热备+心跳探测:两台设备之间通过心跳线互相监控,主设备故障后,备设备通过虚拟IP接管流量。这类切换的问题更常出现在三层网络上,比如VRRP协议里优先级配置、抢占模式设定之类。跟AI服务的直接关系不算太大,但如果你所在团队的网络链路上也叠了这些设备,遇到“整个网络出口间歇性丢包”的问题时,要考虑是不是它们在做切换时抢占了转发路径。
4. 典型故障实录:可能踩到的真实坑
除了上面那次典型的视频生成故障,过去一年里还有好几个值得记录的AI服务响应异常案例。我把它们整理成一份“坑位实录”,每个都附上现象、排查路径和最终解决方式。这些案例可能没有上面那个那么宏大叙事,但胜在常见,遇到一次就知道是怎么回事。
4.1 案例一:GPU显存OOM引发的服务“半死”状态
现象是:推理服务偶尔超时,但不是持续超时,大概每半小时出现一波。监控图显示,每次故障波峰前,GPU显存使用率都会爬到一个很高位然后骤降。
排查过程:最开始我们怀疑是模型推理本身的问题,后来发现波峰出现频率和业务流量没有强对应关系。直到有一次我们直接盯着nvidia-smi,才发现另一路定时任务(做离线批量推理)会在固定时间点启动,把显存几乎吃满,然后在任务结束时一次释放。这个过程中,在线推理服务因为拿不到足够显存,请求全部阻塞等待显存分配,表现出来就是周期性的响应变慢。
解法其实不复杂:给离线批量推理任务和在线服务做显存隔离,或者让离线任务严格限制在低优先级调度。但教训很深——如果当时GPU显存监控告警能早一点接上,我们根本不用在那盯了整整一天的nvidia-smi。现在很多推理框架支持显存的动态分配和抢占(比如TensorFlow的GPUOptions、PyTorch的gpu_mem_limit),但不同服务混部仍然需要非常小心,显存不是“反正它还会释放”,而是“你无法预测它什么时候释放”。
4.2 案例二:RAID0磁盘预故障导致模型加载卡死
现象是:服务日常挺正常,但每次重启后模型加载都要花比平时长好几倍的时间,重启后前几分钟内请求大量超时,且超时时间逐步缓解。一开始我们以为是模型文件太大、加载慢,后来发现情况在恶化:同样的模型,上周重启加载用时80秒,这周变成200多秒。
排查方向转到了磁盘。用iostat一测,发现%util持续接近100%,await长期在几千毫秒量级——这个数字对SSD来说已经是灾难级别。再用smartctl -a /dev/sdb一看,SMART信息里直接有“reallocated sector count”和“current pending sector”报警,盘已经处于预故障状态。更麻烦的是这根盘是RAID0阵列里的一员,而整个模型文件正好就在这个RAID0卷上。RAID0没有冗余,故障盘的每一次校验重试都会拖慢整条阵列的IO性能,模型加载自然慢得像爬。
换盘的定位过程也值得一说。系统层面看到的是/dev/sdb,但你要告诉机房的运维去换哪一块物理硬盘,就得用阵列卡管理工具(我们用的LSI-9361-8i卡,工具是storcli)把逻辑盘和物理槽位对应起来。命令大致是storcli /c0 /eall /sall show,输出里能看到每个物理盘对应的Slot编号和状态。配合smartctl的结果,能确认是哪一块Slot的盘该换。这里有个关键细节:RAID0明确不支持热替换,坏一块盘整个卷的数据全完蛋,所以遇到RAID0的盘有预故障告警,正确的做法是立刻备份数据,然后找时间窗口整体迁移到新阵列,而不是等着一根根换盘硬扛。
以此为教训,我们后来把所有模型文件、大索引文件从RAID0迁移到了RAID10或SSD单盘。AI服务的模型加载是个高吞吐、低延迟场景,RAID0看似能提升性能,但在可靠性上一票否决。这个案例也解释了热词里“LSI-9361-8i阵列卡、硬盘做的RAID0、目前预故障、怎么定位在系统下的盘符”这几句话背后的全部问题。
4.3 案例三:ping显示“一般故障”不是什么玄学
很多人一看到中等规模的AI服务第一反应是业务层。但实际上,AI服务里视频抽帧、图像处理、模型权重大量读取,对网络的要求一点不比计算低。这里说一个我在非AI项目里遇到过,但在AI服务上完全适用的问题:Linux服务器上ping内网或外网地址返回connect: Network is unreachable或者“一般故障”,并且服务对外表现是“能连上集群内部的其他机器,但访问外网API大量超时”。
排查这类问题,我自己有一套固定动作:
ip addr看网卡状态,是不是有接口down了;ethtool <网卡名>看是否有大量rderr、txerr、missed错误;ip route看默认路由是否存在、是否被多条等价路由弄乱;- 如果是多网卡机器,检查策略路由有没有出冲突,AI服务双网卡(业务网和内网存储网)是常态,路由表一旦出错,所有往对象存储或外部模型API的请求都会莫名其妙丢包。
曾经有一次,我们给一台推理节点临时加了一张网卡,结果操作系统自动添加的默认路由和原来的默认路由产生了冲突,导致一半的流量走了不可达的下一跳。那个机器表现为“服务时好时坏”,持续了一整天,最后用ip route看到两条default路由才破案。这类纯网络层面的问题,在AI服务故障里占比不算小,但非常容易被归因到“系统慢”上。
4.4 案例四:本地抽卡顺畅,线上制作卡到怀疑人生
这应该是最让业务方和研发都崩溃的一类问题:“我本地上跑同样的AI视频抽卡、风格化生成都特别流畅,怎么一发到线上制作就卡成PPT?”不是个例,线上反馈的用户还不少。
先说一下这个现象为什么会发生。本地“抽卡”是单用户单请求,一个人占着一整块GPU和整个CPU核。线上制作服务面对的是几十、上百并发,GPU显存要分给多人,CPU上有视频解码、请求调度、日志打印多个环节在抢资源,再加上网络传输、对象存储的读写延迟,模型推理这部分在整个响应链路里所占的权重会大幅降低。换句话说,本地流畅是因为你独享资源并且跳过了网络开销;线上卡是因为链路变长、资源被共享。
这类问题的解决思路也不是一句“加机器”就行。首先要通过压测明确线上服务的真实容量水位:单机能同时跑多少个抽帧任务、多少个推理任务,超过这个值,P95延迟会发生多少级的跳变。很多团队从来没做过推理服务的压测,直接上生产,结果一个活动流量峰值稍微偏大,服务就直接瘫痪。其次是优化链路:把视频解码和模型推理拆到不同的实例上部署,避免CPU高占用和GPU推理互相拖后腿;对大文件传输走内网存储而不是公网对象存储;对耗时任务采用异步化+消息队列削峰。
我见过的最典型的改善方案,是把整个AI视频制作的流程改成了“任务先提交、后台排队、前端轮询进度”,而不是用户全程同步等一个HTTP长连接。同步调用在本地演示没问题,但线上并发稍微一高,线程池就被占满,服务自然响应异常。改成异步之后,单机支撑的并发立刻上了好几个量级。这个思路对所有有CPU或GPU密集处理的AI服务都有参考价值。
4.5 故障排查速查表与工具箱清单
最后,把我平时用于排查AI服务线上异常的常用命令和工具整理成一张速查表,方便直接对照使用。这些都是经过实战验证的,按“资源→进程→链路→应用”分层组织:
| 排查内容 | 工具/命令 | 关键输出指标 |
|---|---|---|
| 系统负载与CPU | uptime、top、mpstat -P ALL 1 | load average、各核CPU us/sy/wa占比 |
| 定位高CPU进程/线程 | top -Hp <pid>、pidstat -t -p <pid> 1 | 线程PID、CPU占用率 |
| 抓Java线程栈 | jstack <pid> | 线程状态(RUNNABLE/BLOCKED)、热点方法 |
| 抓Python线程栈 | py-spy dump --pid <pid> | Python函数调用栈 |
| 抓进程系统调用 | strace -p <pid> -c | 系统调用耗时分布 |
| 磁盘IO | iostat -x 1、iotop | %util、await、读写吞吐 |
| RAID盘阵状态 | storcli /c0 /eall /sall show | 盘位Slot状态、逻辑盘健康 |
| 磁盘SMART信息 | smartctl -a /dev/sdX | reallocated/pending sectors |
| 网络链路与路由 | ip addr、ip route、ethtool、arp -n | 网卡状态、路由冲突、ARP解析 |
| 抓包分析 | tcpdump -i eth0 host <ip> -w file.pcap、Wireshark | TCP重传、握手异常 |
| GPU状态 | nvidia-smi、nvidia-smi dmon -s pucvmet | 显存、SM利用率、温度、Xid错误 |
| 内存与Swap | free -h、vmstat 1、dmesg | grep -i oom | 可用内存、si/so换页、OOM记录 |
| 应用延迟与错误 | 网关/APM大盘(如Prometheus+Grafana、SkyWalking) | QPS、P99/P95、错误率曲线 |
| 缓存命中 | Redis的INFO stats、keyspace、热点Key分析 | hits/misses比例、过期Key分布 |
这张表不是让你故障时从头到尾都敲一遍,而是根据前面判断的现象分类,挑对应的工具看。熟练之后,这套动作可以在十分钟内收敛到具体根因。
说到底,AI服务线上响应异常,十次里有八次不是什么高深的分布式一致性难题,而是基础的资源耗尽、缓存失效、网络配置、磁盘损坏这些“传统问题”。区别只在于它们发生在AI服务的链路上,容易被一层“模型很玄”的滤镜挡住视线。先把这些基础问题一个个排除干净,再往模型和算法层面深挖,这个顺序永远不会错。按照这个思路走,很多故障其实比你想象的要朴素得多。