Nresource服務之接口緩存化


1、 背景

    Nresource服務日均4.5億流量,考慮到未來流量急增場景,我們打算對大流量接口進行緩存化處理;根據服務管理平台數據統計顯示getUsableResoureCount接口調用量很大,接近40%,故對此接口進行緩存化處理。

 

2、 方案調研

    getUsableResoureCount接口用途:獲取用戶的可用資源數,契約為:Map<String, Integer> getUsableResoureCount(long userId, int resourceType, ResourceCountTypeEnum typeEnum, List<Integer> cities, List<Integer> caties) throws Exception;支持傳入資源數類型(全國/本地)多城市和多類目按照包含的策略進行資源過濾;

    由於資源庫存表設計字段:城市和類目寫入格式為:1,2,3,即以逗號組合的字符串,所以如果緩存用戶對應城市和類目的所有余量,實現難度大且意義不大。

    通過對接口返回值的觀察,我們發現getUsableResoureCount接口返回值很多都是查詢用戶所有資源余量,不區分城市和類目,且查詢結果都為0,所以我們切換思路:是不是可以把這些無余量的數據緩存起來?

    通過2021-07-27 10:00:00數據統計我們發現,單節點一分鍾getUsableResoureCount接口調用量為395,其中查詢所有資源余量的微287,返回值為0的為183,接近46%的請求是無數據的,所以緩存用戶無余量的數據是有意義的,能擋住接近50%的無用請求。

    緩存用戶無余量的數據,我們需要在所有涉及余量增減的操作,同時維護redis中余量變化,如何維護db與緩存中數據的一致性,也是面臨的問題,所以我們想:可不可以不緩存余量,只緩存一個余量標識,這樣既能擋住無用請求,又不需要維護db與緩存的數據一致性呢?參考布隆過濾器,我們決定對此接口進行緩存余量標識,只記錄有還是沒有,即1和0。

3、 方案實施

getUsableResoureCount接口先查詢緩存,如果返回值為0,則放入緩存,所有增加余量的操作均需要更新redis標識為1。基本目標就是:保證更新標識為有的操作一定成功。考慮到服務並發,寫操作(更新redis標識為1)可能會被讀操作(更新redis標識為0)覆蓋,所以更新redis標識為0的時候,先增加時間校驗即晚一分鍾更新,因為redis標識更新為0或null,不會影響最終查詢,而是會查詢db,晚一分鍾又可以避免讀寫覆蓋的問題。最終采用lua腳本實現讀操作,而寫操作采用同步set異步重試保證最終成功;

ps :有沒有考慮過載讀接口中為什么要晚一分鍾中更新緩存?

答:主從延遲,以及並發場景下,將緩存更新錯,命名用戶有資源,結果給更新成了0從而影響用戶使用。

lua腳本如下:

 

 

4、最終效果

接口響應耗時:

2021.9.2 VS 2021.9.9

 

 

2021.9.8 VS 2021.9.9

 

 

性能提升(ms):1.4 -> 0.9 提升超過30%

整體服務響應耗時:

2021.9.8 VS 2021.9.9

 

 

 

性能提升(ms):1.8 -> 1.6 提升超過10%

 

緩存命中率統計:

服務節點:10.***.60.***

命中率接近80%

5、未來考量

1)緩存的擴展性,未來新的寫接口需要更新redis標識為1;

2)緩存的接口適配性,考慮更多查詢接口應用緩存; 

  ps: 整體思路,由於業務原因,沒有采用傳統緩存用redis存有效數據的思路,我們是反其道行之,用redis來擋住無效流量


免責聲明!

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



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