-
Notifications
You must be signed in to change notification settings - Fork 576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
getStream dont use keepalive feature #40
Comments
Teambition 文件服务 https://striker.teambition.net/ 使用 toa 编写。OSS 是其存储源之一。完善了日志分析服务之后,我们发现该服务有一定概率出现异常: {"name":"ResponseError","message":"socket hang up (req \"error\")} 经过 @orangemi 同学的一番 debug 后终于找到了原因: 我们使用了 oss sdk 的 var resp = yield store.getStream(uri)
this.body = resp.stream 但 toa 中有这样一个机制(koa 同样有)
也就是当上游数据源是 stream 时,response 结束后会强制 destroy 该 stream。 这回带来什么问题呢?因为 oss sdk 的 agent 默认会启用 那么我们是不是可以关闭 oss sdk 的 keepAlive 特性?我觉得这样不太好,毕竟 keepAlive 还是能节约很多开销的。所以目前采取的方案是修改了 toa: if (typeof val.pipe === 'function') {
onFinished(this.res, function (err) {
// destroy stream only if error occured
if (err) destroy(val)
})
} 只有当 response 异常时才主动 destroy 上游的 stream,毕竟正常情况都是 stream 结束后触发 response 的结束,是没必要强行 destroy 该 stream 的。 大神们怎么看? @fengmk2 @dead-horse |
this.res error 后,去 destroy oss 的 stream,这个情况也会关闭 keepalive socket 的吧。然后这种场景就不会出现问题了? |
会~,只是可能性极小了,得找个万全之策 |
关闭 keepalive 吧,毕竟读文件这种大小的传输是否 keepalive 感觉影响没那么大吧 |
@zensh 你们有测试 pipe 不加 keepalvie 慢多少么? |
yy一下,能不能临时创建一个stream作为中介? |
没有对比测过 keepalvie 对来的效益。想了下,response error 的情况下 destroy oss stream 是不会出现问题的,因为这个 socket 肯定还是在为这一单服务,不可能接其他单 |
搞个 passthrough 中介的话,且不说性能消耗,还要处理异常传递,不美~ |
昨晚上的,暂时没有了 |
三个不使用keepalive的理由,对oss场景来说比较match |
destroy 以后,keepaliveagent 不会自动补上吗? |
这是 NODE_DEBUG=http测试得到log
第一次removeSocket是socket结束后keepalive |
@gxcsoccer 因为都在阿里云上,走的是内网,所以没那些问题。destroy,keepaliveagent 会自动补上,问题是 destroy 时误杀了正常的 stream |
@gxcsoccer 会自动补上 问题是这个
出现问题的场景: 定义对象名称
场景描述正常场景:oss client 使用 agentkeepalive,创建了一个基于 agentkeepalive.socket1 的 oss.stream1。
感觉比较乱,有空补个图。 |
@zensh 重新看了 http.js 和 agent.js ,确实,如果是 error 事件,必然会触发 close,然后这个 socket 是不会别重用的。你的 patch 理论是生效的。 |
@zensh 在并发比较大的情况下,按道理这种异常出现的概率非常高才对。。。 |
明白了,感觉那 koa/toa 都不用 destroy socket。由 agentkeepalive 自己去管理 |
koajs/koa#165 找到当时加这个的原因,本意是避免赋值给 this.body 的所有的 stream 都会销毁,不会泄露 |
@dead-horse 这也是个原因,不过也好处理了, 那么要考虑重复 set body 和错误响应,都需要确保 close stream |
@dead-horse 感觉第二次还给 body 设置一个 stream,其实应该抛异常处理的。。。而不是现在这样兜底。 |
setter 不应该抛异常吧 |
// stream
if (val instanceof Stream) {
if (original instanceof Stream) {
// same stream, do nothing
if (original === val) return;
// destroy original stream and clean up error listener
original.removeListner('error', this.ctx.onerror);
destroy(original);
}
onFinish(this.res, function(err) {
if (err) {
destroy(val);
}
});
ensureErrorHandler(val, this.ctx.onerror); 改成判断,如果上一次也是 stream,就先清理它。 |
koajs/koa@fa63e25 这样修复如何? |
我认为 set body 中不应该做这个事,否则考虑各种情况会变得很复杂,这个要放在 respond 和 error handle 中去做 |
toa 利用自有的逻辑修复了下:toajs/toa@2633f5e#diff-910eb6f57886ca16c136101fb1699231R737 主要有如下几点:
总而言之,任何 stream,进来后会被添加ctx.onerror 级的 所以,对于我们上面的需求,正常情况下 agent socket 不会被 destroy 掉,一旦出错或 body 重置(如 204),就会被 destroy 掉,但这种情况下 agent socket 肯定还是在为当前的 request 服务,不会出现误杀。 |
等 @dead-horse 的 koa fix |
yy下,大佬们@dead-horse 最后到底怎么解决的?设过timeout,设过maxSockets,也试过上面的toa机制,还是凉了。在线等,很急。 |
有进展吗?上传文件会出现类似的错误( {
"file": "./dist/img/scrollindicatorsprite.1dde3254.png",
"err": {
"code": "ResponseError",
"message": "socket hang up, PUT http://xxx.com/official-website/img/scrollindicatorsprite.1dde3254.png -1 (connected: true, keepalive socket: true, agent status: {\"createSocketCount\":73,\"createSocketErrorCount\":0,\"closeSocketCount\":65,\"errorSocketCount\":0,\"timeoutSocketCount\":0,\"requestCount\":53,\"freeSockets\":{\"xxx.com:80:\":1},\"sockets\":{\"xxx.com:80:\":7},\"requests\":{}}, socketHandledRequests: 3, socketHandledResponses: 2)\nheaders: {}",
"name": "ResponseError"
}
} |
https://github.com/aliyun/oss-nodejs-sdk/blob/master/lib/object.js#L150
cc @zensh
The text was updated successfully, but these errors were encountered: