于是为了解决time_wait的问题,网上搜索了些许资料加上自己的思考,于是认为可以通过连接池来保存tcp连接,减少HttpClient在并发情况下随机打开的端口数量,复用原来有效的连接。 于是等我到了公司,首先观察了一下应用整体的情况: 监控平台的业务流量表现正常,但是部分机器的网卡流量略有突增 接口的平响出现了明显的上升 业务日志无明显的异常,不是底层服务超时的原因,因此平响的原因肯定不是业务本身 由于很可能是修改了HttpClient连接方式为连接池引发的问题,最容易引起变化的肯定是线程和CPU状态,于是立即排查了线程数和CPU的状态是否正常。 从jstack的日志中可以很容易分析出来,有大量的线程在等待获取连接池里的连接而进行排队,因此导致了线程堆积,因此平响上升。 ) 5.案情总结 到此这次雪崩事件的根本问题已彻底定位,让我们再次精炼的总结一下这个案件的全过程: 连接池设置错参数,导致最大连接数为2 大量请求线程需要等待连接池释放连接,出现排队堆积 夯住的线程变多
传统的 HttpURLConnection 并不支持连接池,如果要实现连接池机制,那么需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,没有一定经验的程序员很难写好这块代码逻辑。 一般情况下, HttpClient 已经能满足业务需求了;但是在网关这种高并发场景下,使用 HttpClient 进行大量的请求网络,还是需要用连接池才能提高网关的TPS,不然很容易成为网关的瓶颈。 Apache 的 HttpClient的早期版本,提供了PoolingClientConnectionManager、DefaultHttpClient 等类来实现 Http 连接池,但这些类在 4.3 v : this.defaultMaxPerRoute; } connectTimeout:多久等待与远程服务器抛出超时异常之前建立连接 socketTimeout:多久等待服务器抛出超时异常之前,各种消息响应 ,先从连接池中的连接时等待(连接池不会立即返回,如果所有的连接被检出) staleConnectionCheckEnabled:可以在潜在的 IOExceptions 成本的性能有所提高被禁用 http
开学季邀新,赢腾讯内推实习机会
3000);//3.3设置客户端从连接池获取链接的超时时间 httpGet.setConfig(builder.build()); //4.发起请求 response = httpClient.execute 代码3.3设置客户端从连接池获取链接的超时时间,如果在该时间内没能从连接池获取到连接,则抛出ConnectionPoolTimeoutException异常。 代码3.2设置客户端发起TCP连接请求的超时时间,也就是创建TCP连接时候等待的时间,如果该时间内还没完成TCP三次握手,则抛出ConnectTimeoutException异常。 代码3.1设置客户端等待服务端返回数据的超时时间,也就是请求发出去后,如果等待该时间服务端还没返回结果,则抛出SocketTimeoutException异常。 对于过期链接的处理,当Tomcat主动关闭链接时,httpclient 4.4之前是每次在复用链接前进行检查链接是否可用,http4.4后,是自上次使用连接以来所经过的时间超过已设置的超时时(默认超时设置为
,此时我们需要查看构建HttpClient实例的方法来寻找答案:此方法包含一系列的初始化操作,包括构建连接池,给连接池设置最大连接数,指定重用策略和长连接策略等,这里我们还注意到,HttpClient创建了一个异步线程 3.3 三个超时 connectionRequestTimout connetionTimeout socketTimeout 【connectionRequestTimout】:指从连接池获取连接的超时时间 ; 【connetionTimeout】:指客户端和服务器建立连接的超时时间,超时后会报ConnectionTimeOutException异常; 【socketTimeout】:指客户端和服务器建立连接后 ”中的步骤2,连接直接被关闭;所以正常情况下是没有问题的,长连接其实并没有发挥真正的作用;那问题自然就只能出现在一些异常场景,导致了长连接没有被及时关闭,结合最初的分析,是服务端主动断开了连接,那大概率出现在一些超时导致连接断开的异常场景 ;然而再结合“连接的产生与管理”的步骤4,当free容器为空了以后,从连接池获取连接时需要等待available容器里的连接被释放掉,整个过程是单线程的,效率极低,势必会造成拥堵,最终导致大量等待获取连接超时报错
状态, 必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。 这里我理解的CLOSE_WAIT就是服务端被动关闭时没有及时释放连接或客户端连接池在连接被动关闭时没有及时释放连接。出现这种问题最大的可能就是代码的问题。 2. (),而没有使用连接池; (2)在出现连接异常时,并没有关闭连接,会导致很多的CLOSE_WAIT; 先将上面代码异常处理部分修改成如下: ... } catch (Exception e) { 针对上面的代码,是每个连接只使用一次的,还可以设置一些超时时间: ? 3. 使用连接池 直接上代码: ? 中检索ManagedClientConnection实例时使用的毫秒级的超时时间 int CONN_MANAGER_TIMEOUT = 500; // 该值就是连接不够用的时候等待超时时间
于是为了解决time_wait的问题,网上搜索了些许资料加上自己的思考,于是认为可以通过连接池来保存tcp连接,减少HttpClient在并发情况下随机打开的端口数量,复用原来有效的连接。 于是等我到了公司,首先观察了一下应用整体的情况: 监控平台的业务流量表现正常,但是部分机器的网卡流量略有突增 接口的平响出现了明显的上升 业务日志无明显的异常,不是底层服务超时的原因,因此平响的原因肯定不是业务本身 由于很可能是修改了HttpClient连接方式为连接池引发的问题,最容易引起变化的肯定是线程和CPU状态,于是立即排查了线程数和CPU的状态是否正常。 从jstack的日志中可以很容易分析出来,有大量的线程在等待获取连接池里的连接而进行排队,因此导致了线程堆积,因此平响上升。 ) 案情总结 到此这次雪崩事件的根本问题已彻底定位,让我们再次精炼的总结一下这个案件的全过程: 连接池设置错参数,导致最大连接数为2 大量请求线程需要等待连接池释放连接,出现排队堆积 夯住的线程变多,接口平响升高
还可能有一种状态叫:超时。成功、失败和超时是分布式系统调用的三态。 ? 为什么要超时处理 对于超时这种状态,长时间等待会影响用户体验,并发量大时还可能会因为线程池耗尽而不能响应其他请求。 在apache的HttpClient实现中,添加了获取连接池阶段。 获取连接池阶段 因为建立连接需要IO、网络带宽等开销,需要池化处理,如果超过了连接池的最大值,则需要等待其他连接执行完释放资源。 数据通信阶段 与目标url建立连接后,等待数据报文传输的时间。这个阶段又叫做socket通信阶段。这个阶段可能有两种类型的事件:读取和写入。超时时间一般设1s到5s。 ? 为了进一步理解,可以借助HttpClient的调用代码来感受一下其使用 HttpParams httpParams = new BasicHttpParams(); // 获取连接的最大等待时间 0表示永不超时 0 3.0.1 autoReconnect 当数据库连接异常中断时是否自动重连 false 1.1 maxReconnects autoReconnect=true时,重试连接的次数 3
1,局部变量提升为静态变量 这个是文章开头提的问题的原因,因为登录要向单点系统验证用户的身份,所以它采用httpclient框架来发送http请求,它在这里把httpclient的变量作为一个静态变量, 然后在方法里面复用该对象,然后方法里面调用完该对象又没有释放资源合理的close,这个框架默认会维护一个连接池,如果你申请一个资源使用后不释放,那么该资源将不被下一个请求使用,新的请求必须在等待队列中等待 ,然后当用户登录20次后,把资源池中的请求都耗尽了,新的请求拿不到资源位于等待队列中不断等待,导致服务器超时,登录失败504错误。 当时我看到这个类的静态变量时httpclient的时候,我心中就飘起不好的预感,此处是一个容易出错的地方,如果是我,对这个框架,这个类没有十足的把握,我会它把整成局部变量,这样在低并发下,就让GC去帮我回收吧 ,你为啥也不打印异常信息,也不throws异常,就这样凶猛的将异常吃了,明明有问题,它不报,通过它来引发一个新的异常来雪藏真正的问题。
具体情况如下: 于是为了解决time_wait的问题,网上搜索了些许资料加上自己的思考,于是认为可以通过连接池来保存tcp连接,减少HttpClient在并发情况下随机打开的端口数量,复用原来有效的连接 于是等我到了公司,首先观察了一下应用整体的情况: 监控平台的业务流量表现正常,但是部分机器的网卡流量略有突增; 接口的平响出现了明显的上升; 业务日志无明显的异常,不是底层服务超时的原因,因此平响的原因肯定不是业务本身 由于很可能是修改了HttpClient连接方式为连接池引发的问题,最容易引起变化的肯定是线程和CPU状态,于是立即排查了线程数和CPU的状态是否正常。 ,总于可以确认问题 jstack状态: 从jstack的日志中可以很容易分析出来,有大量的线程在等待获取连接池里的连接而进行排队,因此导致了线程堆积,因此平响上升。 案情总结 到此这次雪崩事件的根本问题已彻底定位,让我们再次精炼的总结一下这个案件的全过程: 连接池设置错参数,导致最大连接数为2; 大量请求线程需要等待连接池释放连接,出现排队堆积; 夯住的线程变多,接口平响升高
具体情况如下: time_wait特征 于是为了解决 time_wait 的问题,网上搜索了些许资料加上自己的思考,于是认为可以通过连接池来保存 tcp 连接,减少 HttpClient 于是等我到了公司,首先观察了一下应用整体的情况: 监控平台的业务流量表现正常,但是部分机器的网卡流量略有突增 接口的平响出现了明显的上升 业务日志无明显的异常,不是底层服务超时的原因,因此平响的原因肯定不是业务本身 由于很可能是修改了 HttpClient 连接方式为连接池引发的问题,最容易引起变化的肯定是线程和 CPU 状态,于是立即排查了线程数和 CPU 的状态是否正常。 jstack 状态: jstack 状态 从 jstack 的日志中可以很容易分析出来,有大量的线程在等待获取连接池里的连接而进行排队,因此导致了线程堆积,因此平响上升。 案情总结 到此这次雪崩事件的根本问题已彻底定位,让我们再次精炼的总结一下这个案件的全过程: ❝ 连接池设置错参数,导致最大连接数为 2 大量请求线程需要等待连接池释放连接,出现排队堆积 夯住的线程变多
RestHighLevelClient 底层封装的是一个http连接池,当需要执行 update、index、delete操作时,直接从连接池中取出一个连接,然后发送http请求到ElasticSearch 指的是连接目标url的连接超时时间,即客服端发送请求到与目标url建立起连接的最大时间。如果在该时间范围内还没有建立起连接,会抛出connectionTimeOut异常。 connectionRequestTimeout:设置从connect Manager(连接池)获取Connection 超时时间,单位毫秒。 HttpClient中的要用连接时尝试从连接池中获取,若是在等待了一定的时间后还没有获取到可用连接(比如连接池中没有空闲连接了)则会抛出获取连接超时异常。 即在与目标url建立了连接之后,等待返回数据的时间的最大时间,如果超出时间没有响应,就会抛出socketTimeoutException异常。
四、HttpClient如何生成持久连接 HttpClien中使用了连接池来管理持有连接,同一条TCP链路上,连接是可以复用的。HttpClient通过连接池的方式进行连接持久化。 ,不过我们看HttpClient源码主要关注两点: 连接池的具体设计方案,以供以后自定义连接池参考 如何与HTTP协议对应上,即理论抽象转为代码的实现 4.1 HttpClient连接池的实现 HttpClient ,没有到上限就会新建一个连接,并放入池中 如果到达了上限,就排队等待,等到了信号量,就重新获得一次,等待不到就抛超时异常 通过线程池获取连接要通过ReetrantLock加锁,保证线程安全 到这里为止, 在上一章中,我们看到了HttpClient通过连接池来获得连接,当需要使用连接的时候从池中获得。 ,连接池分为两个,一个是总连接池,一个是每个route对应的连接池 HttpClient通过异步的Future<CPoolEntry>来获取一个池化的连接 默认连接重用策略与HTTP协议约束一致,根据response
HttpClient 如何生成持久连接 HttpClient 中使用了连接池来管理持有连接,同一条 TCP 链路上,连接是可以复用的。HttpClient 通过连接池的方式进行连接持久化。 ,不过我们看 HttpClient 源码主要关注两点: 连接池的具体设计方案,以供以后自定义连接池参考 如何与 HTTP 协议对应上,即理论抽象转为代码的实现 HttpClient 连接池的实现 HttpClient 连接池是否已经超过了最大数量,没有到上限就会新建一个连接,并放入池中 如果到达了上限,就排队等待,等到了信号量,就重新获得一次,等待不到就抛超时异常 通过线程池获取连接要通过 ReetrantLock 在上一章中,我们看到了 HttpClient 通过连接池来获得连接,当需要使用连接的时候从池中获得。 通过连接池来管理持久连接,连接池分为两个,一个是总连接池,一个是每个 route 对应的连接池 HttpClient 通过异步的 Future<CPoolEntry> 来获取一个池化的连接 默认连接重用策略与
3,局部变量提升为静态变量 这个是文章开头提的问题的原因,因为登录要向单点系统验证用户的身份,所以它采用httpclient框架来发送http请求,它在这里把httpclient的变量作为一个静态变量 ,然后在方法里面复用该对象,然后方法里面调用完该对象又没有释放资源合理的close,这个框架默认会维护一个连接池,如果你申请一个资源使用后不释放,那么该资源将不被下一个请求使用,新的请求必须在等待队列中等待 ,然后当用户登录20次后,把资源池中的请求都耗尽了,新的请求拿不到资源位于等待队列中不断等待,导致服务器超时,登录失败504错误。 httpclient这一块的代码问题提供的机会。 吃了就吃了,你为啥也不打印异常信息,也不throws异常,就这样凶猛的将异常吃了,明明有问题,它不报,通过它来引发一个新的异常来雪藏真正的问题。
来源:五月的仓颉 cnblogs.com/xrq730/p/10963689.html 起因 用不用线程池的差别 用哪个httpclient 不使用连接池的运行效果 使用连接池的运行结果 绕不开的长短连接 是线程安全的,因此HttpClient正常使用应当做成全局变量,但是一旦全局共用一个,HttpClient内部构建的时候会new一个连接池 * 出来,这样就体现不出使用连接池的效果 是线程安全的,但是一旦做成全局的就失去了测试效果,因为HttpClient在初始化的时候默认会new一个连接池出来。 // setConnectionRequestTimeout表示从连接池中拿连接的等待超时时间 // setSocketTimeout表示发出请求后等待对端应答的超时时间 ,任务多而连接少,导致很多任务一直在排队等待前面的执行完才可以拿到连接去处理,降低了处理速度 那针对连接池中的连接数量如何设置的这个问题,答案是没有固定的,但是可以通过估算得到一个预估值。
这三位都是解决一类问题的,如著名的雪崩:A→B→C互相依次调用,但C项目很可能出现问题(流量过大或者报错等),引发线程一直进行等待,导致拖垮整个链路层,线程资源耗尽。 ? 二、配置 首先来点理论性的东西。好吃不贵。 Ⅰ隔离方式 线程隔离(默认):使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。 : false //连接池最大连接数,默认200 max-connections: 500 //每一个IP最大占用多少连接 默认 50 max-connections-per-route : 50 //默认连接超时时间:2000毫秒 connection-timeout: 8000 //连接池管理定时器执行频率:默认 3000毫秒 connection-timer-repeat : 6000 //连接池中存活时间,默认为5 time-to-live: 5 time-to-live-unit: minutes 超时设置遵循的基本原则是:依赖方的超时配置覆盖被依赖方的配置
异常的详细信息应该显示出违反哪个约束条件。 从上不难看出: 重叠构造器模式在参数很多的情况下,客户端代码会很难写,并且难以阅读。 int connReqTimeout = DEFAULT_CONN_REQ_TIMEOUT; //从连接池获取连接超时时间 private static int connTimout = int connReqTimeout = DEFAULT_CONN_REQ_TIMEOUT; //从连接池获取连接超时时间 private int connTimout = DEFAULT_CONN_TIMEOUT ; //发起连接超时时间 private int connSocketTimeout = DEFAULT_CONN_SOCKET_TIMEOUT; //连接套接字等待时间 RequestConfig.copy(defaultRequestConfig) .setConnectionRequestTimeout(connReqTimeout)//从连接池获取连接超时时间
扫码关注腾讯云开发者
领取腾讯云代金券