Connection RST(2019.10.29)

2024-01-13 02:18
文章标签 connection 29 rst 2019.10

本文主要是介绍Connection RST(2019.10.29),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在使用HttpClient调用后台resetful服务时,“Connection reset”是一个比较常见的问题,有同学跟我私信说被这个问题困扰很久了,今天就来分析下,希望能帮到大家。例如我们线上的网关日志就会抛该错误: 
这里写图片描述
从日志中可以看到是Socket套接字在read数据时抛出了该错误。 
导致“Connection reset”的原因是服务器端因为某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志“RST”,然后此时客户端就会提示“java.net.SocketException: Connection reset”。 
可能有同学对复位标志“RST”还不太了解,这里简单解释一下: 
TCP建立连接时需要三次握手,在释放连接需要四次挥手;例如三次握手的过程如下:

  1. 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;
  2. 第二次握手:服务器收到syn包,并会确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  3. 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

可以看到握手时会在客户端和服务器之间传递一些TCP头信息,比如ACK标志、SYN标志以及挥手时的FIN标志等。 
除了以上这些常见的标志头信息,还有另外一些标志头信息,比如推标志PSH、复位标志RST等。其中复位标志RST的作用就是“复位相应的TCP连接”。 
TCP连接和释放时还有许多细节,比如半连接状态、半关闭状态等。详情请参考这方面的巨著《TCP/IP详解》和《UNIX网络编程》。 
前面说到出现“Connection reset”的原因是服务器关闭了Connection[调用了Socket.close()方法]。大家可能有疑问了:服务器关闭了Connection为什么会返回“RST”而不是返回“FIN”标志。原因在于Socket.close()方法的语义和TCP的“FIN”标志语义不一样:发送TCP的“FIN”标志表示我不再发送数据了,而Socket.close()表示我不在发送也不接受数据了。问题就出在“我不接受数据” 上,如果此时客户端还往服务器发送数据,服务器内核接收到数据,但是发现此时Socket已经close了,则会返回“RST”标志给客户端。当然,此时客户端就会提示:“Connection reset”。详细说明可以参考oracle的有关文档:http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html。 
另一个可能导致的“Connection reset”的原因是服务器设置了Socket.setLinger (true, 0)。但我检查过线上的tomcat配置,是没有使用该设置的,而且线上的服务器都使用了nginx进行反向代理,所以并不是该原因导致的。关于该原因上面的oracle文档也谈到了并给出了解释。 
此外啰嗦一下,另外还有一种比较常见的错误“Connection reset by peer”,该错误和“Connection reset”是有区别的:

  • 服务器返回了“RST”时,如果此时客户端正在从Socket套接字的输出流中读数据则会提示Connection reset”;
  • 服务器返回了“RST”时,如果此时客户端正在往Socket套接字的输入流中写数据则会提示“Connection reset by peer”。 
    “Connection reset by peer”如下图所示: 
    这里写图片描述

前面谈到了导致“Connection reset”的原因,而具体的解决方案有如下几种:

  • 出错了重试;
  • 客户端和服务器统一使用TCP长连接;
  • 客户端和服务器统一使用TCP短连接。

首先是出错了重试:这种方案可以简单防止“Connection reset”错误,然后如果服务不是“幂等”的则不能使用该方法;比如提交订单操作就不是幂等的,如果使用重试则可能造成重复提单。

然后是客户端和服务器统一使用TCP长连接:客户端使用TCP长连接很容易配置(直接设置HttpClient就好),而服务器配置长连接就比较麻烦了,就拿tomcat来说,需要设置tomcat的maxKeepAliveRequests、connectionTimeout等参数。另外如果使用了nginx进行反向代理或负载均衡,此时也需要配置nginx以支持长连接(nginx默认是对客户端使用长连接,对服务器使用短连接)。

使用长连接可以避免每次建立TCP连接的三次握手而节约一定的时间,但是我这边由于是内网,客户端和服务器的3次握手很快,大约只需1ms。ping一下大约0.93ms(一次往返);三次握手也是一次往返(第三次握手不用返回)。根据80/20原理,1ms可以忽略不计;又考虑到长连接的扩展性不如短连接好、修改nginx和tomcat的配置代价很大(所有后台服务都需要修改);所以这里并没有使用长连接。ping服务器的时间如下图: 
这里写图片描述

最后的解决方案是客户端和服务器统一使用TCP短连接:我这边正是这么干的,而使用短连接既不用改nginx配置,也不用改tomcat配置,只需在使用HttpClient时使用http1.0协议并增加http请求的header信息(Connection: Close),源码如下:

httpGet.setProtocolVersion(HttpVersion.HTTP_1_0);
httpGet.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
  • 1
  • 2

最后再补充几句,虽然对于每次请求TCP长连接只能节约大约1ms的时间,但是具体是使用长连接还是短连接还是要衡量下,比如你的服务每天的pv是1亿,那么使用长连接节约的总时间为:

1亿*1ms=10^8*1ms=10^5*1s=10^5*1h/3600≈27.78h
  • 1

神奇的是,亿万级pv的服务使用长连接一天内节约的总时间为27.78小时(竟然大于一天)。

所以使用长连接还是短连接大家需要根据自己的服务访问量、扩展性等因素衡量下。但是一定要注意:服务器和客户端的连接一定要保持一致,要么都是长连接,要么都是短连接。

这篇关于Connection RST(2019.10.29)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/599928

相关文章

基于Python的机器学习系列(29):前馈神经网络

在本篇文章中,我们将学习如何使用PyTorch构建和训练一个前馈神经网络。我们将以线性回归为例,逐步了解PyTorch的各个组件及其在神经网络中的应用。这些步骤包括: 指定输入和目标:我们将定义输入特征和目标变量。数据集和数据加载器:使用PyTorch的数据集和数据加载器来管理和加载数据。nn.Linear(全连接层):创建前馈神经网络中的线性层。定义损失函数:选择合适的损失函数

『功能项目』Unity本地数据库读取进入游戏【29】

本章项目成果展示 打开上一篇28Unity连接读取本地数据库的项目, 本章要做的事情是通过读取本地数据库登录进入游戏场景 首先创建一个脚本文件夹: 新建脚本:MySqlAccess.cs 编写脚本:MySqlAccess.cs using UnityEngine;using MySql.Data.MySqlClient;public class MySq

ssh问题:Connection closed by foreign host. Disconnected from remote host

放通一个远程ip能够ssh服务器,但是报错: Connection closed by foreign host.   Disconnected from remote host。。。   解决办法: firewall防火墙放通ip。 /etc/ssh/sshd_config文件修改,运行root用户密码登,再重启sshd服务。 /etc/hosts.allow和/etc/hos

Oracle - ORA-28547: Connection to server failed,probable Oracle Net admin error (Navicat)

一、异常     用Navicat连接Oracle数据库时抛出的异常 二、方案     使用 Oracle 安装目录 \Oracle\product\11.2.0\dbhome_1\BIN 下的 oci.dll      替换 Navicat 安装目录 \Navicat Premium\instantclient_10_2 下的 oci.dll 文件即可

Oracle - ORA-28009: connection as SYS should be as SYSDBA OR SYSOPER

一、原因     sys 用户是超级管理员,所以在登录的时候需要额外指定其角色 二、方案     1、在 PL/SQL 中,在登录界面,将 连接为 的选项 SYSDBA 选中          2、在 SQLPlus 中,通过 as sysdba 子句指定 -- 方式一[oracle@xl ~]$ sqlplus sys/登录密码 as sysdba-- 方式二[o

mysql 事务与connection,锁,慢sql,如何解决,杀死执行的线程

前提说明 navicat中每打开一个窗口就是打开一个connection,关掉窗口就是关掉connection 事务与connection  测试事务不提交的情况 (步骤1)先打开一个窗口,开启一个事务T1插入一条数据,这里不进行提交。 由于在一个事务中,所以select 能立刻查出insert的但还没提交的数据。 查询是否开启 事务超时,回滚策略。 SHOW GLO

关于javaSocket中 Software caused connection abort: recv failed问题

在学习Socket中今天突然遇到了下面这样的问题 原来是网路连接出了问题,因为我测试的是远程连接所以是在学校的局域网下,结果很不稳定,开始还以为怎么了一会连上了一会又出现问题然后把IP地址改为本机的127.0.0.1之后就没有 出现过了.

leetcode解题思路分析(五)29-36题

两数相除 给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。 返回被除数 dividend 除以除数 divisor 得到的商。 本题思路倒是不难,既然不能用乘除法和mod,那使用减法是理所当然的,唯一需要考虑的是边界溢出情况 class Solution {public:int divide(int dividend, in

火狐浏览器设置秘籍:让https协议下的ws不加密时运行无阻(WebSocket connection HTTPS)

Uncaught (in promise) DOMException: Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. 明确指出了一个常见的安全限制:当尝试从一个通过HTTPS加载的页面上发起一个不安

9/29学习总结

周六上午开了总结会,感觉到自己太颓废了相较于别人的努力发现自己和每个人的差距都实在是太大,总结的时候说不出几句,而听到他人的总结时有多多少少能在自己身上找到这些点这点说明反思的还不够并不能抓住问题的要点。近期自己的学习只是看那些基础的题目一点新的知识都没有整天就感觉自己空空的没有东西可以总结,这也反映出看题目也没有看得很深没有将其中的思想给提取出来。对于那些和其他知识点结和的题目我也是跳过而这我想