1、案例分享;
2、原理汇总;
3、解决方式;
4、总结;
1、背景
某部分客户业务使用cos的node.js的sdk来进行上传下载等操作,近期客户端偶尔触发上传文件报错{ error: { code: 'ECONNRESET' } } 的异常。
那么此问题的到底从何而来,又该如何解决?
经了解:
业务的使用分块上传对象,且通过onProgress查看上传文件的进度回调函数;
const COS = require('cos-nodejs-sdk-v5');
let cos = new COS({
getAuthorization: function (options, callback) {
callback({
TmpSecretId: cosconfig.obj.credentials.tmpSecretId,
TmpSecretKey: cosconfig.obj.credentials.tmpSecretKey,
XCosSecurityToken: cosconfig.obj.credentials.stsToken,
ExpiredTime: cosconfig.obj.expiredTime
})
}
})
cos.sliceUploadFile({
Region : cosconfig.obj.region,
Bucket : cosconfig.obj.bucket,
Key : destPath,
FilePath: filepath,
onProgress: cosprogress
}, coscallback)
2、排查:
1、requestid以及文件具体url信息查看对应cos的上传历史记录;
2、但是通过上传的onProgress来看进程是从0%到1%有发送数据的,并非长时间等待;
3、通过过滤多次上传log以及咨询确认我们nodejs的保持长连接的keep alive的特性;
服务端在60s内保持tcp的连接通路,此阶段没有发送数据,就会reset断掉连接,但是客户端在收到断开的tcp信息前,发起了http的新请求,导致服务端拒绝了请求;
3、原因:
总结一下就是:
在长连接的前提下,服务端先于客户端关闭了 TCP,而客户端此时还未同步状态,所以存在一个错误的暂态(客户端认为 TCP 连接依然在,但实际已经销毁了)
4、措施:
客户业务形态侧,可根据sdk中的参数自行调整。根据业务量级场景来评估调整:
这里涉及到状态机制里竞争形态:
ECONNRESET
。总结一下就是:
服务端先于客户端关闭了 TCP,而客户端此时还未同步状态,所以存在一个错误的暂态(客户端认为 TCP 连接依然在,但实际已经销毁了)
正常的tcp的连接和keep alive
因为静默导致超时断开连接的状态
既然问题的原理和源头来源清楚了,那也就需要从根本上来进行规避掉;
但是由于长连接一系列保持的长期会话的特性和优点,使得我们不得不去借用,所以我们或许可采用的是去利用现状的bug特性,而不是去完全避开它;
彻底的去避开它,直接使用短链接,即keep-alive的false关闭掉;
客户端先于服务端关闭 TCP 连接
把客户端的 keep-alive
超时时间设置得短一些 < 短于服务端的超时时间;
这样就可以保证永远是客户端这边超时关闭的 TCP 连接,消除了错误的暂态。
优点:
可以较大程度的既解决规避了这个问题,又保持了keep alive长连接的业务特性。
缺点:
实际生产环境中却是没法 100% 解决;
因为即使把客户端超时时间缩短到一定的数值,因为中间公网路由的网络延迟的存在,始终无法保证所有的
客户端的 keep-alive
超时时间 + 网络延迟的时间 都小于服务端设置的值;
如果把客户端超时时间设置得太小,又失去了keep alive的长连接保持的意义。
具体配置方法可参考:
服务端在response header中告诉客户端的头部的超时时间的信息
可参考:https://zhuanlan.zhihu.com/p/34147188
重传重试
在识别到对应错误码后,且是复用了同样的tcp连接,现在最新的node.js已经可以通过req.reusedSocket来识别到是否复用了同一个连接。
优点:
在之前两种方法的基础上,可以最大程度的确保业务的正确性,重试解决现网存在的此类所有的报错问题;
缺点:
重试消耗少部分性能;
作为经典的cs架构请求方式,浏览器自然也会遇到这个问题,但是我们却很少发现有浏览器会报错408的错误状态码;
由于浏览器为了规避此类问题,直接采用了感官无法感知到的优雅处理方式:
直接进行重试自动重试新连接中的其余请求,以便用户完全不知道发生的潜在故障
可参考:https://stackoverflow.com/questions/42631273/how-do-browsers-handle-http-keepalive-race-condition
后续可参考以上方法方式解决此类报错。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。