記一種不錯的緩存設(shè)計思路
之前與同事討論接口性能問題時聽他介紹了一種緩存設(shè)計思路,覺得不錯,做個記錄供以后參考。
場景
假設(shè)有個以下格式的接口:
GET /api?keys={key1,key2,key3,...}&types={1,2,3,...}
其中 keys 是業(yè)務(wù)主鍵列表,types 是想要取到的信息的類型。
請求該接口需要返回業(yè)務(wù)主鍵列表對應(yīng)的業(yè)務(wù)對象列表,對象里需要包含指定類型的信息。
業(yè)務(wù)主鍵可能的取值較多,千萬量級,type 取值范圍為 1-10,可以任意組合,每種 type 對應(yīng)到數(shù)據(jù)庫是 1-N 張表,示意:
現(xiàn)在設(shè)想這個接口遇到了性能瓶頸,打算添加 Redis 緩存來改善響應(yīng)速度,應(yīng)該如何設(shè)計?
設(shè)計思路
方案一:最簡單粗暴的方法是直接使用請求的所有參數(shù)作為緩存 key,請求的返回內(nèi)容為 value。
方案二:如果稍做一下思考,可能就會想到文首我提到的覺得不錯的思路了:
- 使用 業(yè)務(wù)主鍵:表名 作為緩存 key,表名里對應(yīng)的該業(yè)務(wù)主鍵的記錄作為 value;
- 查詢時,先根據(jù)查詢參數(shù) keys,以及 types 對應(yīng)的表,得到所有 key1:tb_1_1、key1:tb_1_2 這樣的組合,使用 Redis 的 mget 命令,批量取到所有緩存中存在的信息,剩下沒有命中的,批量到數(shù)據(jù)庫里查詢到結(jié)果,并放入緩存;
- 在某個表的數(shù)據(jù)有更新時,只需刷新 涉及業(yè)務(wù)主鍵:該表名 的緩存,或令其失效即可。
小結(jié)
在以上兩種方案之間做評估和選擇,考慮幾個方面:
- 緩存命中率;
- 緩存數(shù)量、占用空間大??;
- 刷新緩存是否方便;
稍作思考和計算,就會發(fā)現(xiàn)此場景下方案二的優(yōu)勢。
另外,就是需要根據(jù)實際業(yè)務(wù)場景,如業(yè)務(wù)對象復(fù)雜度、讀寫次數(shù)比等,來評估合適的緩存數(shù)據(jù)的粒度和層次,是對應(yīng)到某一級組合后的業(yè)務(wù)對象(緩存值對應(yīng)存儲 + 部分邏輯),還是最基本的數(shù)據(jù)庫表/字段(存儲的歸存儲,邏輯的歸邏輯)。