日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

【故障現場】多線程性能優化最大的坑,99%人都不自知

來源: 責編: 時間:2024-01-22 17:25:45 329觀看
導讀1. 問題&分析當我們在處理慢接口問題時,經常會使用多線程技術,將能夠并行處理的任務拆分到不同的線程中處理,等任務處理完成后,再收集各線程的處理結果,進行后續的處理。整體思路如下圖所示:圖片這樣可以將并行部分的總耗時

1. 問題&分析

當我們在處理慢接口問題時,經常會使用多線程技術,將能夠并行處理的任務拆分到不同的線程中處理,等任務處理完成后,再收集各線程的處理結果,進行后續的處理。整體思路如下圖所示:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

這樣可以將并行部分的總耗時從 sum 降為 max,從而大幅降低接口的響應時間。RlW28資訊網——每日最新資訊28at.com

1.1. 案例

訂單詳情頁耗時嚴重,p99 將近3秒,已經驗證影響用戶體驗,本次迭代小艾專門對該接口進行優化。迭代剛上線,該接口的響應時間大幅降低,p99 降低到 800 毫秒以內,大家紛紛向小艾發來祝賀。但好景不長,隨著流量的增加,接口響應時間也在逐漸變長,p99 超過 5 秒,最后系統拋出大量的 RejectedExecutionException 異常,這個接口不可用。最終,QA伙伴火速進行回滾操作,系統恢復正常。RlW28資訊網——每日最新資訊28at.com

系統恢復后,小艾仔細查看系統監控,CPU使用率并不高,內存也處于正常水位,接口性能居然比優化前還差,真心不知道哪里出了問題。RlW28資訊網——每日最新資訊28at.com

優化前代碼:RlW28資訊網——每日最新資訊28at.com

public RestResult<OrderDetailVO> getOrderDetail(@PathVariable Long orderId){        Stopwatch stopwatch = Stopwatch.createStarted();        OrderService.Order order = this.orderService.getById(orderId);        if (order == null){            return RestResult.success(null);        }        OrderDetailVO orderDetail = new OrderDetailVO();        orderDetail.setUser(userService.getById(order.getUserId()));        orderDetail.setAddress(addressService.getById(order.getUserAddressId()));        orderDetail.setCoupon(couponService.getById(order.getCouponId()));        orderDetail.setProduct(productService.getById(order.getProductId()));        log.info("串行 Cost {} ms", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));        return RestResult.success(orderDetail);}

優化前耗時:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

優化后代碼:RlW28資訊網——每日最新資訊28at.com

public RestResult<OrderDetailVO> getOrderDetailNew(@PathVariable Long orderId){        Stopwatch stopwatch = Stopwatch.createStarted();        OrderService.Order order = this.orderService.getById(orderId);        if (order == null){            return RestResult.success(null);        }        Future<UserService.User> userFuture = this.executorService.submit(() -> userService.getById(order.getUserId()));        Future<AddressService.Address> addressFuture = this.executorService.submit(() -> addressService.getById(order.getUserAddressId()));        Future<CouponService.Coupon> couponFuture = this.executorService.submit(() -> couponService.getById(order.getCouponId()));        Future<ProductService.Product> productFuture = this.executorService.submit(() -> productService.getById(order.getProductId()));        OrderDetailVO orderDetail = new OrderDetailVO();        orderDetail.setUser(getFutureValue(userFuture));        orderDetail.setProduct(getFutureValue(productFuture));        orderDetail.setAddress(getFutureValue(addressFuture));        orderDetail.setCoupon(getFutureValue(couponFuture));        log.info("并行 Cost {} ms", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));        return RestResult.success(orderDetail);    }

優化后耗時:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

可見采用并行優化后,接口的響應時間從 4 秒 將至 1 秒,效果還是非常明顯的。RlW28資訊網——每日最新資訊28at.com

但,繼續加大請求量,系統便出現問題,如下圖所示:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

圖片RlW28資訊網——每日最新資訊28at.com

在流量逐漸增加的過程中,從日志中可以得到以下信息:RlW28資訊網——每日最新資訊28at.com

初期耗時穩定,基本在 1 秒左右RlW28資訊網——每日最新資訊28at.com

接口耗時逐漸增大,甚至遠超串行處理的耗時(大于 4 秒)RlW28資訊網——每日最新資訊28at.com

有些請求直接拋出 RejectedExecutionException 異常RlW28資訊網——每日最新資訊28at.com

1.2. 問題分析

從代碼中并未發現任何問題,設計思路也非常清晰,其核心問題在線程池使用上,項目線程池配置如下:RlW28資訊網——每日最新資訊28at.com

int coreSize = Runtime.getRuntime().availableProcessors();executorService = new ThreadPoolExecutor(coreSize, coreSize * 5,        5L, TimeUnit.MINUTES,        new LinkedBlockingQueue<Runnable>(1024)        );

核心配置為:RlW28資訊網——每日最新資訊28at.com

  1. 核心線程數為 cpu 核數
  2. 最大線程數為 cpu 核數的 5 倍
  3. 空閑線程存活時間為 5 分鐘
  4. 任務隊列為 LinkedBlockingQueue 大小為 1024

在這個配置下,我們推演下以上的三個現象。RlW28資訊網——每日最新資訊28at.com

1.2.1. 線程資源充足

如下圖所示:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

整體流程如下:RlW28資訊網——每日最新資訊28at.com

  1. 主線程向線程池提交 Task
  2. 由于線程處于空閑狀態,立即接受并處理問題
  3. 線程池線程處理完任務,將最終的處理結果寫回到 Future
  4. 主線程等待所有任務執行完成,獲取所有執行結果,然后執行后續流程

這正是想要的執行結果,任務被并行執行,大幅降低接口耗時。RlW28資訊網——每日最新資訊28at.com

1.2.2. 任務進入等待隊列

隨著流量的增加,所有的核心線程都處于忙碌狀態,此時新任務將進入等待隊列,具體如下:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

整體流入如下:RlW28資訊網——每日最新資訊28at.com

  1. 主線程向線程池提交任務
  2. 由于沒有核心線程可用,任務被放置到任務隊列
  3. 主線程進入等待狀態,等待時間包括兩部分:

任務在隊列中等待線程調度時間RlW28資訊網——每日最新資訊28at.com

任務分配到線程后,任務實際執行時間RlW28資訊網——每日最新資訊28at.com

  1. 如果前面等待的任務非常多,那等待時間將變的非常長

主線程等待時間 = 隊列等待時間 + 任務執行時間。當任務隊列非常長時,整體時間將遠超串行執行時間。RlW28資訊網——每日最新資訊28at.com

1.2.3. 資源耗盡觸發拒絕策略

流量繼續增加,線程池的任務隊列已滿并且線程數量也達到上限,此時會觸發拒絕策略,具體如下:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

線程池默認拒絕策略為:AbortPolicy,直接拋出 RejectedExecutionException,從而觸發接口異常。RlW28資訊網——每日最新資訊28at.com

還有更可怕的情況,就是部分提交,也就是主線程已經成功提交幾個任務,如下圖所示:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

核心流程如下:RlW28資訊網——每日最新資訊28at.com

  1. 主線程已經成功提交兩個任務
  2. 在提交第三個任務時,由于資源不夠觸發拒絕策略,拋出異常導致主線程提前結束
  3. 已經成功提交的任務仍舊會被線程執行,由于主線程已經退出,執行結果沒有任何意義,從而白白浪費系統資源

2. 解決方案

前面已經分析的很清楚,問題的本質就是線程池資源分配不合理,核心參數設置錯誤:RlW28資訊網——每日最新資訊28at.com

  1. 隊列設置錯誤。在該場景下,需要充分利用線程資源,將任務放入隊列會增加任務在隊列的等待時間,隊列長度越大對系統的傷害越大;
  2. 拒絕策略設置錯誤。直接拋出異常會中斷主流程,導致部分無效任務(無意義任務)提交,白白浪費系統資源;

除線程池參數問題外,還有個小問題:主線程完成任務提交后處于等待狀態,未執行任何有意義的操作,存在資源浪費。RlW28資訊網——每日最新資訊28at.com

2.1. 線程池改進方案

改進線程池如下所示:RlW28資訊網——每日最新資訊28at.com

int coreSize = Runtime.getRuntime().availableProcessors();executorService = new ThreadPoolExecutor(coreSize, coreSize * 5,        5L, TimeUnit.MINUTES,        new SynchronousQueue<>(),        new ThreadPoolExecutor.CallerRunsPolicy()        );

線程池配置如下:RlW28資訊網——每日最新資訊28at.com

  1. 核心線程數不變,仍舊是 cpu 數;
  2. 最大線程數不變,仍舊是 cpu 數的5倍;
  3. 空閑線程存活時間不變,仍舊是 5 分鐘;
  4. 使用 SynchronousQueue 替代 LinkedBlockingQueue(1024)。SynchronousQueue 是一個特殊的隊列,其最大容量是1。也就是說,任何一次插入操作都必須等待一個相應的刪除操作,反之亦然。如果沒有相應的操作正在進行,則該線程將被阻塞;
  5. 指定拒絕策略為 CallerRunsPolicy。當線程池資源不夠時,由主線程來執行任務;

在這個配置下,及時線程池中的所有資源全部耗盡,也只會降級到串行執行,不會讓系統變的更糟糕。RlW28資訊網——每日最新資訊28at.com

新配置下,系統表現如下:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

在最差的情況下也僅僅與串行執行耗時一致。RlW28資訊網——每日最新資訊28at.com

總體來說就一句話:線程池有資源可用,那就為主線程分擔部分壓力;如果沒有資源可用,那就由主線程獨自完成。RlW28資訊網——每日最新資訊28at.com

2.1. 充分利用主線程

上面提到一個小問題,在資源充足情況下,所有任務均有線程池線程完成,主線程一致處于等待狀態,存在一定的資源浪費。RlW28資訊網——每日最新資訊28at.com

如下圖所示:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

3 個任務耗費 4 個線程資源:RlW28資訊網——每日最新資訊28at.com

  1. 線程池3個線程負責執行任務
  2. 主線程等待執行結果,一直處于阻塞狀態

為了充分利用線程資源,可以讓主線程負責執行任意一個任務。如下圖所示:RlW28資訊網——每日最新資訊28at.com

圖片圖片RlW28資訊網——每日最新資訊28at.com

主線程不在盲目等待,也負責一個任務的執行,這樣 3 個任務只需 3 個線程即可。RlW28資訊網——每日最新資訊28at.com

代碼上也非常簡單,具體如下:RlW28資訊網——每日最新資訊28at.com

public RestResult<OrderDetailVO> getOrderDetailNew(@PathVariable Long orderId){    Stopwatch stopwatch = Stopwatch.createStarted();    OrderService.Order order = this.orderService.getById(orderId);    if (order == null){        return RestResult.success(null);    }    Future<UserService.User> userFuture = this.executorService.submit(() -> userService.getById(order.getUserId()));    Future<AddressService.Address> addressFuture = this.executorService.submit(() -> addressService.getById(order.getUserAddressId()));    Future<CouponService.Coupon> couponFuture = this.executorService.submit(() -> couponService.getById(order.getCouponId()));//        Future<ProductService.Product> productFuture = this.executorService.submit(() -> productService.getById(order.getProductId()));    OrderDetailVO orderDetail = new OrderDetailVO();    // 由主線程負責運行    orderDetail.setProduct(productService.getById(order.getProductId()));    orderDetail.setUser(getFutureValue(userFuture));    orderDetail.setAddress(getFutureValue(addressFuture));    orderDetail.setCoupon(getFutureValue(couponFuture));    log.info("并行 Cost {} ms", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));    return RestResult.success(orderDetail);}

主線程執行不同的任務,會對接口的響應時間產生影響嗎?RlW28資訊網——每日最新資訊28at.com

不會,并行執行整體耗時為 max(任務耗時),主線程必須獲取全部結果才能運行,所以必須等待這么長時間。RlW28資訊網——每日最新資訊28at.com

  1. 如果主線程運行的任務不是最耗時任務,則需要等待最耗時任務執行完成才能執行后續邏輯;
  2. 如果主線程運行的是最耗時任務,則其他線程已經執行完成并提前釋放資源;

3. 示例&源碼

代碼倉庫:https://gitee.com/litao851025/learnFromBugRlW28資訊網——每日最新資訊28at.com

代碼地址:https://gitee.com/litao851025/learnFromBug/tree/master/src/main/java/com/geekhalo/demo/thread/paralleltaskRlW28資訊網——每日最新資訊28at.com


RlW28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-66204-0.html【故障現場】多線程性能優化最大的坑,99%人都不自知

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: CSS 滾動驅動動畫實現圓弧滾動條

下一篇: 牢記這 16 個 SpringBoot 擴展接口,寫出更加漂亮的代碼

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
亚洲欧美在线一区二区| 国产亚洲一区二区三区在线观看| 美国三级日本三级久久99| 久久久久久久久综合| 男女精品网站| 欧美午夜不卡在线观看免费| 国产精品网红福利| 激情欧美亚洲| 99视频有精品| 欧美一级欧美一级在线播放| 久久影视精品| 亚洲国产日韩一区二区| 亚洲精品综合精品自拍| 亚洲欧美电影在线观看| 久久人人97超碰精品888| 欧美女人交a| 欧美性天天影院| 韩日精品中文字幕| 日韩视频在线一区| 久久疯狂做爰流白浆xx| 欧美国产日韩一区二区| 国产伦精品一区二区三区四区免费| 狠狠色狠狠色综合日日tαg| 一个色综合av| 亚洲精品视频在线观看免费| 亚洲免费视频在线观看| 麻豆av福利av久久av| 国产精品xvideos88| 亚洲大片在线观看| 亚洲欧美日韩精品久久久久| 你懂的一区二区| 国产欧美日韩亚州综合| 日韩视频在线观看免费| 久久先锋影音av| 国产精品亚洲产品| 日韩视频一区二区三区在线播放免费观看| 欧美一区不卡| 欧美色另类天堂2015| 在线观看一区| 欧美一级淫片播放口| 欧美日韩一区高清| 亚洲国产精品va在线看黑人动漫| 午夜在线精品偷拍| 欧美日韩在线播| 亚洲国产综合91精品麻豆| 欧美一级黄色录像| 欧美午夜欧美| 亚洲日本视频| 麻豆成人精品| 国产一区二区三区的电影| 在线视频你懂得一区| 欧美成人亚洲成人| 欲香欲色天天天综合和网| 有码中文亚洲精品| 日韩视频精品在线| 老鸭窝亚洲一区二区三区| 国产一区二区你懂的| 亚洲欧美一区二区三区久久 | 99视频精品全部免费在线| 久久一区二区精品| 国产手机视频一区二区| 亚洲一区二区三区777| 欧美精品在线免费| 亚洲欧洲精品一区二区三区 | 久久精品视频在线看| 国产女人精品视频| 亚洲欧美视频一区| 国产精品久久久久一区二区| 一区二区三区高清在线观看| 欧美精品18| 亚洲狠狠丁香婷婷综合久久久| 久久久视频精品| 韩国女主播一区二区三区| 欧美综合二区| 国产午夜精品美女视频明星a级 | 在线综合+亚洲+欧美中文字幕| 欧美精品18| 日韩午夜av| 欧美日韩视频在线观看一区二区三区| 亚洲人体影院| 欧美日本国产精品| 亚洲最新中文字幕| 欧美视频在线观看| 亚洲午夜在线| 国产精品一区二区三区乱码| 午夜精彩国产免费不卡不顿大片| 国产精品一区二区男女羞羞无遮挡| 亚洲欧美日韩在线| 国产婷婷色一区二区三区在线 | 亚洲午夜精品| 国产精品热久久久久夜色精品三区| 亚洲欧美中文日韩v在线观看| 国产欧美91| 久久久午夜电影| 亚洲电影中文字幕| 欧美另类一区| 亚洲综合二区| 国产视频亚洲精品| 久久一区激情| 亚洲精品在线一区二区| 欧美性大战xxxxx久久久| 亚洲欧美综合另类中字| 国内在线观看一区二区三区| 免费人成精品欧美精品| 夜夜嗨av一区二区三区网页| 国产精品乱人伦中文| 久久aⅴ国产紧身牛仔裤| 在线成人黄色| 欧美日韩美女在线| 欧美亚洲免费| 1769国内精品视频在线播放| 欧美另类久久久品 | 欧美国产精品中文字幕| 亚洲图片欧洲图片av| 国产亚洲欧美在线| 欧美成人久久| 国产一区二区高清| 麻豆精品视频在线观看视频| 99国产精品久久久久久久| 国产精品电影观看| 久久九九99| 亚洲精品视频在线观看网站 | 亚洲美女av电影| 国产精品日韩二区| 久久综合婷婷| 亚洲色诱最新| 韩日欧美一区二区| 欧美日韩在线大尺度| 欧美一区永久视频免费观看| 久久婷婷综合激情| 最新国产拍偷乱拍精品| 国产精品日本精品| 麻豆国产精品va在线观看不卡| 在线亚洲欧美视频| 在线观看精品一区| 欧美调教视频| 美女精品自拍一二三四| 亚洲欧美国产高清| 亚洲国产一区二区视频| 国产伦精品一区二区三区免费迷| 欧美不卡激情三级在线观看| 亚洲一区二区三区免费观看| 永久域名在线精品| 国产精品家教| 亚洲一区二区在线观看视频| 黄色成人小视频| 欧美性猛交视频| 美女免费视频一区| 亚洲欧美日韩网| 亚洲精品国精品久久99热| 国产女精品视频网站免费| 欧美精品自拍偷拍动漫精品| 久久精品国产亚洲精品| 一区二区三区久久久| 在线日韩中文字幕| 国产欧美日韩亚洲| 欧美午夜精品理论片a级大开眼界| 久久午夜视频| 亚洲欧美日韩在线| 99精品国产一区二区青青牛奶 | 在线一区二区三区四区五区| 亚洲福利在线看| 国产午夜精品一区二区三区视频 | 亚洲综合精品| 亚洲免费观看| 亚洲第一在线| 国产在线精品成人一区二区三区| 欧美午夜精彩| 欧美噜噜久久久xxx| 久久另类ts人妖一区二区| 欧美一级播放| 亚洲欧美久久| 亚洲视频在线观看视频| 亚洲久久一区二区| 亚洲国产第一| 影音先锋日韩精品| 国产主播精品| 国产欧美一区二区三区在线看蜜臀| 欧美日韩一区二区精品| 欧美激情精品久久久久久久变态 | 久久高清一区| 小黄鸭精品密入口导航| 亚洲一区久久久| 在线亚洲电影| 亚洲伦理久久| 亚洲精品在线电影| 亚洲激情黄色| 最新69国产成人精品视频免费| 在线播放精品| 一区在线电影| 伊人久久av导航| 在线观看视频一区二区欧美日韩| 国产一区二区三区观看| 国产欧美一区二区三区另类精品 | 欧美三区在线| 欧美日韩中文字幕综合视频| 欧美日韩国产精品自在自线| 欧美精品一区在线发布| 欧美激情一级片一区二区| 欧美大片免费久久精品三p | 国产精品专区第二| 国产伦精品一区二区三区高清| 国产乱理伦片在线观看夜一区| 国产精品日韩精品欧美在线|