緩存穿透和緩存雪崩
緩存穿透
-
概念
所謂緩存穿透就是說在緩存中不存在,然後直接在數據庫中查詢的現象,圖例如下:
-
場景
一般來說,緩存穿透的場景發生在故意攻擊的場景下;比如說,本來查詢意見商品的序號是正數,但是請求方總是請求大量的負數過來,導致緩存無效,全部流量都打在了數據庫中,如果某一時刻流量過大,則會導致數據庫崩潰;
-
解決方案
- 方案一:布隆過濾器
- 布隆過濾器會判斷某個元素是否在某個幾個中,相關的知識點會專門去介紹。
- 方案二:緩存空值
- 可以把一些不符合要求的數據的key值設置爲NULL,這樣就不會一直去查數據庫了但是需要設置過期時間;
最好就是在redis前面加一個布隆過濾器,這樣很降低緩存穿透的概率;
- 方案一:布隆過濾器
-
僞代碼
////方案一 //僞碼 string penetrate1(int ID,string str) { //使用布隆過濾器,後續專門寫一篇博客 if(存在) { redis操作 } else { return NULL; } } ////方案二 //僞碼 string penetrate1(int ID,string str) { //假設可以就是ID int CacheTime = 30; string CacheValue; char cmd[128]; char sql[128]; memset(cmd,0,sizeof(cmd)); memset(sql,0,sizeof(sql)); sprintf(cmd,"get %d",ID); redisReply* replay = (redisReply*)redisCommand(conn,cmd); if(replay->type == REDIS_REPLY_ERROR) { //查詢數據庫 mysql_query(&mysql,sql); MYSQL_RES *result= mysql_store_result(&mysql); int row = mysql_num_rows(result); //查詢爲空 if(row < 0) { //設置默認值 memset(cmd,0,sizeof(cmd)); sprintf(cmd,"set %d ''",ID); redisReply* replay = (redisReply*)redisCommand(conn,cmd); } //數據庫數據同步到redis中 //set XX XX redisReply* replay = (redisReply*)redisCommand(conn,cmd); //返回數據 return 結果; } else { return replay->str; } }
緩存雪崩
- 概念
所謂緩存雪崩就是在某一個時刻,緩存集大量失效。所有流量直接打到數據庫上,對數據庫造成巨大壓力;
-
場景
基本我們能想到的場景就是一些電商搶購的現象,一般就是比如12點開始,在1點的時候大量同時失效,這個時候就會造成緩存雪崩的現象;
-
解決方案
-
方案一:加鎖/隊列
- 加鎖/隊列;這樣雖然能降低數據庫壓力,但是同時,響應也很慢
-
方案二:緩存標記
- 給每一個緩存數據增加相應的緩存標記,記錄緩存的是否失效,如果緩存標記失效,則更新數據緩存
-
方案三:緩存過期時間錯開
- 設置緩存時間錯開,可以在設置過期時間的時候,加一個一定範圍內的隨機值來錯開
-
想了解學習更多C++後臺服務器方面的知識,請關注:
微信公衆號:C++後臺服務器開發