我们在开发过程中经常会出现Connection reset问题,包括http调⽤,数据库连接等场景。出现Connection reset的原因很多,本⽂从tcp层⾯简单介绍下Connection reset出现的原因,以及在实际开发过程中如何排查这类问题。
1、什么是Connection reset
在TCP⾸部中有6个标志位,其中⼀个标志位为RST,⽤于“复位”的。⽆论何时⼀个报⽂ 段发往基准的连接( referenced connection)出现错误,TCP都会发出⼀个复位报⽂段。如果双⽅需要继续建⽴连接,那么需要重新进⾏三次握⼿建⽴连接。
2、出现RST的原因
2.1 RST攻击、⼲扰
上⾯简单介绍了RST标志位的作⽤,很容易想到这样⼀个场景,如果中间⽹络节点想要破坏⼀个tcp连接,那么它只要伪造成其中⼀⽅发送RST报⽂到另⼀⽅,即可让双⽅连接失效。
上图中,三次握⼿建⽴了tcp连接,由于是https连接,需要进⾏加密操作。这时,对⽅发送RST,双⽅并没有进⾏“四次挥⼿”,⽽是连接直接失效。这时客户端发起重拾,重新建⽴连接,但是很快⼜被“对⽅”重置了。和客户端连接tcp连接以及发送RST报⽂的,都不⼀定是真正的服务端,⽽可能是中间节点。我们使⽤HTTPS可以避免受到中间⼈攻击。对⽅⽆法使⽤中间⼈攻击,但是想阻⽌我们访问,所以可以通过RST来重置连接。
2.2 请求⼀个不存在的端⼝
当客户端访问服务端⼀个没有监听的端⼝时,服务端会发送RST报⽂。
如上图所⽰,客户端(192.168.2.192)访问了服务端(192.168.2.1)⼀个未监听的端⼝(9090),服务端发送了RST报⽂。
2.3 异常终⽌⼀个连接
终⽌⼀个连接的正常⽅式是⼀⽅发送 FIN。有时这也称为有序释放(orderly release),因为在所有排队数据都已发送之后才发送 FIN,正常情况下没有任何数据丢失。但也有可能发送⼀个复位报⽂段⽽不是 FIN来中途释放⼀个连接。有时称这为异常释放 (abortive release)。
上图,当客户端连接redis后,我们⼿动关闭redis服务,redis服务端会发送RST来强制终⽌⼀个连接。客户端通常收到这样的错误:Connection reset by peer,或者:远程主机强迫关闭了⼀个现有的连接。
2.4 半打开连接
如果⼀⽅已经关闭或异常终⽌连接⽽另⼀⽅却还不知道,我们将这样的TCP连接称为半打开(Half-Open)的。只要不打算在半打开 连接上传输数据,仍处于连接状态的⼀⽅就不会检测另⼀⽅已经出现异常。
3、排查思路
实际开发过程中,前⾯三个问题⽐较容易识别和解决。最困难的是最后⼀种半打开连接,原因往往很难发现。因为⽹络正常的情况下,都会通过正常关闭或者2.3的⽅式来关闭连接。现在客户端和服务端的⽹络⾮常复杂,有各种nat,代理,防⽕墙等设备,这些中间设备可能配置了⼀些安全策略,导致断开连接⽽不通知。
通过查询客户端⽇志,定位出现异常的时间。查询服务端⽇志,查询有⽆连接断开⽇志;查询连接是否存在;如果不存在,查询断开的时间。通过这些可以判断是不是由于半打开连接导致的问题。半打开连接⼀般是由于中间设备或者⽹络问题断开连接,⽽客户端不知道。 解决⽅案就是找到对应的设备,配置连接,避免长连接断开。
临时⽅案就是,开启keep-live;减少长连接存活时间;连接异常时进⾏重试。
因篇幅问题不能全部显示,请点此查看更多更全内容