https://www.cnblogs.com/turn2i/p/10480088.html

在写这个问题前,其实我是为了分析项目碰到的一个tcp close wait问题。这个问题就不在这里讲了。

造成的原因很简单,就是很多项目对httpclient的参数和使用都理解有问题,往往随便写一个或者使用网上的代码。导致在一些场景连接关闭有问题

httpclient大致有这些版本

  • httpclient3.x
  • httpclient4.x到httpclient4.3以下
  • httpclient4.3以上

一般会选择4.3以上

https://www.baeldung.com/httpclient-connection-management 这是国外一个教学网站的说明,使用和说明还算比较ok

 
于是我写了一个demo工具类,并对这个工具类做了一些测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class HttpClientUtils {
  
  
    private static CloseableHttpClient httpClient;
  
  
    static {
  
        // 基本配置
        RequestConfig requestConfig = RequestConfig.custom()
                // 建连超时时间
                .setConnectTimeout(5000)
                // 传输超时时间
                .setSocketTimeout(3000)
                // 从连接池获取连接超时时间
                .setConnectionRequestTimeout(10000)
                .build();
  
        // 连接管理器
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        // 最大连接数
        cm.setMaxTotal(80);
        // 同一个路由最大连接数
        cm.setDefaultMaxPerRoute(20);
  
        // 客户端构造器
        HttpClientBuilder clientBuilder = HttpClients
                .custom()
                .setConnectionManager(cm)
                .setConnectionManagerShared(false)// 影响连接的关闭
                .setDefaultRequestConfig(requestConfig);
  
        httpClient = clientBuilder.build();
    }
  
    public static byte[] get(String url, String userAgent) throws IOException {
        HttpGet httpGet = new HttpGet(url);
        if (userAgent != null) {
            httpGet.setHeader(HTTP.USER_AGENT, userAgent);
        }
        CloseableHttpResponse response = httpClient.execute(httpGet, HttpClientContext.create());
  
        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
  
        HttpEntity entity = response.getEntity();
  
        if (entity != null) {
            try {
                return IOUtils.toByteArray(entity.getContent());
            finally {
                // 只需在传输完毕关闭流即可,详细见源码
                EntityUtils.consumeQuietly(entity);
            }
        }
  
        return null;
    }
  
}

  服务端我简单启动了一个web服务(这里略过这个操作),然后客户端用demo进行请求处理

demo1:客户端单线程多次请求

 
1
2
3
4
5
6
7
8
9
10
for (int i = 0; i < 20; i++) {
    try {
    catch (IOException e) {
        e.printStackTrace();
    }
}
 
CountDownLatch latch = new CountDownLatch(1);

客户端的tcp连接状况

服务器的tcp连接情况

符合预期,只有一个连接,连接复用

demo2:客户端多线程请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (int i = 0; i < 100; i++) {
    new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(new String(HttpClientUtils.post("http://10.101.17.26:8888/demo"), "utf-8"));
                catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
    }
}
CountDownLatch latch = new CountDownLatch(1);

客户端tcp连接情况

100个请求,20个连接,符合预期

重点来了,刚好为了测试单线程的close情况,于是把thread去掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        for (int i = 0; i < 100; i++) {
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
                    try {
                        System.out.println(new String(HttpClientUtils.post("http://10.101.17.26:8888/demo"), "utf-8"));
                    catch (IOException e) {
                        e.printStackTrace();
                    }
//                }
//            }).start();
        }
        CountDownLatch latch = new CountDownLatch(1);
        latch.await();

控制台一看,连接呢???一下子可以说是搞不明白的

20正常100就没了,怀疑和100这个数字安息,于是模拟了以下测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for (int i = 0; i < 101; i++) {
 
    if (i == 98 || i == 99 || i == 100) {
        System.out.println(i);
    }
    try {
    catch (IOException e) {
        e.printStackTrace();
    }
 
}
 
CountDownLatch latch = new CountDownLatch(1);

打断点跟踪发现,reusable这个参数在100的时候,行为是和99和101不同的

于是看源码跟踪这个参数修改的地方

private volatile boolean reusable;

代码中有多处将此参数设置为false,其中在100的时候,命中断点。在MainClientExec.java中有如下使用,那么 reuseStrategy.keepAlive(response, context)是关键

继续看 reuseStrategy.keepAlive(response, context),有个叫Porxy-Connection的当100的时候,值为Close状态,证明这个是服务端的一些设置导致的,于是谷歌关键字keepalive

找到tomcat有如下参数配置,nginx也有,大致意思就是一个连接能被重复使用的次数,当超过他,就会断开。这也可以解释为什么100的时候,连接没了。101又开始建立新的连接

maxKeepAliveRequests

The maximum number of HTTP requests which can be pipelined until the connection is closed by the server. Setting this attribute to 1 will disable HTTP/1.0 keep-alive, as well as HTTP/1.1 keep-alive and pipelining. Setting this to -1 will allow an unlimited amount of pipelined or keep-alive HTTP requests. If not specified, this attribute is set to 100.    

 
如果把这个参数设成1,http1.1就退化成http1.0了 

[转帖]Tomcat maxKeepAliveRequests的更多相关文章

  1. [转帖]Tomcat目录结构详解

    Tomcat目录结构详解 https://www.cnblogs.com/veggiegfei/p/8474484.html 之前应该是知道一点 但是没有这么系统 感谢原作者的描述. 1.bin: 该 ...

  2. Spring Boot 2.5.0 发布:支持Java16、Gradle 7、Datasource初始化机制调整

    今年520的事情是真的多,娱乐圈的我们不管,就跟DD一起来看看 Spring Boot 2.5.0 的发布吧!看看都带来了哪些振奋人心的新特性和改动! 主要更新 支持 Java 16 支持 Gradl ...

  3. 【java】基于Tomcat的WebSocket转帖 + 自己理解

    网址:http://redstarofsleep.iteye.com/blog/1488639 原帖时间是2012-5-8,自己书写时间是2013年6月21日10:39:06 Java代码 packa ...

  4. [转帖]Apache、Tomcat与Catalina作为软件名字的含义与关系

    Apache.Tomcat与Catalina作为软件名字的含义与关系 -- :: 复杂度掠夺者 阅读数 3356更多 分类专栏: 术语解释 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA ...

  5. [转帖]说一说JVM双亲委派机制与Tomcat

    说一说JVM双亲委派机制与Tomcat https://www.cnblogs.com/dengchengchao/p/11844022.html 讲个故事: 以前,爱捣鼓的小明突然灵机一动,写出了下 ...

  6. jvm系列(五):tomcat性能调优和性能监控(visualvm)

    tomcat服务器优化 1.JDK内存优化 根据服务器物理内容情况配置相关参数优化tomcat性能.当应用程序需要的内存超出堆的最大值时虚拟机就会提示内存溢出,并且导致应用服务崩溃.因此一般建议堆的最 ...

  7. tomcat 常用优化配置

    1.精简Tomcat和配置文件 1.删除不需要的管理应用和帮助应用,提高tomcat安全性. # 删除webapps下所有文件 # rm –fr $CATALINA_HOME/webapps/* # ...

  8. Apache, Tomcat, JK Configuration Example

    Example of worker.properties: worker.list=myWorker,yourWorker worker.myWorker.port=7505 worker.myWor ...

  9. 聊下并发和Tomcat线程数(错误更正)

    本文前半部分结论存在严重错误,请看最后2015-1-20更新部分. 最近一直在解决线上一个问题,表现是: Tomcat每到凌晨会有一个高峰,峰值的并发达到了3000以上,最后的结果是Tomcat线程池 ...

  10. Tomcat重启脚本restart.sh停止脚本stop.sh

    Tomcat重启脚本restart.sh停止脚本stop.sh Tomcat本身提供了 startup.sh(启动)shutdown.sh(关闭)脚本,我们在部署中经常会出现死进程形象,无法杀掉进程需 ...

随机推荐

  1. PC端和移动端应用的开发差异

    PC端和移动端应用的开发差异主要体现在用户界面(UI)和用户体验(UX)设计.交互设计.性能优化.适配策略等方面.  

  2. GaussDB技术解读系列之应用无损透明(ALT)

    本文作者 :华为云GaussDB研发高级工程师 藏琦 1.背景 GaussDB作为一款企业级分布式数据库,提供了"同城跨AZ双活.两地三中心.双集群强一致"等极致的高可用容灾能力. ...

  3. iOS应用程序发布流程:从测试到上架的完整指南

    ​ 目录 转载:iOS应用程序的签名.重签名和安装测试 前言 打开要处理的IPA文件 设置签名使用的证书和描述文件 开始ios ipa重签名 转载:iOS应用程序的签名.重签名和安装测试 前言 ipa ...

  4. Redis 数据一致性

    概述 当我们在使用缓存时,如果发生数据变更,那么你需要同时操作缓存和数据库,而它们两个又分属不同的系统,因此无法做到同时操作成功或失败,因此在并发读写下很可能出现缓存与数据库数据不一致的情况 理论上可 ...

  5. PlayWright安装及使用

    PlayWright是由业界大佬微软(Microsoft)开源的端到端 Web 测试和自动化库,可谓是大厂背书,功能满格,虽然作为无头浏览器,该框架的主要作用是测试 Web 应用,但事实上,无头浏览器 ...

  6. websocket群聊实战

    演示及源码地址: 演示地址:https://www.wchime.xyz/#/ 后端代码:https://gitee.com/mom925/wchime-web-api 前端代码:https://gi ...

  7. 机器学习周刊 第4期:动手实战人工智能、计算机科学热门论文、免费的基于ChatGPT API的安卓端语音助手、每日数学、检索增强 (RAG) 生成技术综述

    LLM开发者必读论文:检索增强(RAG)生成技术综述! 目录: 1.动手实战人工智能 Hands-on Al 2.huggingface的NLP.深度强化学习.语音课 3.Awesome Jupyte ...

  8. ITS实现可滚动表格

    一.ITS不支持TableControl 在ITS条码开发中,遇到需要滚动浏览表格的需求,但是在ITS中是不支持TableControl,并且已经验证在PDA中显示ALV行不通,因为ALV条目过多无法 ...

  9. 【AcWing】第6场周赛 B题 3734. 求和 (思维)

    AcWing 3734. 求和 其实这道题并不难,只是思维性很强! 因为 \(a\) 的各个数位不包含除了 \(4\) 和 \(7\)​ 以外的其他数字. 仔细观察数据会发现因为 \(1\le l \ ...

  10. 房贷LPR该如何选择

    一.新政是否和你有关? 原文:是指2020年1月1日前金融机构已发放的和已签订合同但未发放的参考贷款基准利率定价的浮动利率贷款(不包括公积金个人住房贷款).   二.新政如何调整? 一种是按照LPR加 ...