Redis的數(shù)據(jù)類型
??????? Redis支持五中常用數(shù)據(jù)類型,string hash list set zset
Redis的持久化機(jī)制是什么
??????? Redis提供兩種持久化機(jī)制,RDB和AOF機(jī)制
??????? RDB持久化機(jī)制,是指數(shù)據(jù)集快照的方式半持久化模式記錄Redis數(shù)據(jù)庫的所有鍵值對,在某個(gè)時(shí)間點(diǎn)將數(shù)據(jù)寫入一個(gè)臨時(shí)文件,持久化結(jié)束后,用這個(gè)臨時(shí)文件替換上次的持久化文件,達(dá)到數(shù)據(jù)恢復(fù).
優(yōu)點(diǎn):
- 只有一個(gè)文件dump.rdb,方便持久化.
- 容錯(cuò)性好,一個(gè)文件可以保存到安全的磁盤.
- 性能最大化,fork子進(jìn)程來完成寫操作,讓主進(jìn)程繼續(xù)處理命令,所以是IO最大化,使用單獨(dú)的子進(jìn)程進(jìn)行持久化,主進(jìn)程不會進(jìn)行任何的IO操作,保證了Redis的高性能.
- 相對于數(shù)據(jù)集大時(shí),比AOF的啟動效率更高.
缺點(diǎn):數(shù)據(jù)安全性較低,RDB是間隔一段時(shí)間進(jìn)行持久化,如果持久化之間Redis發(fā)生故障,會發(fā)生數(shù)據(jù)丟失.所以這種方式更適合數(shù)據(jù)要求不嚴(yán)謹(jǐn)?shù)臅r(shí)候.
????????AOF持久化機(jī)制:是指所有的命令行記錄以Redis命令請求協(xié)議的格式完全持久化存儲保存為aof文件.
優(yōu)點(diǎn):
- 數(shù)據(jù)安全,aof持久化可以配置appendsync屬性,有always,每進(jìn)行一次命令操作就記錄到aof文件中一次.
- 通過append模式寫文件,及時(shí)中途服務(wù)器宕機(jī),可以通過redis-check-aof工具解決數(shù)據(jù)一致性問題.
- AOF機(jī)制的rewrite模式,aof文件沒有被rewrite之前,可以刪除其中的某些命令
缺點(diǎn):
- aof文件比rdb文件大,且恢復(fù)速度慢.
- 數(shù)據(jù)集大時(shí),比RDB啟動效率低
Redis過期策略,淘汰機(jī)制
??????? 過期策略
??????? 1.定時(shí)刪除,當(dāng)對一個(gè)key設(shè)置了過期時(shí)間,當(dāng)該時(shí)間到期之后,立即執(zhí)行對該key的刪除,優(yōu)點(diǎn)是對內(nèi)存友好,保證key一旦過期就能立即從內(nèi)存中刪除.缺點(diǎn):對CPU不友好,在過期的鍵數(shù)量較多的時(shí)候,刪除過期的鍵需要占用一定的CPU時(shí)間,對服務(wù)器的響應(yīng)時(shí)間和吞吐量造成影響.
??????? 2.惰性刪除,當(dāng)一個(gè)key過期之后,并不會立即從內(nèi)存中刪除,而是在調(diào)用key的時(shí)候去檢查其是否過期,如果過期,將其從內(nèi)存中刪除.優(yōu)點(diǎn)是對CPU友好,只有在使用的時(shí)候才會檢查.對于沒有用到的key不會浪費(fèi)時(shí)間進(jìn)行過期檢查.缺點(diǎn):對內(nèi)存不友好,key過期之后如果一直沒有使用,就會一直占用這部分內(nèi)存.如果Redis中存在很多過期鍵沒有被使用,就永遠(yuǎn)不會刪除,內(nèi)存不會被釋放,從而造成內(nèi)存泄漏.
??????? 3.定期刪除,每隔一段時(shí)間,就隨機(jī)抽取一些設(shè)置了過期時(shí)間的key進(jìn)行檢查,將其中過期的鍵刪除掉,默認(rèn)是1s執(zhí)行10次定期刪除,每次抽取5個(gè).優(yōu)點(diǎn)可以通過限制刪除操作執(zhí)行的時(shí)長和頻率來減少刪除的操作對CPU的影響.另外定期刪除,也能有效釋放過期鍵占用的內(nèi)存.缺點(diǎn):單一確定刪除操作執(zhí)行的時(shí)長和頻率,如果執(zhí)行的太頻繁,定期刪除策略變得和定時(shí)刪除一樣,對CPU不友好.如果執(zhí)行頻率太低,就和惰性刪除一樣,過期鍵占用的內(nèi)存不會及時(shí)得到釋放.而且,如果在獲取某個(gè)鍵時(shí),如果某個(gè)鍵的過期時(shí)間到了,但是還沒執(zhí)行定期刪除,那么就會返回這個(gè)鍵的值,這是業(yè)務(wù)不能忍受的錯(cuò)誤.
??????? 淘汰策略.
- no-eviction 當(dāng)內(nèi)存不足以容納新數(shù)寫入的數(shù)據(jù)時(shí),新寫入操作會報(bào)錯(cuò).無法寫入新數(shù)據(jù),一般不操作.
- allkeys-lru 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時(shí),移除最近最少使用的key,這個(gè)是最常用的.
- allkeys-random 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時(shí),隨機(jī)移除key
- allkeys-lfu 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時(shí),移除最少使用的key
- volatile-lru 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的key中,移除最近最少使用的key
- volatile-random 內(nèi)存不足以容納新寫入新寫入的數(shù)據(jù)時(shí),在設(shè)置了過期的key中,隨機(jī)刪除一個(gè).
- volatile-lfu 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間key中,移除最少使用的key
- volatile-ttl 當(dāng)內(nèi)存不足以容納新寫入的數(shù)據(jù)時(shí),在設(shè)置了過期時(shí)間的key中,優(yōu)先移除剩余存貨時(shí)間最短的.
Redis的事務(wù)
??????? Redis的事務(wù)不保證原子性,在Redis中,單條命令是原子性執(zhí)行的,但事務(wù)不保證原子性,且沒有回滾.事務(wù)中任意命令執(zhí)行失敗,其余的命令仍會被執(zhí)行.
??????? Redis沒有隔離級別的概念,批量操作在發(fā)送exec命令前被放入隊(duì)列緩存,并不會被實(shí)際執(zhí)行,也就不存在事務(wù)內(nèi)的查詢要看到的事務(wù)里的更新,所以事務(wù)外的查詢是查不到的.
?????????優(yōu)點(diǎn):一次性按照順序執(zhí)行多個(gè)Redis命令,不受其他客戶端命令請求影響,事務(wù)中的命令要么都執(zhí)行,要么都不執(zhí)行.
??????? 缺點(diǎn):事務(wù)執(zhí)行時(shí),不能保證原子性,命令入隊(duì)每次都需要和服務(wù)器進(jìn)行交互,增加帶寬.
??????? 注意:當(dāng)事務(wù)中命令的語法使用錯(cuò)誤時(shí),最終會導(dǎo)致事務(wù)執(zhí)行不成功,即事務(wù)中所有命令都不執(zhí)行.當(dāng)時(shí)事務(wù)中命令知識邏輯錯(cuò)誤,就比如給字符串做加減乘除操作,只能在執(zhí)行過程中發(fā)現(xiàn)錯(cuò)誤,這種事務(wù)執(zhí)行中失敗的命令不影響其他命令的執(zhí)行.
Redis集群,哨兵,主從復(fù)制模式
主從復(fù)制模式
??????? 主從復(fù)制,是只將一臺Redis服務(wù)器的數(shù)據(jù)復(fù)制到其他Redis服務(wù)器,前者成為主節(jié)點(diǎn),master,后者成為從節(jié)點(diǎn)slave,數(shù)據(jù)的復(fù)制只能是從主節(jié)點(diǎn)到從節(jié)點(diǎn).master節(jié)點(diǎn)可以增刪改查數(shù)據(jù),slave只能查詢數(shù)據(jù)
??????? 主從復(fù)制實(shí)現(xiàn)了數(shù)據(jù)的熱備份,是持久化之外的一種數(shù)據(jù)冗余方式.當(dāng)主節(jié)點(diǎn)出現(xiàn)問題之后,可以有從節(jié)點(diǎn)提供服務(wù),實(shí)現(xiàn)快速的故障恢復(fù).在主從復(fù)制的基礎(chǔ)上,配合讀寫分離,可以右主節(jié)點(diǎn)提供寫服務(wù),由從節(jié)點(diǎn)提供讀服務(wù),尤其是在寫少讀多的場景下,通過多個(gè)從節(jié)點(diǎn)分擔(dān)讀負(fù)載,可以大大提高Redis服務(wù)器的并發(fā)量.除此之外,主從模式還是集群和哨兵能夠?qū)嵤┑幕A(chǔ).
哨兵模式
??????? 哨兵是一個(gè)分布式系統(tǒng),用于對主從結(jié)構(gòu)中的每臺服務(wù)器進(jìn)行監(jiān)控,當(dāng)出現(xiàn)故障時(shí)通過投票機(jī)制選擇新的Master并將所有的Slave連接到新的Master.所以整個(gè)運(yùn)行哨兵集群的數(shù)量不能少于3個(gè)節(jié)點(diǎn).
??????? 哨兵會不斷檢查主節(jié)點(diǎn)和從節(jié)點(diǎn)是否運(yùn)作正常.當(dāng)主節(jié)點(diǎn)不能正常工作時(shí),哨兵會開始自動故障轉(zhuǎn)移操作.它會將失效主節(jié)點(diǎn)的其中一個(gè)從節(jié)點(diǎn)升級為新的主節(jié)點(diǎn).并讓其他從節(jié)點(diǎn)改為復(fù)制新的主節(jié)點(diǎn).
??????? 哨兵結(jié)構(gòu)由哨兵節(jié)點(diǎn)和數(shù)據(jù)節(jié)點(diǎn)組成,在整個(gè)哨兵系統(tǒng)中,會同時(shí)存在一個(gè)或多個(gè)哨兵節(jié)點(diǎn)組成,哨兵節(jié)點(diǎn)的特殊的Redis節(jié)點(diǎn),不存儲數(shù)據(jù).主節(jié)點(diǎn)和從節(jié)點(diǎn)都是數(shù)據(jù)節(jié)點(diǎn).
集群
??????? 數(shù)據(jù)分區(qū)是集群最核心的功能.集群將數(shù)據(jù)分散到多個(gè)節(jié)點(diǎn),一方面突破了Redis單機(jī)內(nèi)存大小的限制,存儲容量大大增加,另一方面,每個(gè)主節(jié)點(diǎn)都可以對外提供讀服務(wù)和寫服務(wù),大大提高了集群的響應(yīng)能力.
??????? 集群支持主從復(fù)制模式和主節(jié)點(diǎn)的自動故障轉(zhuǎn)移,當(dāng)任意節(jié)點(diǎn)發(fā)送故障時(shí),集群仍然可以對外提供服務(wù).
??????
Redis如果hash沖突,怎么解決
??????? 當(dāng)一個(gè)新的鍵值對要添加到字典中時(shí),程序需要現(xiàn)根據(jù)鍵值對的鍵算出哈希值和索引值,然后再根據(jù)索引值,將包含新鍵值對的哈希表節(jié)點(diǎn)放到哈希表數(shù)組對應(yīng)的指定索引上面.
??????? Redis中的hash沖突是指,兩個(gè)key的哈希值和哈希桶計(jì)算對應(yīng)關(guān)系時(shí),正好落在了一個(gè)哈希桶中.
??????? Redis的哈希表是采用鏈地址法解決鍵沖突的,每個(gè)哈希表節(jié)點(diǎn)上都有一個(gè)next指針,多個(gè)哈希表節(jié)點(diǎn)可以用next指針構(gòu)成一個(gè)單向鏈表,被分配到同一個(gè)索引上的多個(gè)節(jié)點(diǎn)可以用這個(gè)單向鏈表連接起來,這樣就解決了鍵沖突的問題.
????????
Redis實(shí)現(xiàn)分布式鎖
??????? 在分布式場景中,我們傳統(tǒng)的synchronized和lock都失效了,所以此時(shí)需要一種全新的鎖.redis提供的了一個(gè)命令--setnx,當(dāng)我們使用這個(gè)命令去存儲數(shù)據(jù),如果當(dāng)前的key已經(jīng)存在,就不會進(jìn)行任何操作,同時(shí)返回0,如果不存在,就會成功存儲數(shù)據(jù),返回1.
??????? 根據(jù)這個(gè)機(jī)制,我們可以訪問一個(gè)程序時(shí),先存入一個(gè)約定好的key,value可以是我們當(dāng)前的時(shí)間戳,如果存入成功,那我們就視為當(dāng)前線程獲取到了鎖,如果存入失敗了.我們就視為鎖已被其他線程占有,當(dāng)前線程沒有獲取到線程鎖.在需要釋放線程鎖的時(shí)候,我們將這個(gè)key從redis中刪除即可.
??????? 同時(shí),為了避免死鎖,我們需要再setnx時(shí)對key 添加過期時(shí)間.
??????? 在獲取鎖時(shí),我們可以通過循環(huán)去不斷嘗試獲取鎖,如果獲取到了就開始執(zhí)行,如果沒有獲取到就一直獲取.當(dāng)然,我們也可以為這個(gè)循環(huán)添加一個(gè)超時(shí)時(shí)間.類似于自旋鎖的自旋機(jī)制.
緩存穿透問題
??????? 指查詢一個(gè)不存在的數(shù)據(jù),我們的機(jī)制是先去從緩存中讀取,如果緩存中不存在的話會去數(shù)據(jù)庫中查詢,并且將查詢到的結(jié)果存入緩存中.那如果數(shù)據(jù)庫中也沒有該數(shù)據(jù),就不會放入緩存中,所以這種情況下就會去穿過緩存去訪問數(shù)據(jù)庫,這樣就可能會導(dǎo)致數(shù)據(jù)庫同時(shí)處理大量請求,可能導(dǎo)致數(shù)據(jù)庫崩潰.
??????? 解決方法
- 如果是非法參數(shù),我們可以在api層做參數(shù)校驗(yàn),在接受到請求之后就去處理非法參數(shù).
- 如果是正確請求,但是數(shù)據(jù)庫中不存在,那我們在緩存中針對該數(shù)據(jù)添加一個(gè)key,value設(shè)為null,給他一個(gè)過期時(shí)間,這樣首次請求會到達(dá)數(shù)據(jù)庫,但是其他請求都會被緩存攔截.
- 采用布隆過濾器判斷數(shù)據(jù)是否存在,如果存在就繼續(xù)往下查.
緩存擊穿
??????? 緩存擊穿是指如果大量請求訪問某個(gè)數(shù)據(jù)的時(shí)候這個(gè)數(shù)據(jù)失效了,就會穿過緩存訪問數(shù)據(jù)庫,這樣對數(shù)據(jù)庫造成大量壓力,導(dǎo)致數(shù)據(jù)庫崩潰
??????? 我們可以通過設(shè)置熱點(diǎn)數(shù)據(jù)永不過期去解決,但是這樣可能會浪費(fèi)資源,所以我們可以使用分布式鎖進(jìn)行對數(shù)據(jù)庫的訪問攔截,同一時(shí)間該類請求中只能有一個(gè)線程訪問數(shù)據(jù)庫.這樣就會大大降低數(shù)據(jù)庫的壓力.
緩存雪崩
??????? 緩存雪崩是指同時(shí)間大量熱點(diǎn)數(shù)據(jù)同時(shí)失效,大量請求同時(shí)涌入數(shù)據(jù)庫,導(dǎo)致數(shù)據(jù)庫崩潰.
??????? 解決方式
??????? 首先最暴力的解決方式就是設(shè)置熱點(diǎn)數(shù)據(jù)永不過期.
??????? 其次就是對熱點(diǎn)數(shù)據(jù)設(shè)置隨機(jī)的過期時(shí)間,不讓大量熱點(diǎn)同時(shí)過期.
布隆過濾器
??????? 布隆過濾器是有一個(gè)初始值為0的位圖數(shù)組和n個(gè)哈希值組成的.當(dāng)我們存儲數(shù)據(jù)時(shí),針對一個(gè)key通過多個(gè)hash算法取多個(gè)值,在位圖數(shù)組中對這多個(gè)值對應(yīng)的位置值改為1
??????? 在查詢的時(shí)候,還是先針對這個(gè)key做hash計(jì)算取多個(gè)值,如果這幾個(gè)值對應(yīng)的位置都是1,則代表這個(gè)key可能存在.如果其中有一個(gè)以上的0,則說明這個(gè)key一定不存在.
??????? 例如:我們現(xiàn)在存儲兩條數(shù)據(jù),其key分別為zhang和li,如果我們經(jīng)過hash計(jì)算之后zhang得到了3個(gè)值,分別是1 3 5,那我們將位圖中第 1 3 5位對應(yīng)值分別改為1.li經(jīng)過hash計(jì)算之后得到了 7? 8? 9,那我們將位圖中第7 8 9對應(yīng)的值分別改為1.至此,布隆過濾器中第 1 3 5 7 8 9位的值為1,,其余為0.文章來源:http://www.zghlxwxcb.cn/news/detail-485676.html
??????? 我們現(xiàn)在開始查詢key為wang和zhao 的兩條數(shù)據(jù),加入wang通過hash計(jì)算之后得到的3個(gè)值,分別是1 5 8,我們在位圖數(shù)組上發(fā)現(xiàn)這三個(gè)位置對應(yīng)的值都是1,所以布隆過濾器會認(rèn)為這個(gè)值是可能存在的.zhao經(jīng)過hash 計(jì)算之后得到的數(shù)據(jù)分別是 2 3 5,在位圖數(shù)組上我們可以看到 3 5兩個(gè)位置對應(yīng)的值是1,但是2對應(yīng)的值還是0,所以認(rèn)為和這個(gè)key絕對不存在,就會被攔截.文章來源地址http://www.zghlxwxcb.cn/news/detail-485676.html
到了這里,關(guān)于Java常見面試題之Redis的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!