redis數據的輪詢規則探討(併發訪問查詢接口的性能問題思考)

業務場景如下:

公司舉辦司慶活動,使用微信端鏈接H5頁面訪問後臺服務實現員工答題搶紅包活動(除了微信網頁授權登錄用到微信API接口外,H5及後臺服務均為公司自己研發)

redis數據的輪詢規則探討(併發訪問查詢接口的性能問題思考)

除了微信登錄接口、員工信息獲得接口、祝福語接口、抽獎接口外,還有一個員工中獎名單接口(通過輪詢方式在抽獎活動頁 面滾動展示)

由於預計員工瞬間湧入為萬人以上,在處理併發訪問查詢接口時,當併發進程達到一定的數量時,數據庫的瓶頸問題就出來,性能下降嚴重,很多查詢進程處於等待阻塞狀態。

經過調查發現引發性能問題的關鍵在於大量數據庫連接請求處於排隊中,數據庫吞吐容量有限,如果不減少訪問請求次數,那麼優化SQL或減少查詢記錄數的有一定效果,但在併發超過一定數量的情況下(比如200)性能問題還是存在著。所以解決該問題的思路是轉移數據庫的壓力,考慮使用緩存來處理大併發請求。這裡考慮採用redis緩存來提高讀取性能,降低對數據的IO操作。

接口功能業務:系統進入抽獎頁面後,自動觸發輪詢調用員工中獎名單接口以獲得員工中獎名單列表數據,假設輪詢時間為5分鐘一次(輪詢時間可以由系統後臺管理員自行設置)

那麼一小時60分鐘將會被5分鐘分割為步長相等12等分時間段,每等份的臨界值為 5,10,15,20,25,30,35,40,45,50,55,60分鐘,那麼在系統接受到的瞬間第一次名單請求(時間假設為整點0分)需要去從數據庫讀取數據(並將該次查詢數據,以一定的 業務規則key值存入到redis中)外,其餘的所有請求(0分至5分鐘之間的所有請求,0

<=請求時間<5)都將去redis中取數據,從而減少了對數據庫的壓力。直到第二個臨界點來臨為止(第二個時間段 5分鐘開始的首次請求,系統將重新去數據庫查詢數據,並再次存入到redis中)重新查詢並存入新的數據以供其它請求查詢。

那麼問題來了,第一次請求是從數據庫讀取的數據,並以一定的規則(體現在key值上)存入到redis 中,系統如何對0~5分鐘時間段所有請求生成同樣的key值,然後通過key值去redis中取出 0分首次存入的數據呢?

參考以下方法 參數 currentTime為當前請求的系統時間,格式為 2018-06-07 17:12:00

參數 polling_time 為系統的輪詢時間 比如 為 5 (分鐘)

代碼邏輯為 將60分鐘按輪詢時間分割為相等的時間段,生成一個數組

然後拿系統時間 分鐘數 如 12去和臨界值去比較,其實是判斷12是否超過臨界值15, 如果沒有超過的話,則取上一個臨界值10,然後封裝成 2018-06-07 17:10:00 返回

/**
 * 根據輪詢時長與當前時間生成key值
 * 業務邏輯:
 * 將60分鐘按輪詢時長分成若干等份 比如 輪詢時長為5分鐘,則分為 12等份 每等份的臨界值為 5,10,15,20,25,30,35,40,45,50,55,60
 * 則傳入的當前時間在等份中,返回該等份的最小值
 * 比如傳入時間為2018-06-07 17:12:00 12 位於等份臨界值 10 與 15之間 則返回值應該為10 最終返回時間應該為 2018-06-07 17:10:00
 * @param currentTime 當前時間 2018-06-07 17:12:00
 * @param polling_time 輪詢時長(小於60分鐘) 比如 5
 * @return 2018-06-07 17:10:00
 * @throws Exception
 */
 private String getWinningListKey(String currentTime ,String polling_time) throws Exception {
 String minute = "0";
 String [] arr = currentTime.split(" "); //17:12:00
 String [] arr1 = arr[1].split(":"); //12
 //1小時內的時間間隔
 int interval = 60/Integer.valueOf(polling_time);//60/5=12
 String [] intervalArr = new String[interval];//5,10,15,20,25,30,35,40,45,50,55,60
 for(int i = 0 ; i= Integer.valueOf(intervalArr[i])
 && Integer.valueOf(arr1[1])  
< Integer.valueOf(polling_time)*(2+i)){ minute = intervalArr[i]; break; } } minute = minute.length() == 1 ? "0"+minute : minute; return arr[0]+ " "+arr1[0]+":"+minute+":00"; }

這個邏輯的意思是 如果當前請求的系統時間沒有超過或等於下一個臨界點(15分),那麼就取上一個臨界點的值(10分鐘),

這樣,時間段內生成的key值總是保持一致,通過key去redis中獲得歷史拍照數據,一但達到臨界點,又會重新生成新的key值,再依上述規則進行下去實現了業務邏輯的關於輪詢數據獲得與重新生成的業務規則。

經過重新壓力測試,數據查詢的瓶頸和進程阻塞問題得到根本性的解決。

redis數據的輪詢規則探討(併發訪問查詢接口的性能問題思考)

這裡有一個值得注意的地方,雖然輪詢時間是由管理員後臺設置的,要求被60整除(比如5能被60整除),如果不能整除,那麼時間段將會被切割的不完整,會遇到時間間隙,程序將會監控不到。


分享到:


相關文章: