十億推薦關系優化實戰


 

  最近,一朋友整天因為CPU 99%搞得茶飯不思,夜不能寐,找到我”訴苦“。聽完成,心中一陣竊喜:是時候展現真正的實力了(其實是練手的機會來了)。半推半就應承了下來。

 

 

 

01 分析問題

        幾分鍾了解下來,大概情況如下:會員可以推薦其他用戶注冊,會員有一個屬性--活躍度,用戶觀看視頻,簽到等等行為時,這個屬性會動態變化,其中有個需求是統計所有下級活躍度。會員模型如下,模型比較簡單,使用使用sqlserver 2016。

 

 

  了解需求后,再來看看占cpu高的查詢。其中占cpu 時間最多的就是下面這條sql,查詢某個用戶所有下級的活躍度之和。這條語句使用遞歸查詢,那是比較耗時的,另外如果層級太多還有如下錯誤:語句被終止。完成執行語句前已用完最大遞歸 100。

  

1 WITH T
2 AS( 
3     SELECt DataID, avtivenewss FROM User WHERE DataID = 4167
4     UNION ALL 
5     SELECT u.DataID, u.avtivenewss   
6     FROM User U INNER JOIN T ON U.parentUserid=T.DataID
7 ) 
8 SELECT sum(avtivenewss) FROM T

  

  當前用戶1W+。

 

02 失敗的嘗試:前綴法

 

      幾乎沒思考,就想到了一個方法:前綴法。一個用戶的所有后代使用同一個前綴。增加一個字段 paths,以用戶編號為基礎,格式為:/1/2/3/,用戶注冊時使用記錄上級的paths + 上級id 生成自己的paths,  增加paths的索引,這樣更具此字段就可以查詢我的所有下級了,再寫個腳步初始化。非常簡單,三下五除二就解決了。上線效果非常明顯。

 

 

  但是好景真短,沒兩天cpu 又高了。一查,好多查詢都沒有走索引,明明字段已經加了索引。一看數據,原來是索引長度限制問題。用戶居然有好幾十個層級,且還在不斷增加,長度超過索引最大長度后,索引失效。

  當前用戶10W+。

 

04 大膽猜測,小心嘗試

 

     會員關系是一棵樹,不管怎么遍歷,效率都有限。如果把樹拉平,用戶與所有后代都建立一個關系,性能會怎么樣呢。為了避免再次打臉,悄悄的開始了嘗試。增加模型tree。

    

  這需要在用戶注冊時,添加與所有祖祖輩輩的關系。比如 4167用戶注冊,需要一次添加14條關系記錄。而查詢用戶的所有子子孫孫時,也會非常方便。

 

  編寫腳本初始化數據,增加切換開關,戰戰兢兢的上線了。經過一個高峰,cpu居然都在10%以下,完全沒有壓力嘛,終於可以亮出臉來了。這是典型的空間換時間。但是高興之余,心中閃過一個念頭--這個表的膨脹速度有點快,它會有極限么。不過,馬上被另一個念頭壓制了:小網站能有多大量!

 

 

 

  有個什么定律來着:凡事只要有可能出錯,那就一定會出錯。果不其然,10天后同樣的問題再次發生。cpu幾乎爆滿。只能不停重啟,最后干脆下掉了這個統計功能,為此還被懟了一頓,甚至說實在不行換mysql吧。我竟無言以對。此時關系表總數為10億。

   當前用戶100W+。

  

05 終級方案:分表

 

     其實對於分表這樣的事兒,一直都有想過,就是沒干過,另外也一直以為是sum()引起的cpu問題。后來咨詢了公司做交易的同學,傳說他們每天處理2kw的訂單,基本思路也是根據用戶id分了2048張表。反正也沒轍了,擼起袖子搞起來吧。分析了tree 表只有兩個查詢場景,查用戶所有后代及查用戶所有祖先。分別以ancestor ,descendant 分256 張表。用戶注冊時,把關系分別寫到個分表中。

 

  編寫腳本初始化兩個緯度的分表數據,再次戰戰兢兢的上線了。經過數個高峰,效果比預期好太多了。徹底告別了cpu告警。
經歷了幾次失敗,早以沒了高興勁兒,心中有個疑問,如果是sum引起的cpu跑滿的話,現在sum並沒有減少,但是cpu為啥清閑了呢?這背后一定有原因的。

 

  

06 刨根問底

 

      帶着上面的疑問,對比了一些監控數據,發現了一個可疑的地方,磁盤請求減少了數百次。那么磁盤與cpu有什么樣的關系呢?

 

 

  查詢相關資料后,得出一個猜測:

  未分表前,每次查詢所有后代(祖先時)時,因為數據在磁盤上非常分散,page cache 命中率低,磁盤預讀失效,所以一次查詢要進行很多次磁盤隨機讀,大量的io操作,cpu就要進行大量的上下文切換,從而導致cpu跑滿。

  分表后,每次查詢所有后代(祖先時)時,每次都在特定的分表中查詢,數據在磁盤上非常緊湊,磁盤預讀發揮最大性能,page cache 命中率高,io次數據大量減少,cpu上下文切換次數減少,沒了壓力,cpu自然清閑了。

 

     最后打個廣告:哈啰出行,base 杭州, java 我們的部門有大量HC(供應鏈,本地生活方向都有), 歡迎私聊哈。微信:jijunjian

 

         I have a dream to be a good programmer。

         

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM