牛客面试系列之Redis
文章目錄
- Redis數據類型
- Redis基本數據類型的使用和使用場景
- String
- hash
- list
- set
- zset
- 標題為什么使用Redis?
- 標題為什么Redis的性能高?
- 標題Redis為什么使用單線程?
- Redis過期策略
- Redis淘汰策略
- Redis緩存穿透
- Redis緩存擊穿
- Redis緩存雪崩
- Redis分布式鎖
- 單Redis實例實現分布式鎖
- 多Redis實例實現分布式鎖
?作者簡介:我是18shou,一名即將秋招的java實習生
🔥系列專欄:牛客面經專欄
📃推薦一款八股、面經、模擬面試、刷題神器👉 超級無敵之牛客
耗時數小時從牛客整理的面經以及筆記
Redis數據類型
數據類型 :最大存儲數據量
key:512M
string:512M
hash:2^32-1
list:2^32-1
set:2^32-1
sorted setbitmap:512M
hyperloglog:12K
Redis基本數據類型的使用和使用場景
String
String:set(添加鍵值對),get(獲取鍵值對),decr(自減1),incr(自增1),mget(同時獲取一個或多個value)
適合用于高頻訪問的信息,比如書一個大V的粉絲數量,微博數量等等,可以用Redis的String來存放。如博客訪問次數、網站訪問量。
hash
hash: hget,hset,hgetall 可以應用在電商網站購物車的設計,用戶就是一個key,商品是一個field,數量為value。
list
list:
lpush(從左邊插入一個或多個值),rpush(從右邊插入一個或多個值),rpop(從右邊吐出一個值),lrange(key,start,stop)(按照索引下標獲得元素從左到右)
可以運用在微信朋友圈點贊,比如說要求按照點贊的順序來顯示好友信息,如果取消點贊,就移除點贊列表。微博中我的關注列表
set
set: sadd(添加一個或多個值), spop (隨機從集合中吐出一個值),
smembers(取出對應鍵所有值),sunion(sunion:sunion key1 key2 取key1和key2的并集)
假如一個公司里面有很多的員工,在內部的OA系統中就具有700多個角色,3000多個業務操作,20000多種數據,那么如何快速進行業務操作的相關校驗呢?
Redis的set是string類型的無序集合,和list不同的是,set中不會出現重復的成員,集合最大的好處就是可以進行交集或差集的操作。
?使用場景:共同好友、二度好友,記錄訪問網站的獨立IP等 ?常用命令:sadd、spop、smembers、sunion等。
zset
zset (有序集合)
Redis中的zset和set一樣,都是string類型的集合,也不允許有重復的成員,但不同的是zset的每個元素都會有一個double類型的分數(score)與之關聯,而Redis也是通過這個分數來為這個集合排序的。
應用場景:在線游戲的積分排行榜、熱點新聞排行榜等 常用命令:zadd、zrange、zrem、zcard等。
標題為什么使用Redis?
因為是基于內存,可持久化的Key-Value數據庫,具有速度快,可持久化,豐富數據類型,支持數據備份的功能。
標題為什么Redis的性能高?
(1)Redis的數據是完全存放在內存中的,類似hashmap優勢是查找和操作的時間復雜度都是O(1)
(2)Redis采用了單線程,避免了不必要的上下文切換和競爭條件以及多線程導致的相關鎖的問題。
(3)采用多路I/O復用模型,非阻塞IO,空閑時把當前線程阻塞,當有IO流事件時,就從阻塞狀態喚醒,然后程序會輪詢一邊所有的流,并一次順序處理事件的流,避免了大量的無用操作。
標題Redis為什么使用單線程?
(1)使用Redis時幾乎不存在CPU瓶頸,主要受限于網絡和內存,比如說Linux下Redis可以pipelining每秒處理100萬個請求。
(2)使用單線程可維護性高,多線程雖然優秀但是帶來的程序執行順序不確定,并發讀寫一系列問題,增加系統復雜度,同時線程切換,造成的性能消耗。
(3)Redis采用的時I/O復用模型,處理性能高,沒必要用多線程,并且單線程Redis內部實現復雜度低。
Redis過期策略
Redis會把設置了過期時間的key放入一個獨立的字典里,在key過期時并不會立刻刪除它。Redis會通過如下兩種策略,來刪除過期的key:
1.從過期字典中隨機選擇20個key;
2.刪除這20個key中已過期的key;
3.如果過期的key的比例超過25%,則重復步驟1;
Redis淘汰策略
當Redis占用內存超出最大限制(maxmemory)時,
可采用如下策略(maxmemory-policy),讓Redis淘汰一些數據,以騰出空間繼續提供讀寫服務:
Redis緩存穿透
場景 查詢根本不存在的數據,使得請求直達存儲層,導致其負載過大,甚至宕機。 ·解決方案 1.緩存空對象
存儲層未命中后,仍然將空值存入緩存層。再次訪問該數據時,緩存層會直接返回空值。2.布隆過濾器
將所有存在的key提前存入布隆過濾器,在訪問緩存層之前,先通過過濾器攔截,若請求的是不存在的key,則直接返回空值。
Redis緩存擊穿
場景 一份熱點數據,它的訪問量非常大。在其緩存失效瞬間,大量請求直達存儲層,導致服務崩潰。·解決方案 1.加互斥鎖
對數據的訪問加互斥鎖,當一個線程訪問該數據時,其他線程只能等待。
這個線程訪問過后,緩存中的數據將被重建,屆時其他線程就可以直接從緩存取值。2.永不過期
不設置過期時間,所以不會出現上述問題,這是“物理”上的不過期。為每個value設置邏輯過期時間,當發現該值邏輯
過期時,使用單獨的線程重建緩存。
Redis緩存雪崩
場景 由于某些原因,緩存層不能提供服務,導致所有的請求直達存儲層,造成存儲層宕機。·解決方案
1.避免同時過期 設置過期時間時,附加一個隨機數,避免大量的key同時過期。2.構建高可用的Redis緩存 部署多個Redis實例,個別節點宕機,依然可以保持服務的整體可用。3.構建多級緩存
增加本地緩存,在存儲層前面多加一級屏障,降低請求直達存儲層的幾率。4.啟用限流和降級措施
對存儲層增加限流措施,當請求超出限制時,對其提供降級服務。
Redis分布式鎖
場景
修改時,經常需要先將數據讀取到內存,在內存中修改后再存回去。在分布式應用中,可能多個進程同時執行上述操作,而讀取和修改非原子操作,所以會產生沖突。增加分布式鎖,可以解決此類問題基本原理
同步鎖:在多個線程都能訪問到的地方,做一個標記,標識該數據的訪問權限。分布式鎖:在多個進程都能訪問到的地方,做一個標記,標識該數據的訪問權限。實現方式
1.基于數據庫實現分布式鎖;2.基于Redis實現分布式鎖;3.基于zookeeper實現分布式鎖;
Redis實現分布式鎖的原則
1.安全屬性:獨享。在任一時刻,只有一個客戶端持有鎖。
2.活性A:無死鎖。即便持有鎖的客戶端崩潰或者網絡被分裂,鎖仍然可以被獲取。3.活性B:容錯。只要大部分Redis節點都活著,客戶端就可以獲取和釋放鎖。
單Redis實例實現分布式鎖
1.獲取鎖使用命令: SET resource_name my_random_value NX PX 3000o
NX:僅在key不存在時才執行成功。
PX:設置鎖的自動過期時間。
2.通過Lua腳本釋放鎖: 可以避免刪除別的客戶端獲取成功的鎖:
if redis.call ( "get",KEYS[1])==ARGV [1] then return redis.call ( "del",KEYS [1]) else return 0 end
A加鎖->A阻塞->因超時釋放鎖 ->B加鎖->A恢復->釋放鎖
多Redis實例實現分布式鎖
Redlock算法,該算法有現成的實現,其Java版本的厙為Redisson。
1.獲取當前Unix時間,以毫秒為單位。
2.依次嘗試從N個實例,使用相同的key和隨機值獲取鎖,并設置響應超時時間。如果服務器沒有在
規定時間內響應,客戶端應該盡快嘗試另外一個Redis實例。
3.客戶端使用當前時間減去開始獲取鎖的時間,得到獲取鎖使用的時間。當且僅當大多數的Redis節
點都取到鎖,并且使用的時間小于鎖失效時間時,鎖才算取得成功。
4.如果取到了鎖,key的真正有效時間等于有效時間減去獲取鎖使用的時間。5.如果獲取鎖失敗,客戶端應該在所有的Redis實例上進行解鎖。
📃推薦超級無敵之牛客
總結
以上是生活随笔為你收集整理的牛客面试系列之Redis的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 马士兵python_马士兵python大
- 下一篇: Centos8安装完mysql