Xamarin调Heroku上Flask接口随机报Connection reset by peer排查
问题背景
现有一套基于Flask框架开发的Web API,以及配套调用该API的Xamarin.Forms移动端应用,此前数月系统运行始终稳定,自一周前开始突发异常:移动端尝试访问Web API时会随机抛出Connection reset by peer错误,具体异常信息如下:
Read error: ssl=0xd6269d18: I/O error during system call, Connection reset by peer
该异常为随机触发,无固定复现路径:部分场景下接口调用可正常完成,部分场景下会触发报错。
已确认的实现与现象
客户端侧
客户端使用System.Net.Http.HttpClient发起接口请求,核心请求代码如下:
public async Task<string> GetClientData(string token) { HttpResponseMessage response = await httpClient.GetAsync(server_url + Resx.Urls.get_route + "?token=" + token); return await response.Content.ReadAsStringAsync(); }
服务端侧
服务端部署在Heroku平台,存在一个典型特征:即便客户端抛出上述连接异常,Heroku的运行日志仍显示对应请求已被正常处理,返回状态码为200。服务端示例接口路由代码如下:
@app.route('/get', methods=['GET']) def get(): clients = get_users() # database call token = request.args.get('token') for c in clients: if(c.token == token): return c.to_json() abort(400) # no client with such token
交叉验证结果
编写与移动端调用逻辑完全一致的Python测试脚本调用接口,多次测试均未复现该异常。
根因排查方向
该异常的根因基本可以排除Flask业务代码问题,按排查优先级从高到低排序如下:
- 优先排查Heroku平台侧网络中间层的策略变更:Heroku前置的负载均衡、SSL终止节点如果在一周前调整了空闲连接超时时间、连接池回收规则,会出现TCP连接被中间层单方面关闭,但客户端仍复用失效长连接发请求的情况,正好符合当前现象:服务端应用已经正常处理完请求返回200给负载均衡,但负载均衡回传响应给客户端的链路因为连接已失效触发重置,同网络路径下的短连接测试脚本因为不复用长连接,很难复现问题。
- 其次排查Xamarin.Forms侧HttpClient的运行配置:Android平台下默认的原生HttpClient实现存在长连接复用的已知兼容问题,如果请求没有手动配置
Connection: close头,也没有针对网络层异常加入重试逻辑,客户端连接池缓存的已被远端关闭的连接就会随机触发该类报错。可以先临时给所有请求加上Connection: close头测试,如果异常消失即可确认是长连接复用导致的问题。 - 最后排查Flask服务的服务层配置:确认Gunicorn/使用的WSGI服务器是否配置了过短的连接超时、是否启用了激进的连接回收策略,这部分概率极低,因为同逻辑的Python脚本调用未复现问题。
内容的提问来源于stack exchange,提问作者user13595734
相关产品推荐
相关产品推荐

