線上高併發應用重構(寫)填坑經驗分享(二)

上一篇主要從設計層面,分享了一些小經驗。

因軟件系統有其複雜性和多樣性,不同的場景、架構下,系統的瓶頸各不相同。

文章裏的一些想法和設計並不通用,主要針對的是高併發場景下海量數據的實時查詢。


 

這次再分享一個更貼近生活的案例。

有時看似簡單的邏輯,往往隱藏了最深的坑,甚至成爲系統的性能瓶頸。

舉個栗子

微博用戶主頁

這個頁面應該都不陌生,業務也並不複雜。

值得注意的是紅線圈出的功能:粉絲數量,微博總數,評論、轉發、點贊數量。

乍一看很簡單,再一看還是很簡單。

根據條件,從相關的業務表統計數量就好了呀。

比如, 從好友關係表count所有關注作者的人( type = 2 代表被關注)。

select count(1) from user_relation where uid = 'xxx' and type = 2 

沒毛病啊,十分合理。這麼簡單的東西難道還能玩出花來?

第一版上線時

我就是這麼做的,結果整個服務直接掛掉了。

看了下監控,發現量變竟然引發了質變。

在系統數據量不大或流量不高時,使用count查詢來處理此業務沒有任何問題。

當數據達到一定量級時,比如圖中的粉絲量300W+,如果查詢的結果集數量過大,即便根據索引查詢,正常耗時也會達到幾秒、十幾秒,更別說在高併發下頻繁查詢。

用戶主頁,一頁查詢15條動態,每條動態都要顯示轉發、評論、點贊數,總共需要count45次。

再加上微博上億的用戶量,超高的併發,此處若實時地使用count查詢,將輕鬆GET以下異常:

The last packet sent successfully to the server was 5,652 milliseconds ago

因爲MySQL服務器所有的線程都用來執行這些count慢查詢了,導致後面的請求全部阻塞。

此時,數據庫性能監控面板會有一些顯著的指標特徵:CPU負載達到100%,運行線程數異常高。

第二版上線時

我專門加了一張表用來計數, 類似 (動態id, 點贊數, 評論數, 轉發數 )這樣的結構。

每次用戶點贊、評論、轉發時,直接在表上寫入數量+1。

查詢時直接從此表讀取數量,避免count查詢。

解決方法雖簡單了些,能搞定性能上的瓶頸即可。

此前,也參考過一些關於微博架構的資料,裏面有提到計數器服務。(如:https://www.cnblogs.com/kenshinobiy/p/4316217.html。)

但當時並沒理解爲什麼要做計數器?什麼數這麼吊還要專門做個服務來計算?

微信朋友圈

微信朋友圈

朋友圈的設計,就完全不用展示數量。

直接避開了很多可能給系統帶來性能瓶頸的坑。

相比之下,微信的工程師一定能少掉不少頭髮。

當然,二者社交場景不同,介質也不同(WEB | APP),有些產品上的設計是不可避免的。

綜上

在MySQL進行實時查詢時,應該避免查詢出的結果集數量過大。

否則,即使像count這樣最簡單的查詢語句,也可能帶來性能問題。

當然,最終還是要看具體的使用場景。

比如,一個用來彙總每日報表的查詢語句,使用了 union,group by  等性能不佳的子句,整個查詢耗時5秒。

但它每天只執行一次,且查詢的數據表並不頻繁使用。即便這是一條慢查詢,對性能的影響也是微乎其微。

而像案例中的count語句,即便耗時只有1秒,如果每秒請求1000次,那它對數據庫CPU的消耗就是前者的200倍。


 

無聊可關注下公衆號: 躺平de程序員

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章