简单利用PoolingHttpClientConnectionManager来优化HttpClient方法,避免httpclient导致的java.net.SocketException: Network is unreachable (connect failed)


简单利用PoolingHttpClientConnectionManager来优化HttpClient方法,避免httpclient导致的排队堆积从而引发java.net.SocketException: Network is unreachable (connect failed)

背景描述(无关问题,可以忽略):

之前因为公司数据库访问速度太慢,导致我所负责的模块查询效率也及低,所以对其数据库方面做了优化,因为sql已经没有太多的优化空间了,所以就对数据库表做了调整。优化过程主要是将几张旧表中合法有效的数据转移到一张新表上,这样避免了每次查询的排查数据是否合法,也省去了两表联查三表联查等降低查询效率的字段。
而问题就出在将旧表数据转移到新表上时,有很多断链需要处理掉。我首先想到的是用HttpClient直接逐个请求,返回200保存到新表中,非200则丢弃。就这样,问题来了:

问题描述

HttpClient连接没有做关闭操作,导致new的httpclient过多造成tomcat假死 or DB死锁。

解决思路

利用httpclient池化技术来保证请求的数量,并且及时关闭无效的请求。

实现过程,直接上代码了

帮助类

/**
 * httpclient池工具类
 * @Author: zhuyu
 * @Date: Create in 18:40:09 2020年12月20日 0020
 */
public class HttpClientHelper {

    static PoolingHttpClientConnectionManager clientPool = new PoolingHttpClientConnectionManager();

    // httpclient请求超时配置
    static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();

    // 将需要配置的值都放到静态代码块中,类被加载时,静态代码块也会被加载
    static {
        // 最大连接请求数
        clientPool.setMaxTotal(5);
        // 最大路由连接数
        clientPool.setDefaultMaxPerRoute(5);
    }
        // 通过getHttpclientPool方法来获取httpclient,避免了直接去手动new
    public static CloseableHttpClient getHttpclientPool() {
        return HttpClients.custom().setConnectionManager(clientPool).setDefaultRequestConfig(requestConfig).build();
    }
}

功能实现类

class Test {

    private static final int SUCCESS_CODE = 200;

    private static final String Read_Timed_Out_ERROR = "Read timed out";

    public static void main(String[] args) {
        // 开始时间
        long startTime = System.currentTimeMillis();
        // 请求链接
        String requestHref = "http://www.baidu.com";
        // 从HttpClient连接池中获取httpclient
        CloseableHttpClient httpClient = HttpClientHelper.getHttpclientPool();
        int times = 0;
        for (int i = 0; i < 50; i++) {
            HttpGet httpGet = new HttpGet(requestHref);
            try {
                CloseableHttpResponse response = httpClient.execute(httpGet);
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != SUCCESS_CODE) {
                    System.out.println("发现断链");
                }
                times++;
            } catch (Exception e) {
                if (Read_Timed_Out_ERROR.equals(e.getMessage())) {
                    System.out.println("连接超时");
                } else {
                    System.out.println("e.getMessage() = " + e.getMessage());
                }
            }finally {
                httpGet.releaseConnection();
            }
        }
        System.out.println("本次请求一共耗时:{" + (System.currentTimeMillis() - startTime) + "}"+"共请求次数 :"+times);
    }
}

最后测试,大功告成。需要注意的是:

实现过程的bug

利用单例模式创建httpclient pool后,直接用httpclienthelper创建了httpclient,然后在关闭时遇到了问题,因为之前设置的最大连接数是5,

所以导致httpclient访问5次后就卡住了,说明请求没有被释放。

尝试直接close httpclient,但这样会导致Connection pool shut down

最终只能把希望寄托于httpGet上了,进入httpGet中寻找方法,果不其然!!

CloseableHttpResponse是可以刷新请求内部状态的,这样既可以使得pool中的五个连接继续发起请求,又可以避免new太多httpclient。

结语:一般如果要重复使用httpclient时,推荐使用连接池去操作,但如果只是请求几次,那么直接new也没什么关系,不过要记得close


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM