最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

restTemplate未設置連接數(shù)導致服務雪崩問題以及解決

 更新時間:2024年10月29日 14:24:16   作者:萊特昂  
面對線上問題,仔細分析原因,及時調(diào)整配置,能有效解決問題,本文詳細描述了線上遇到流量突增引發(fā)的問題,通過查看代碼和連接池信息,分析出問題的原因是連接池滿了,連接池大小配置不足以應對大并發(fā)流量,通過調(diào)整連接池大小配置

背景

昨天發(fā)版遇到個線上問題,由于運維操作放量時隔離機器過多,導致只有大概三分之一的機器承載全部流量,等于單臺機器的流量突增至正常時候的三倍。

前置對外的api服務開始瘋狂報錯:

ConnectionPoolTimeoutException:Timeout warning for connection from pool

問題分析

連接池滿了。

查看下相關(guān)代碼,用了restTemplate去調(diào)用另外一個子系統(tǒng),繼續(xù)查看關(guān)于連接池的信息:

org.apache.http.conn.ConnectionPoolTimeoutException 是 Apache HttpClient 拋出的一種 山異常,表示從連接池獲取連接超時。

這種異常通常是由以下原因?qū)е拢?/p>

1.連接池中沒有可用的連接。當請求到達時,如果連接池中沒有可用的連接,就會嘗試創(chuàng)建新的連接。如果創(chuàng)建連接的速度很慢,或者連接池中的連接已經(jīng)用完了,就會出現(xiàn)ConnectionPoolTimeoutException 異常。

2.連接池中的連接都被占用。如果連接池中的所有連接都正在被占用,而且沒有連接釋放回池中,就會導致連接池超時異常。3.請求超時時間設置過短。如果設置的請求超時時間過短,就可能在等待連接的過程中超時。

迅速去查看連接池大小配置了多少,發(fā)現(xiàn)并沒有進行相關(guān)的配置,那默認的就是2,這樣遠遠不夠應對當前瞬時的大并發(fā)流量的。

問題解決

立刻進行了相關(guān)配置:

@Bean
public RestTemplate buildRestTemplate(){
    final ConnectionKeepAliveStrategy myStrategy = (response, context) -> {
        return 5 * 1000;//設置一個鏈接的最大存活時間
    };
    MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
    // 總連接數(shù)
    pollingConnectionManager.setMaxTotal(1000);
    // 同路由的并發(fā)數(shù)
    pollingConnectionManager.setDefaultMaxPerRoute(1000);
    HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(pollingConnectionManager)
    .setKeepAliveStrategy(myStrategy).build();
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
    httpClient);
    factory.setConnectTimeout(3000);
    factory.setReadTimeout(5000);
    return new RestTemplate(factory);
}

直接設置成了1000,交給測試壓測,瞬時200的并發(fā)量壓測也沒有出現(xiàn)ConnectionPoolTimeoutException的問題,看來成功解決了。

restTemplate優(yōu)化點補充

另外,restTemplate還有個點能夠優(yōu)化。

1. RestTemplate 介紹

RestTemplate和Spring提供的JdbcTemplate類似,對象一旦構(gòu)建(使用過程中不對其屬性進行修改)就是線程安全的,多線程環(huán)境下可以安全使用。

2. 場景描述

A系統(tǒng)接口需要訪問B系統(tǒng)接口,正常請求時,這部分代碼耗時不是很明顯(約10ms)。后來,進行接口壓力測試,發(fā)現(xiàn)請求耗時長達500ms,導致整個接口的tps很難上去,調(diào)整線程池參數(shù)效果努力無果,后來對請求B系統(tǒng)接口做了內(nèi)存級別的緩存(guava),tps增長了3倍左右(約500)。

3.問題分析

B系統(tǒng)給出的壓測數(shù)據(jù)顯示,單實例接口的tps在1000+,因此初步排除了B系統(tǒng)接口性能差的可能。于是,開始深究系統(tǒng)本身代碼可能存在的問題。

最開始的代碼編寫方式如下:

String url = "xxx.com/api"';
RestTemplate restTemplate = new RestTemplate();
MemeberCardCodeRspDTO result = restTemplate.getForObject(url, MemeberCardCodeRspDTO.class);
System.out.println(result != null ? result.getMsg() : "null");

看上去簡單明了,兩行代碼搞定,非常優(yōu)雅。

后來在組長大大的幫助下,大致定位了問題點,覺得該部分代碼可能存在部分性能問題,應該抽取成單實例,即不能每次使用時重新new一個新的對象。

改造后的代碼為:

@Bean
public RestTemplate buildRestTemplate(){
    final ConnectionKeepAliveStrategy myStrategy = (response, context) -> {
        return 5 * 1000;//設置一個鏈接的最大存活時間
    };
    MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
    // 總連接數(shù)
    pollingConnectionManager.setMaxTotal(1000);
    // 同路由的并發(fā)數(shù)
    pollingConnectionManager.setDefaultMaxPerRoute(1000);
    HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(pollingConnectionManager)
    .setKeepAliveStrategy(myStrategy).build();
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
    httpClient);
    factory.setConnectTimeout(3000);
    factory.setReadTimeout(5000);
    return new RestTemplate(factory);
}

直接依賴spring bean注解將其定義成單實例對象,其他地方直接屬性注入后使用。

4. 性能分析

問題得到解決后,課余時間又對該部分代碼做了一個粗略的定量分析,本機跑的數(shù)據(jù),還是能比較清晰地得出結(jié)論。

private final String url = "xxxx.com/api";
private int loopCount = 400;
private int concurrentThread = 400;
private RestTemplate restTemplate;

@BeforeTest
public void init() {
   final ConnectionKeepAliveStrategy myStrategy = (response, context) -> {
        return 5 * 1000;//設置一個鏈接的最大存活時間
   };
   PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
   // 總連接數(shù)
   pollingConnectionManager.setMaxTotal(1000);
   // 同路由的并發(fā)數(shù)
   pollingConnectionManager.setDefaultMaxPerRoute(1000);
   HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(pollingConnectionManager)
   .setKeepAliveStrategy(myStrategy).build();
   HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
   httpClient);
   factory.setConnectTimeout(3000);
   factory.setReadTimeout(5000);
   restTemplate = new RestTemplate(factory);
}
@Test
public void testHttp1() {
  long start = System.currentTimeMillis();
  ExecutorService executor = Executors.newFixedThreadPool(concurrentThread);
  for (int i =0 ; i< loopCount; i++){
      executor.submit(() -> {
          MemeberCardCodeRspDTO result = restTemplate.getForObject(url, MemeberCardCodeRspDTO.class);
          System.out.println(result != null ? result.getMsg() : "null");
      });
  }
  try {
      executor.shutdown();
      executor.awaitTermination(30, TimeUnit.MINUTES); // or longer.
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
   long time = System.currentTimeMillis() - start;
   System.out.printf("Tasks1 took %d ms to run%n", time);
}

@Test
public void testHttp2() {
   long start = System.currentTimeMillis();
   ExecutorService executor = Executors.newFixedThreadPool(concurrentThread);
   for (int i =0 ; i< loopCount; i++){
       executor.submit(() -> {
           RestTemplate restTemplate = new RestTemplate();
           MemeberCardCodeRspDTO result = restTemplate.getForObject(url, MemeberCardCodeRspDTO.class);
           ystem.out.println(result != null ? result.getMsg() : "null");
       });
   }
   try {
        executor.shutdown();
        executor.awaitTermination(30, TimeUnit.MINUTES); // or longer.
   } catch (InterruptedException e) {
        e.printStackTrace();
   }
   long time = System.currentTimeMillis() - start;
   System.out.printf("Tasks2 took %d ms to run%n", time);
}

調(diào)整threads數(shù)量,跑了6組數(shù)據(jù),結(jié)果對比如下:

圖中比較清晰的可以看出,優(yōu)化過后的代碼性能提升比較明顯,且隨著并發(fā)任務數(shù)增加,耗時波動不會太大。

問題總結(jié)

第三方庫提供的各種方便的類,簡化了編碼復雜度,方便了開發(fā)者。使用不恰當時,細微的編碼可能埋藏著大的隱患。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot接口返回數(shù)據(jù)類型全面解析

    springboot接口返回數(shù)據(jù)類型全面解析

    這篇文章主要介紹了springboot接口返回數(shù)據(jù)類型問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java畢業(yè)設計實戰(zhàn)之仿小米電子產(chǎn)品售賣商城系統(tǒng)的實現(xiàn)

    Java畢業(yè)設計實戰(zhàn)之仿小米電子產(chǎn)品售賣商城系統(tǒng)的實現(xiàn)

    這是一個使用了java+SpringBoot+Vue+MySQL+Redis+ElementUI開發(fā)的仿小米商城系統(tǒng),是一個畢業(yè)設計的實戰(zhàn)練習,具有小米商城該有的所有基礎功能,感興趣的朋友快來看看吧
    2022-01-01
  • Logstash配置Java日志格式的方法小結(jié)

    Logstash配置Java日志格式的方法小結(jié)

    Logstash 是用于日志收集的開源工具,通常與 Elasticsearch 和 Kibana 一起使用,形成 ELK Stack,Logstash 非常靈活,可以通過配置文件(通常是 .conf 文件)來定義數(shù)據(jù)的輸入、處理和輸出,本文給大家介紹了Logstash配置Java日志格式的方法,需要的朋友可以參考下
    2024-09-09
  • Java調(diào)用微信支付功能的方法示例代碼

    Java調(diào)用微信支付功能的方法示例代碼

    這篇文章主要介紹了Java調(diào)用微信支付功能的方法示例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • springboot?filter配置多個時,執(zhí)行順序問題

    springboot?filter配置多個時,執(zhí)行順序問題

    這篇文章主要介紹了springboot?filter配置多個時,執(zhí)行順序問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 一文詳解SpringBoot?Redis多數(shù)據(jù)源配置

    一文詳解SpringBoot?Redis多數(shù)據(jù)源配置

    Spring?Boot默認只允許一種?Redis?連接池配置,且配置受限于?Lettuce?包,不夠靈活,所以本文將為大家介紹如何自定義Redis配置方案實現(xiàn)多數(shù)據(jù)源支持,需要的可以參考下
    2024-11-11
  • Spring Bean 中的生命周期和獲取方式詳解

    Spring Bean 中的生命周期和獲取方式詳解

    Bean的加載和獲取過程涉及配置文件解析、資源加載、XML解析和BeanDefinition注冊等步驟,本文給大家介紹Spring Bean 的生命周期和獲取方式,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • 詳解JAVA類加載機制(推薦)

    詳解JAVA類加載機制(推薦)

    這篇文章主要介紹了JAVA類加載機制的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • 解析Java多線程之常見鎖策略與CAS中的ABA問題

    解析Java多線程之常見鎖策略與CAS中的ABA問題

    本篇文章介紹了常見的鎖策略,并說明了synchronized關(guān)鍵字加的鎖類型不是單一一種鎖類型的,根據(jù)可重入鎖與非可重入鎖引出了死鎖的概念與死鎖條件,最后介紹了CAS指令以及CAS鎖產(chǎn)生的ABA問題及其解決方案,需要的朋友可以參考下
    2022-06-06
  • Java實現(xiàn)統(tǒng)計字符串出現(xiàn)的次數(shù)

    Java實現(xiàn)統(tǒng)計字符串出現(xiàn)的次數(shù)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)統(tǒng)計字符串出現(xiàn)的次數(shù),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評論

望城县| 蕲春县| 屯门区| 二连浩特市| 陕西省| 景洪市| 肥乡县| 丽水市| 和平区| 前郭尔| 迁安市| 西藏| 河间市| 繁峙县| 高淳县| 根河市| 视频| 阿合奇县| 芜湖县| 临城县| 太白县| 林周县| 隆化县| 黎城县| 石河子市| 个旧市| 武城县| 安丘市| 广平县| 潼南县| 陈巴尔虎旗| 冀州市| 田东县| 扎兰屯市| 上思县| 长子县| 永善县| 乌拉特前旗| 聂荣县| 岱山县| 江川县|