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