• HTTP异步连接池和多线程实践


    今天在查询一个列表的时候,突然发现列表由于之前压测导致几万条脏数据积累。导致找一个数据比较麻烦,由于项目没有提供批量删除的功能,所以想了个办法通过接口把数据挨个删除。

    思路如下:先去请求分页列表,然后解析数据,通过请求删除接口去一条一条的删除。

    虽然比较简单,但是几万条数据还是耗费了比较长的时间,中间进行了一些优化,所以分成了好几个版本来完成。

    第一版:串行请求

    脚本如下:

    public static void main(String[] args) {
        def base = getBase()
        def manager = new TeacherManager(base)
        3.upto(1000) {
            def list = manager.verifyList(it)
            list.getJSONObject("data")?.getJSONArray("list").each { x ->
                manager.verify(x.id, x.tel)
            }
        }
        allOver()
    }
    

    查询列表和删除记录的方法如下:

        public JSONObject verifyList(int page = 3) {
            String url = TeacherManagerApi.VERIFY_LIST;
            JSONObject params = getParams();
            params.put("page", page);
            params.put("page_size", 50);
            JSONObject response = getPostResponse(url, params);
            output(response);
            return response;
        }
        
            public JSONObject verify(int id = 0, String tel = "") {
            String url = TeacherManagerApi.VERIFY;
            JSONObject params = getParams();
            params.put("action", 2);//2:拒绝
            params.put("id", id);
            params.put("tel", tel);
            params.put("refused_result", "清空脏数据");
            JSONObject response = getPostResponse(url, params);
            return response;
        }
    

    第二版:HTTP异步请求优化

    主要是优化了verify方法,每次可以串行获取完列表之后,删除的接口请求就通过异步方法调用。方法如下:

        public JSONObject verify(int id = 0, String tel = "") {
            String url = TeacherManagerApi.VERIFY;
            JSONObject params = getParams();
            params.put("action", 2);//2:拒绝
            params.put("id", id);
            params.put("tel", tel);
            params.put("refused_result", "清空脏数据");
            output(params.toString());
            HttpPost post = getPost(url, params);
            setHeaders(post);
            FanLibrary.excuteSyncWithResponse(post);
            return null;
        }
    

    异步连接池的方法如下:

        /**
         * 异步发送请求
         *
         * @param request
         */
        public static void excuteSync(HttpRequestBase request) {
            if (!ClientManage.httpAsyncClient.isRunning()) ClientManage.httpAsyncClient.start();
            ClientManage.httpAsyncClient.execute(request, null);
        }
    
        /**
         * 异步发送请求获取影响Demo
         * <p>经过测试没卵用</p>
         *
         * @param request
         * @throws ExecutionException
         * @throws InterruptedException
         */
        public static JSONObject excuteSyncWithResponse(HttpRequestBase request) {
            if (!ClientManage.httpAsyncClient.isRunning()) ClientManage.httpAsyncClient.start();
            Future<HttpResponse> execute = ClientManage.httpAsyncClient.execute(request, null);
            try {
                HttpResponse httpResponse = execute.get();
                String content = getContent(httpResponse);
                return getJsonResponse(content, null);
            } catch (Exception e) {
                logger.error("异步请求获取响应失败!", e);
            }
            return new JSONObject();
        }
    

    获取异步连接池的方法:

        /**
         * 通过连接池获取https协议请求对象
         * <p>
         * 增加默认的请求控制器,和请求配置,连接控制器,取消了cookiestore,单独解析响应set-cookie和发送请求的header,适配多用户同时在线的情况
         * </p>
         *
         * @return
         */
        private static CloseableHttpAsyncClient getCloseableHttpAsyncClient() {
            return HttpAsyncClients.custom().setConnectionManager(NconnManager).setSSLHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER).setSSLContext(sslContext).build();
        }
    

    经过测试,异步发送请求的效率果然有所提高,但是有个问题就是不能立刻关闭连接池,不然会导致请求失败,提示连接池已经关闭。

    第三版:多线程

    核心代码如下:

    public static void main(String[] args) {
        def base = getBase()
        def manager = new TeacherManager(base)
        3.upto(100) {
            new Thread({ ->
                def list = manager.verifyList(it)
                list.getJSONObject("data")?.getJSONArray("list").each { x ->
                    manager.verify(x.id, x.tel)
                }
            }).start()
        }
        allOver()
    }
    

    经过测试,多线程比异步效率高太多了,而且异步总会出现一些问题,比如不成功,由于不关心返回了,很多情况也无法调试,如果使用异步加上获取响应值,有会其他操作,我觉得有点绕远路了。最后采取了多线程这个方案。一秒钟能删掉上百条数据,一会儿就删完了。


    • 公众号FunTester首发,更多原创文章:440+原创文章,欢迎关注、交流,禁止第三方擅自转载。

    热文精选

  • 相关阅读:
    SaltStack概述及安装
    Zabbix高可用
    Zabbix数据库表结构
    asp select count(*) 用 open还是excute
    asp+jquery+ajax,asp后台程序执行不正常
    aspupload ,在winows server 2008 下无法使用
    jquery 如何使用innerHTML
    thinkphp的select和find的区别(转)
    centos安装PHP-pdo支持pdo
    Excel 2007 打开 UTF-8 编码 CSV 文件的乱码BUG
  • 原文地址:https://www.cnblogs.com/FunTester/p/13540025.html
Copyright © 2020-2023  润新知