本文來自網易雲社區。

問題背景

App品牌頁由於多版本的迭代,頁面承載模塊越來越多,如品牌基本信息、優惠券、熱銷、上新、品牌商品篩選、相關品牌推薦等,如下圖所示,用戶訪問品牌頁有時候會感覺載入較慢,主要原因是App品牌頁所有的數據都是通過一個HTTP請求返回數據,這個請求需要調用三次搜索、一次推薦、若干次緩存查詢和DB查詢,而且是順序同步執行,請求響應時間較長,導致的結果是:

1、用戶體驗較差,當可降級服務(熱銷/上新搜索、品牌推薦)某個環節處理較慢時,整個請求的響應時間會拉的很長,即使dubbo配置了超時,多個降級服務的最大響應時間疊加也是不能忍受的。

2、在用戶使用峰值,如每日秒殺或大促時間,慢請求會導致Dubbo線程阻塞。我們不怕請求多,我們就怕慢請求。

在已發版的客戶端無法修改的情況下,只能通過服務端加快處理邏輯,及時返回數據,解決慢請求的問題。

多線程解決方案

針對以上問題,我們打算採取多線程方案解決,JDK 7提供了兩種線程池方案,ThreadPoolExecutor和ForkJoinPool,對兩者原理研究和源碼閱讀後,我們進行了一個比較:

l 適用場景:Fork/Join比ThreadPoolExecutor更適合任務層層分解、處理、結果合併的場景。

l 性能:Fork/Join的工作流竊取演算法,能提供最大化的並行程度。

我們選定ForkJoinPool來解決問題,但是多線程編程有一定的難度,主要原因有:

l 鎖

l 線程間通信

l 異常處理

l 代碼可讀性

l 無ForkJoinPool線上時間經驗

我們需要一個簡單、易用、抽象層次更高的並發框架,我們又查閱了Actor模型的Java實現Akka。

Actor模型:Akka

Actor模型,一種用於處理並發計算的數學模型,特點如下:

l 非同步消息方式通信

l 狀態機

l 無共享

l 無鎖的並發處理方式

l 並行性

Akka是Actor模型的Java實現,底層線程池默認為ForkJoinPool,是比較理想的並發框架選擇,它的編程難度相比直接用JDK的線程池更低,簡單、易用、抽象層次更高。

我們進一步做的工作是結合Spring框架抽象封裝Akka,對外隱藏Akka的細節,提供更簡單的服務,進一步簡化多線程編程的難度。

效果

上線後,通過哨兵對比,App品牌頁性能提升約25%左右,如下圖所示:

相同的方案應用在用戶頁,平均響應時間提升約50%左右,如下圖所示:

用戶在訪問App品牌頁和用戶頁響應速度更快,體驗更佳,系統dubbo線程池彪滿的風險進一步降低,效果達到了預期。

原文:基於akka的多線程框架在考拉APP後端的應用

本文來自網易雲社區,經作者黃曉軍授權發布。

了解網易雲 :

網易雲官網:https://www.163yun.com

網易雲社區:sq.163yun.com/blog網易雲新用戶大禮包:https://www.163yun.com/gift

更多網易研發、產品、運營經驗分享請訪問網易雲社區。


推薦閱讀:
相关文章