Hacker News 中文摘要

RSS订阅

偶发性ECONNRESET -- The occasional ECONNRESET

文章摘要

同一台机器上的两个服务通过TCP连接交换数据时,偶尔会出现连接方读取数据时收到ECONNRESET错误,但日志中无其他异常。作者通过实验重现问题,使用tcpdump和strace工具分析,提出了初步假设,并将在后续文章中继续探讨解决方案。

文章总结

文章标题:偶发的ECONNRESET错误分析(上篇)

问题描述

在同一台机器上运行的两个服务: - 服务A:监听本地TCP端口 - 服务B:连接到该端口并进行数据交换

异常现象:连接方(服务B)在读取数据时偶尔会收到ECONNRESET错误(连接被重置),但日志中未显示其他错误或崩溃信息。

实验复现

作者通过以下程序模拟该场景:

服务端程序: - 创建TCP监听套接字(端口8125) - 对每个连接fork子进程 - 向客户端发送60万字节的"x"数据

客户端程序: - 连接服务端 - 持续调用recv()读取数据 - 提供--spam选项:先发送数据再接收

实验结果: - 普通模式:能完整接收60万字节 - --spam模式:随机出现连接重置,接收字节数不定(如256000、351232等)

网络抓包分析

tcpdump显示确实存在TCP RST(重置)数据包,排除了程序逻辑错误的可能性。

系统调用追踪

服务端: - 正常完成sendto()调用(返回600000) - 立即关闭连接

客户端: - 在最后一次recvfrom()时收到ECONNRESET

初步假设

当服务端存在以下情况时会触发RST: 1. 套接字仍有待读数据("脏"状态) 2. 直接调用close()关闭连接

通过添加1秒延迟关闭的测试证实了该假设: - 延迟后客户端能完整接收数据 - 立即关闭则随机出现重置

实际案例

nginx反向代理+gunicorn+flask架构中出现的类似问题: - nginx分两次写入HTTP请求(头+体) - gunicorn有时只读取头部就返回响应 - 立即关闭连接导致RST

解决方案: 强制应用层读取完整的HTTP请求体。

后续计划

  1. 确认RFC 1122关于"半双工"关闭连接的规定
  2. 定位Python生态中的责任方(gunicorn/flask/应用)
  3. 向上游项目提交问题报告

(注:本文保留了技术细节,删减了个人网站导航等无关内容)

评论总结

以下是评论内容的总结:

  1. 关于RST合理性的讨论
  • 支持RST的观点认为这是TCP标准实现,能避免数据丢失问题 "Um, yes? That's how TCP has been universally implemented for more than 30 years" (Joker_vD) "As outlined in RFC 2525, section 2.17, we send a RST here because data was lost" (smarks引用Linux代码)
  1. 关于FIN替代RST的讨论
  • 有评论质疑使用FIN的负面影响,但未得到明确解释 "But what are the 'awful effects' of sending FIN instead? Can someone explain?" (smarks)
  1. 实际案例分享
  • 多个用户分享了遇到类似问题的实际经验 "frequent HTTP requests to the same domain kept making fresh TCP connections" (gunsch) "this usually happens because both sides wrote data and one side didn't read it before calling close()" (jcalvinowens)
  1. 解决方案建议
  • 建议在关闭前正确处理数据 "the server should call shutdown with SHUT_WR after sending the data and then drain the incoming data" (kune) "read the section on Lingering Close" (toast0)
  1. 对原文的评价
  • 有评论高度赞赏文章质量 "Opens with the problem statement and jumps straight into the investigation" (bayesnet)

注:所有评论均无评分(None),主要围绕TCP连接中RST的使用场景、原理和替代方案展开讨论,包含技术引用和实际案例。