1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        RestTemplate 連接池:記一次壓測(cè)調(diào)優(yōu)

        共 3399字,需瀏覽 7分鐘

         ·

        2020-08-22 15:15

        [ 用大白話講解復(fù)雜的技術(shù) ]

        這是我的第?53?篇原創(chuàng)文章
        作者 l 會(huì)點(diǎn)代碼的大叔(CodeDaShu)??


        最近工作上有些調(diào)整,進(jìn)入了另一個(gè)項(xiàng)目組,本周在給一個(gè)接口做壓力測(cè)試的過(guò)程中,發(fā)現(xiàn) TPS 波動(dòng)比較大:?jiǎn)闻_(tái)服務(wù)器的 TPS 在 1000 到 200 之間波動(dòng),發(fā)現(xiàn)問(wèn)題后我們做了這幾件事兒逐一排問(wèn)題。


        1. 排除其他操作對(duì)壓測(cè)的影響

        觀察數(shù)據(jù)的時(shí)間戳,發(fā)現(xiàn)在壓測(cè)過(guò)程中有頻發(fā)的數(shù)據(jù)寫(xiě)入,先暫停跑批操作,再次壓測(cè)波動(dòng)依然存在;


        2. 代碼檢查,降低數(shù)據(jù)庫(kù)查詢次數(shù)

        做代碼檢查,這個(gè)功能需要查詢六次數(shù)據(jù)庫(kù)、調(diào)用一次接口才能獲得所有數(shù)據(jù),經(jīng)過(guò)優(yōu)化后將查詢數(shù)據(jù)庫(kù)的次數(shù)降低為三次,再次壓測(cè)后 TPS 有所提升,但是波動(dòng)的情況還存在;


        3. 分階段壓測(cè),縮小問(wèn)題范圍

        因?yàn)樵摻涌诘倪壿嬍潜镜剡壿?+ 遠(yuǎn)程調(diào)用,于是先做了擋板單壓本地邏輯,再單獨(dú)壓遠(yuǎn)程接口,兩次壓測(cè)不存在波動(dòng)的問(wèn)題,所以基本上可以確定是調(diào)用接口的過(guò)程中存在一些問(wèn)題;


        4. 排除 GC 問(wèn)題

        調(diào)用接口的過(guò)程中創(chuàng)建了太多的 Java 對(duì)象,可能會(huì)引發(fā)頻發(fā)的 GC 操作;但是通過(guò)對(duì) JVM 的觀察排除了這個(gè)問(wèn)題;


        5. 初步確認(rèn)問(wèn)題

        最后將問(wèn)題的范圍縮小,懷疑是 RestTemplate 的使用問(wèn)題;


        RestTemplate 是 Spring 提供的用于訪問(wèn) Http 接口的客戶端框架,能夠大大提高客戶端的編寫(xiě)效率,大部分基于 SSM 或 Spring Boot 的項(xiàng)目會(huì)使用 RestTemplate,翻了一下項(xiàng)目中 RestTemplate Config,只配置了超時(shí)時(shí)間:

        @Configurationpublic class RestTemplateConfig {    @Bean    public RestTemplate restTemplate(){        SimpleClientHttpRequestFactory factory =new SimpleClientHttpRequestFactory();        factory.setConnectTimeout(30000);        factory.setReadTimeout(10000);        RestTemplate restTemplate = new RestTemplate(factory);        return restTemplate;    }}


        RestTemplate 默認(rèn)的?

        ClientHttpRequestFactor?

        SimpleClientHttpRequestFactory,其中的 createRequest 方法,每次都會(huì)創(chuàng)建一個(gè)新的連接,建立連接本身就是一個(gè)費(fèi)時(shí)費(fèi)力的操作,如果頻繁地對(duì)一個(gè)接口發(fā)起調(diào)用,每次都創(chuàng)建連接會(huì)造成極大的資源浪費(fèi),而且若連接不能及時(shí)釋放,就會(huì)因?yàn)闊o(wú)法建立新的連接導(dǎo)致后面的請(qǐng)求阻塞。

        @Overridepublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {  HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);  prepareConnection(connection, httpMethod.name());
        if (this.bufferRequestBody) { return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming); } else { return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming); }}


        看到這種情況處理起來(lái)也算簡(jiǎn)單:弄個(gè)連接池;


        創(chuàng)建 RestTemplate連接線程池,就需要使用其他的 HTTP 庫(kù)(默認(rèn)使用的是 JDK 自己的),比如 HttpComponents、Netty、OkHttp,在這里我選擇的是 HttpComponents 。


        1. 引入依賴:

        <dependency>    <groupId>org.apache.httpcomponentsgroupId>    <artifactId>httpcoreartifactId>    <version>version>dependency>
        <dependency> <groupId>org.apache.httpcomponentsgroupId> <artifactId>httpclientartifactId> <version>version>dependency>


        2. 修改 RestTemplateConfig :

        @Configurationpublic?class?RestTemplateConfig?{    @Bean    public RestTemplate restTemplate() {        return new RestTemplate(httpRequestFactory());    }
        @Bean public ClientHttpRequestFactory httpRequestFactory() { return new HttpComponentsClientHttpRequestFactory(httpClient()); }
        @Bean public HttpClient httpClient() { Registry registry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); //設(shè)置整個(gè)連接池最大連接數(shù) connectionManager.setMaxTotal(400); //路由是對(duì)maxTotal的細(xì)分 connectionManager.setDefaultMaxPerRoute(100); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(30000) //返回?cái)?shù)據(jù)的超時(shí)時(shí)間????????????????.setConnectTimeout(10000)?//連接上服務(wù)器的超時(shí)時(shí)間 .setConnectionRequestTimeout(1000) //從連接池中獲取連接的超時(shí)時(shí)間 .build(); return HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(connectionManager) .build(); }}


        修改完成之后再次壓測(cè),單機(jī) TPS 穩(wěn)定在 1200,打完收工。


        期待分享

        如果您喜歡本文,請(qǐng)點(diǎn)個(gè)“在看”或分享到朋友圈,這將是對(duì)我最大的鼓勵(lì)。



        瀏覽 173
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            三级小说视频 | 丰满秘书办公室猛烈进出在办公室 | 黄色视频免费网站 | AAAAAA片毛片免费观 | 女人18片毛片90分钟免费 | 操笔123 | 韩国毛片无码 | 逼逼小视频 | 色悠悠导航 | 视频一区免费观看 |