• 微信
    咨询
    微信在线咨询 服务时间:9:00-18:00
    纵横数据官方微信 使用微信扫一扫
    马上在线沟通
  • 业务
    咨询

    QQ在线咨询 服务时间:9:00-18:00

    选择下列产品马上在线沟通

    纵横售前-老古
    QQ:519082853 售前电话:18950029581
    纵横售前-江夏
    QQ:576791973 售前电话:19906048602
    纵横售前-小李
    QQ:3494196421 售前电话:19906048601
    纵横售前-小智
    QQ:2732502176 售前电话:17750597339
    纵横售前-燕子
    QQ:609863413 售前电话:17750597993
    纵横值班售后
    QQ:407474592 售后电话:18950029502
    纵横财务
    QQ:568149701 售后电话:18965139141

    售前咨询热线:

    400-188-6560

    业务姚经理:18950029581

  • 关注

    关于纵横数据 更多优惠活动等您来拿!
    纵横数据官方微信 扫一扫关注官方微信
  • 关闭
  • 顶部
  • 您所在的位置 : 首页 > 新闻公告 > 云服务器接口请求失败原因分析?

    云服务器接口请求失败原因分析?

    去年冬天的一个晚上,一个做社区团购的朋友阿杰给我打来电话,背景音里全是键盘敲击声和此起彼伏的电话铃声。他说他们的微信小程序突然出了大问题,用户下单的时候一直转圈圈,最后提示网络开小差了,请稍后再试。技术团队排查了两个多小时,重启了云服务器,检查了数据库,甚至回滚了最近的代码版本,问题依然存在。最诡异的是,有的用户能正常下单,有的用户死活不行,同一个用户有时候成功有时候失败,没有任何规律。阿杰说他们所有人都盯着监控大屏,CPU正常、内存正常、带宽正常,但就是找不出毛病在哪儿。

    我跟阿杰说,接口请求失败这件事,表面上看起来是后端的问题,但实际上它的原因可能藏在任何一个环节,从前端发起到网络传输,从服务器处理到数据库查询,甚至到第三方服务的响应。你不能只盯着服务器看,要一条链路一条链路地去排查。那天晚上我帮他梳理了一套排查思路,大概花了四十分钟,终于定位到了问题所在。今天我就把这套思路整理出来,希望能给遇到类似困境的朋友一些参考。

    我把接口请求失败的原因分成几个大的层面,从客户端开始,一层一层往服务器深处走,每一层都有可能出问题。

    第一个层面是客户端本身的问题。很多人一看到接口报错就直奔服务器看日志,但其实有些时候服务器根本就没收到请求。为什么没收到,可能是因为客户端网络不通,比如用户正好在地铁里信号不好,或者连接了某个需要登录认证的公共WiFi但还没通过认证。也可能是前端代码的问题,比如请求的URL写错了地址,或者请求方法用错了,该用POST的地方用了GET。还有可能是前端在发请求之前做了一些前置校验,比如参数校验没通过就直接拦截了请求,根本没有发出去。这些都是客户端层面的问题,服务端的日志里不会有任何记录。怎么判断是不是客户端的问题呢,很简单,用别的工具模拟同样的请求去调用你的接口,比如用命令行工具或者专门的API测试软件。如果模拟请求能成功,那说明问题大概率出在客户端,如果模拟请求也失败,那就继续往下排查。

    阿杰当时就让他们的测试人员用命令行工具直接调用下单接口,结果发现命令行调用是正常的,接口返回了正确的数据。这就说明云服务器本身没有问题,问题出在客户端到服务器的中间环节或者前端代码本身。他们后来发现是微信小程序的一个基础库版本升级导致了一个兼容性问题,只有在特定版本的微信上才会触发,所以表现得很随机。

    第二个层面是网络连通性问题。如果模拟请求也失败了,那就要看请求有没有到达你的云服务器。怎么看呢,最简单的方法是在云服务器上实时查看访问日志,同时用另一个终端去发起请求,看日志里有没有出现新的记录。如果日志里完全没有这个请求的记录,说明请求在半路上就丢了。丢在哪里了呢,可能是用户的本地网络问题,可能是运营商在中间做了某些限制,也可能是云服务商的安全策略把请求拦截了。这里要特别留意云服务商提供的安全组和网络访问控制列表,这些规则是在请求到达你的操作系统之前就会被执行的,如果你忘记放行某个端口,或者把某个IP段加入了黑名单,请求根本进不来。还有一种情况是云服务器前面挂了负载均衡器或者Web应用防火墙,这些设备也可能成为请求被拦截的地方。排查这类问题的方法是逐层检查,先看安全组,再看负载均衡器,再看WAF,最后看服务器本身的防火墙。

    我处理过一个案例,一家做直播的公司,他们的接口在某个地区总是请求失败,其他地区都正常。折腾了好久发现是那个地区的运营商把一个特定的端口给屏蔽了,刚好他们的接口用的是那个端口。解决办法就是换了一个常用端口,问题就解决了。这个案例说明,有时候问题不在你这边,但你要有能力定位到是哪一段出了问题,才能有针对性地去解决。

    第三个层面是域名解析问题。如果你的接口是通过域名调用的,那么域名解析这一步也可能出岔子。比如你在前端代码里写的是某个域名,但这个域名解析出来的IP地址不是你云服务器的IP,或者解析出来的IP地址是对的但是DNS解析过程超时了,请求根本发不出去。这种情况的表现是,用IP地址直接调用接口能成功,但用域名调用就失败。排查方法是在客户端的环境里手动解析一下你的域名,看返回的IP是否正确,解析耗时是否在正常范围内。如果发现解析出来的IP不对,那就是域名解析配置的问题,去域名注册商或者DNS服务商那边检查解析记录。如果解析出来的IP是对的但经常超时,那可能是DNS服务器的响应速度有问题,考虑换一个更稳定的公共DNS服务。

    第四个层面是服务器负载过高。有时候接口失败不是因为出错了,而是因为服务器太忙了,来不及处理你的请求。当服务器的并发连接数超过它的处理能力时,新的请求可能会被丢进等待队列,如果队列太长或者等待时间太久,客户端那边就会超时断开连接。这种情况的表现是,接口偶尔成功偶尔失败,失败的时候响应时间特别长。怎么确认是不是负载问题呢,登录云服务器看系统负载平均值,看CPU使用率,看内存占用率,看网络连接数。如果这些指标都很高,说明服务器确实累了。解决办法可以是优化代码减少资源消耗,也可以是在云平台上对服务器进行配置升级,还可以增加服务器数量做负载分担。

    阿杰那次排查到最后,发现他们的问题跟负载没关系,但他们上个月确实出过一次负载导致接口失败的事故。那次是因为一个运营活动没有提前通知技术团队,活动开始后流量突然暴涨了十倍,云服务器瞬间被打满。从那以后他们养成了一个习惯,每次做活动之前都要做流量预估,然后提前扩容。

    第五个层面是程序代码的运行时错误。这是最常见的接口失败原因,也是最容易定位的。你的代码里有bug,处理请求的时候抛出了异常,没有捕获也没有妥善处理,导致接口直接返回了500状态码或者干脆崩溃了。这类问题在日志里会留下非常明确的线索,错误类型、错误信息、出错的文件和行号,基本上看一眼就知道哪里出了问题。但有时候代码错误的表现会伪装成别的样子,比如你调用了另一个服务,那个服务返回的数据格式跟你预期的不一样,你解析的时候报错了。或者你查询数据库的时候没做空值判断,查询结果为空的时候直接用了某个字段的属性,就导致了空指针异常。这类错误需要在代码里加更多的防御性判断,不能假设外部数据永远都是正确的。

    第六个层面是依赖服务的故障。现在的应用很少有完全独立运行的,多半会依赖数据库、缓存、消息队列、对象存储,或者调用第三方的API。任何一个依赖服务出了问题,你的接口都可能失败。比如数据库连接池被耗尽了,新的请求拿不到数据库连接,接口就会超时或者报错。比如Redis挂了,你的代码里没做降级处理,读不到缓存就直接抛异常。比如你调用的第三方支付接口临时不可用,你的接口没有设置超时时间,就一直卡在那里等。怎么排查这类问题呢,在你的代码里给每一个依赖调用都加上详细的日志,记录调用的耗时和返回结果。这样当接口失败的时候,你能很快地看出来是在哪一步卡住了。另外还要给你的所有依赖服务配置健康检查,当某个依赖不可用的时候,你的接口可以快速失败而不是长时间等待。

    我讲一个印象很深的案例。有个做天气查询的网站,他们的接口平时都很稳定,但一到夏天就频繁超时。查了很久才发现,他们的天气数据是从国外一个免费API获取的,而那个免费API在夏季访问量最大的时候经常响应缓慢。他们的代码里没有设置超时时间,用的是默认值,结果就是每个请求都要等两分钟才断开。夏天的时候并发高,等待的请求把服务器的线程池全部占满,新的请求进来就只能排队或者被拒绝。解决办法是在调用第三方API的时候设置一个合理的超时时间,比如三秒钟,三秒内没有响应就放弃这次调用,返回一个友好的提示给用户,而不是让用户一直转圈圈。

    第七个层面是数据相关的问题。有些接口平时跑得好好的,突然某一天开始频繁失败,可能是因为数据量增长到了某个临界点。比如一个查询接口原本全表扫描只扫描一万条数据,很快就能返回结果。半年后数据量增长到了一百万条,同样的查询语句就可能需要几十秒甚至几分钟,客户端早就超时了。这种情况需要在数据库层面做优化,加索引、改写查询语句、做分页、做数据归档。还有一种情况是数据本身出了问题,比如某个必填字段出现了空值,或者某个关联表的数据被误删了,导致接口的逻辑走不下去。这类问题往往需要结合数据库的慢查询日志和业务日志来分析。

    第八个层面是环境配置的差异。很多接口在测试环境一切正常,部署到生产环境就出问题。这往往是因为两个环境的配置不一样,比如测试环境连的是测试数据库,生产环境连的是生产数据库,生产数据库的密码在配置文件里写错了。或者测试环境用的是HTTP,生产环境强制用了HTTPS,但证书配置有问题。或者测试环境没有防火墙限制,生产环境有严格的IP白名单,你的代码里某个回调地址没有被加入白名单。排查这类问题的最佳实践是,在测试环境和生产环境使用完全相同的部署流程和配置管理工具,确保两个环境的差异是可以被追溯和理解的,而不是靠某个人手动修改某个配置文件。

    阿杰他们那个下单接口失败的最终原因是什么呢,我们排查到第六层的时候发现了线索。他们的下单流程里调用了风控服务,而这个风控服务是第三方提供的。那天晚上风控服务的提供方在做机房迁移,有两个小时的窗口期服务不稳定,有的请求能过有的不能过。他们下单接口代码里对风控服务的调用设置了一个重试机制,但重试的时候没有做幂等性保护,导致同一个订单在风控服务那边被创建了多次,然后风控服务返回了重复请求的错误,下单接口收到这个错误之后没有正确处理,直接把错误返回给了前端。前端看到这个错误就显示网络开小差了,但实际上后端并没有出问题。后来他们修改了代码,把对风控服务的调用改成了异步模式,下单请求不等待风控结果就直接返回处理中,这样即使风控服务临时抖动也不会影响用户的下单体验。

    经过这么多次接口故障的排查,我总结出一套适合自己的定位方法,这里分享给大家。当接口请求失败的时候,不要急着去看代码,先确定问题的影响范围,是个别用户还是所有用户,是特定接口还是所有接口,是偶发还是必现。然后用模拟工具绕过客户端直接调用接口,判断问题出在客户端还是服务端。接着查看云服务器的访问日志,确认请求是否到达。如果请求到达了,再看应用日志,找到具体的错误堆栈。如果日志里没有明显的错误,那就检查依赖服务是否正常,检查数据库连接和查询性能。最后,如果所有技术层面的排查都没有结果,考虑一下配置差异和环境因素。

    接口请求失败这件事,就像医生看病一样,你不能头疼医头脚疼医脚,要系统地去看待整个请求链路。前端、网络、服务器、代码、数据库、依赖服务,每一个环节都有可能出问题,而你的任务就是用一个系统的方法论,把出问题的那个环节找出来。



    最新推荐


    微信公众帐号
    关注我们的微信