精华 解决使用 KeepAlive Agent 遇到的 ECONNRESET
发布于 6 年前 作者 fengmk2 8100 次浏览 来自 分享

问题背景

自从 Node.js 8.0 开始,http server 增加了一个默认配置 keepAliveTimeout = 5000 ,它会自动销毁超过 5 秒的空闲连接。

通过 node-modules/agentkeepalive#58 的示例代码,非常容易重现出服务端 Keep Alive 超时的效果,就是客户端复用「Keep Alive」 的 socket connection 会立刻触发 ECONNRESET 异常,因为此 socket 已经被服务端认为空闲超时强制断开了。

现状

在 Egg 里面为了尽可能避免此问题的发生,综合 Node.js 的 keepAliveTimeout 和 Nginx 的 keepalive_timeout 常规配置,将 httpclient 的 freeSocketKeepAliveTimeout 配置为 4 秒,尽可能避免 ECONNRESET 异常发生。

缺点:无法 100% 解决所有问题。由于这是一个靠约定俗成的配置,和一些不稳定性因素的存在,还是有可能遇到本文所描述的问题。例如服务端 keepalive_timeout 被配置为 4 秒,默认的 Egg 配置也就失效。

更好的解决方案

如果服务端告诉客户端当前 socket connection 会被保留多长时间呢?是否就能解决这个问题了? 如服务端在 Response header 中告诉客户端,当前 socket connection 还可以使用 5 秒,那么客户端通过计算,加上网络延迟 500 毫秒,最终得出当前 socket connection 只能用 4.5 秒。

下一个请求间隔在 4.5 秒内,则客户端继续使用这个 socket connection; 下一个请求间隔在 4.5 秒外,则客户端创建一个新的 socket connection 来请求。

业界事实标准:Keep-Alive Header

Google 一番发现业界有一个事实标准:The Keep-Alive Header。它竟然被所有浏览器都支持!

例如,通过 Response Header 告诉客户端当前 socket connection 还可以使用 5 秒,示例如下:

"Keep-Alive: timeout=5"

nginx 开启

配置 keepalive_timeout 的第二个参数:

keepalive_timeout 5 5;

_特别提示:_nginx 一旦配置了 keepalive_timeout,那么它会覆盖 web server 返回的 Keep-Alive header。所以你的应用前面有 nginx,那么必须配置第二个参数才会让 Keep-Alive header 返回给客户端。

Egg 开启

升级到 Egg 的最新版本,默认已经支持。

通过以下 2 个 PR 支持:

参考

原文

原始文章来自 egg.js 团队的 Node.js 经验分享:Node.js 专栏

蚂蚁金服实习生招聘

蚂蚁金服2019届实习生校园招聘已经开启,非常欢迎大家加入我们!详情请查看 https://cnodejs.org/topic/5a9627e32580af301494a8f8 招聘帖子。

3 回复

赞,标题不够吸引人

👍👍 刚好昨天用 egg 调微信支付接口配置错了,导致重复请求,出现 ECONNRESET 错误,还看了半天不明白,这下懂了!感谢!

回到顶部