RestTemplate线程池问题,【timeout waiting for connection from pool】

RestTemplate介绍

RestTemplate是Spring框架提供的一个用于发送HTTP请求的同步客户端工具,它简化了与Restful服务进行交互的过程,提供了一系列便捷的方法来处理常见的HTTP请求,如GET、POST、PUT、DELETE等,RestTemplate会自动处理HTTP请求和响应的序列号和反序列化,让开发者可以更专注于业务逻辑的实现。

代码示例

/**
     * 转发
     * @param request
     * @param url
     * @return
     */
    public ResponseEntity distribute(HttpServletRequest request, String url) {
        try {
            RequestEntity requestEntity = this.createRequestEntity(request, url);
            return this.restTemplate.exchange(requestEntity, Object.class);
        } catch (Exception var7) {
            log.error("distribute_error",e);
            throw new RuntimeException("distribute_error");
        }
    }

    /**
     * 组装请求实体
     * @param request
     * @param url
     * @return
     * @throws URISyntaxException
     * @throws IOException
     */
    private RequestEntity createRequestEntity(HttpServletRequest request, String url) throws URISyntaxException, IOException {
        String method = request.getMethod();
        HttpMethod httpMethod = HttpMethod.resolve(method);
        MultiValueMap<String, String> headers = this.parseRequestHeader(request, url);
        byte[] body = this.parseRequestBody(request);
        return new RequestEntity(body, headers, httpMethod, new URI(url));
    }

    /**
     * 解析请求头
     * @param request
     * @param url
     * @return
     * @throws URISyntaxException
     */
    private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request, String url) throws URISyntaxException {
        HttpHeaders headers = new HttpHeaders();
        List<String> headerNames = Collections.list(request.getHeaderNames());
        Iterator var = headerNames.iterator();
        while(var.hasNext()) {
            String headerName = (String)var.next();
            List<String> headerValues = Collections.list(request.getHeaders(headerName));
            Iterator var1 = headerValues.iterator();
            while(var1.hasNext()) {
                String headerValue = (String)var1.next();
                headers.add(headerName, headerValue);
            }
        }
        headers.setHost(this.getInetSocketAddress(url));
        return headers;
    }

    /**
     * 解析请求体
     * @param request
     * @return
     * @throws IOException
     */
    private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
        InputStream inputStream = request.getInputStream();
        return StreamUtils.copyToByteArray(inputStream);
    }

    private InetSocketAddress getInetSocketAddress(String url) throws URISyntaxException {
        URI newUri = new URI(url);
        int port = newUri.getPort();
        //默认端口配置
        if (newUri.getPort() == -1) {
            if ("http".equals(newUri.getScheme())) {
                port = 80;
            } else if ("https".equals(newUri.getScheme())) {
                port = 443;
            }
        }
        return new InetSocketAddress(newUri.getHost(), port);
    }

问题描述

前期流量较小,转发请求都正常,后面请求接口流量增加,1小时20w左右并发,开始有大量连接池失败的异常日志【timeout waiting for connection from pool】,上游有大量500报错。请求转发成功20万,失败了5万+

问题处理

spring的RestTemplate底层是Apache HttpClient,HttpClient是支持池化技术的。HttpClient使用的版本是4.5.14。默认的连接池配置如下:

maxTotal:连接池中所有连接的最大数量。这个值决定了在任何时刻,连接池可以持有的最大连接数。如果达到这个限制,客户端会等待可用连接,默认值是20

defaultMaxPerRoute:每个路由(即每个目标服务器地址)的最大连接数。路由是指一个特定的主机和端口组合。这意味着对于同一个目标服务器,你可以同时保持的最大连接数。默认值是2

ConnectionRequestTimeout连接超时时间为-1

经过排查发现,HttpClient使用的版本为4.5.X,默认的路由连接数为2,无法满足高并发场景。分别修改连接池参数配置maxTotal=2000,defaultMaxPerRoute=100。具体的设置依据如下:

客户端服务实例有30个,每个线程单独处大概500ms以内,设置了defaultMaxPerRoute=100,能支持大概6000TPS的并发,满足当前业务需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值