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

丶謙信發表於2022-01-21

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

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

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


 

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

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

舉個例子

微博使用者主頁

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

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

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

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

比如, 從好友關係表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程式設計師

相關文章