放弃等待,故障到来:少一个 await 引发的 tcp 连接泄漏故障
今天上午的故障之后,我们 review 了代码,通过压力测试重现问题,分析验证,最终找到了问题的真正原因 —— 在 ASP.NET Core 程序中调用 async 方法时没加 await 。
public async Task<IActionResult> GetRecommDocuments() { //... ShowItem(docs, app); //async方法,其中用到了HttpClient return Ok(docs); }
就是上面的代码中“漏”写了 await ,不是粗心漏写,是故意为之。我们不关心调用 ShowItem 的结果,只要能执行就行,即使执行失败也可以接受。不加 await 可以让 GetRecommDocuments 方法调用 ShowItem 之后无需等待继续执行从而提高响应速度,但是没想到这一招偷工减料,竟然抽空了服务器的 TCP 连接资源,让整个服务器大厦轰然倒塌。
开始从 async/await 的角度怎么也想不通 —— 少一个 await 怎么会如此严重后果,后来突然想到罪魁祸首不在 async/await 而在依赖注入(DI)。GetRecommDocuments 中的 HttpClient 实例是通过构造函数的 IHttpClientFactory 注入的,注入的 HttpClient 实例的生命周期是 Scoped (当前请求范围),本来正常情况下一个请求处理结束,HttpClient 实例会被 DI 容器 Dispose,所使用的 Socket 连接会被放回连接池,但是由于没加 await ,让 ShowItem 不走正常路,DI 容器在请求处理结束时跟踪不到 ShowItem 中的 HttpClient 实例,也就不会进行 Dispose 。结果来一个请求,IHttpClientFactory 就创建一个 HttpClient 实例,每个 HttpClient 实例都占用一个新的 TCP 连接,直至拖垮服务器。
随着软件开发技术的发展,开发效率越来越高了,要写的代码越来越少了,但要考虑的问题却越来越多了。虽然我们每天都在用着 .NET Core ,但由于其内部工作机制不够熟悉,原以为“巧夺天工”的一招却酿成大错,我们会牢记这次教训,进一步地对 .NET Core 刨根问底 。
- [找到问题了.Net丫丫]TCP Provider, error: 0 - A transport-level error has occurred when receiving results f 您的主机中的软件放弃了一个已建立的连接
- 【故障公告】推荐系统中转站撑爆服务器 TCP 连接引发的故障
- TCP连接的状态详解以及故障排查
- 连接远程服务器时,如何显示另外一个等待Form?
- 一个解除TCP连接的TIME_WAIT状态限制的简便方法
- 创建一个tcp连接
- TCP连接的状态详解以及故障排查
- 在向服务器发送请求时发生传输级错误。 (provider: TCP 提供程序, error: 0 - 远程主机强迫关闭了一个现有的连接。) .
- 一个完整的TCP连接
- Cisco测试命令和TCP/IP连接故障处理
- Apache并发请求数及其TCP连接状态故障排除
- C# Socket TcpClient 无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接。。
- 客户端C和服务器S之间建立了一个TCP连接,TCP最大段长度为1KB,客户端C当前的拥塞窗口是16KB,向服务器S连续发送2个最大段之后,成功收到服务器S发送的第一段的确认段,确认段中通告的接受窗口大
- TCP连接的状态详解以及故障排查
- TCP连接connect等待时长控制的另一种方法
- 记一次TCP连接异常故障解决
- 一个内存泄漏引发的血案
- TCP协议中采用三次握手建立一个连接
- 【经验总结】tcp_tw_recycle参数引发的故障
- TCP连接的状态详解及故障排查