Redis如何實現高并發
- 首先是單線程模型:redis采用單線程可以避免多線程下切換和競爭的開銷,提高cpu的利用率,如果是多核cpu,可以部署多個redis實例。
- 基于內存的數據存儲:redis將數據存儲在內存中,相比于硬盤訪問速度更快。
- 優化數據結構:redis使用多種高效的數據結構,如哈希表、跳躍表等提高數據的操作效率。
- 多路復用和非阻塞IO:多路復用允許一個線程同時監聽多個客戶端,而非阻塞IO允許發起IO請求后不會阻塞當前線程,而可以執行其他任務,提高了響應速度和利用率。
redis4.0及之前都是單線程模式,之后慢慢往多線程方向發展,這是為什么呢?
- 4.0之前機器大多是單核的,故使用單線程,但隨著互聯網發展,機器都是多核,為了提高性能慢慢往多線程方向發展。
- 其次,實踐中出現的部分問題不好解決,比如刪除一個大key ——hash表,就需要將里面的鍵值對全部刪除,非常耗時,如果是單線程會出現卡頓,導致其他連接用戶不能及時響應。
到了redis6/7版本網絡處理請求是多線程(瓶頸),命令執行是單線程。
開啟多線程
配置文件redis.conf設置
io-threads 數量? ? ?//設置線程核心數
io-threads-do-reads? yes //開啟多線程
緩存穿透
緩存穿透是指請求的數據在緩存中和數據庫中都不存在,每次請求訪問數據庫。
場景:
- 查詢不存在的數據:緩存無法存儲,故每次從數據庫查詢;
- 查詢熱門數據:數據被訪問頻繁,導致緩存系統無法處理,只能從數據庫中訪問;
- 查詢異常數據:數據服務異常緩存無法訪問。
解決方法:維護一個布隆過濾器(判斷一個元素是否可能在一個集合中)。
緩存擊穿
是指一個查詢的熱點數據不存在緩存,每次都需要訪問數據庫。
場景:
- 未緩存存儲的熱點數據
- 熱點數據過期
解決方法:查詢數據庫前判斷緩存中是否有,若沒用使用redis查詢數據庫,寫入緩存。
緩存雪崩
指某一時間大量緩存數據集體失效,導致數據庫的訪問量加大,對數據庫產生極大負荷。
場景:
- 緩存服務器宕機:當服務器宕機或重啟時,大量訪問將命中數據庫;
- 數據過期時間設置不合理。
- 促銷商品:打折等促銷活動將帶來高頻的數據訪問。
解決方法:
- 將緩存過期時間分散開,即為不同的數據設置不同的過期時間;
- 使用多級緩存結構,通過增加緩存層數來提高數據的保存時間;
實際生產上如何禁止keys */flushdb/flushall等危險命令?
將相應命令設置成空字符串。
在redis.conf配置命令為空字符串
rename- command keys ""
命令含義:重命名指令keys為空字符串
實際遍歷可以通過scan來進行
命令:scan 游標(從0開始)?match 模糊匹配 count 數量
例子 :
從0開始匹配前綴為k的15條記錄
返回第一行表示下一個游標,如果為0表示遍歷完畢。
多大算大key
String為超過10KB。
而集合如List Hash等超過5000即為大key。
危害
造成內存不均,集群遷移困難。
刪除等會造成阻塞。
查詢
redis-cli --bigkeys : 發現其中的大key
memory usage 鍵:查詢某個key的大小
如何刪除
先將大key中數據進行刪除,里面大致清空時直接delete該key
如何調優
將大key移除改為非阻塞
?雙檢加鎖策略
當redis中無數據,而需要向mysql查詢時,如何保證數據一致性?
策略:
- 先在redis緩存查詢是否存在,命中直接返回;
- 未命中則加鎖,再進行一次緩存查詢(因為在多線程中可能上次加鎖的線程已經將數據更新到緩存)
- 若未查到,訪問數據庫,并更新緩存。
數據庫和緩存一致性的策略
先刪除緩存再更新數據庫:
讓下次訪問時,將數據從數據庫中寫回到緩存。
缺陷:可能存在更新不及時,導致線程訪問到舊的數據寫會緩存,導致后面請求訪問的都是舊數據。
先更新數據庫再刪除緩存:
讓下次訪問時,將數據從數據庫中寫回到緩存。
缺陷:可能刪除不及時,導致部分訪問讀取緩存中的舊值。
感謝觀看——