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