面試問題整理
Redis
應(yīng)用場景
- 緩存
- 共享Session
- 消息隊列系統(tǒng)
- 分布式鎖
單線程的Redis為什么快
- 純內(nèi)存操作
- 單線程操作,避免了頻繁的上下文切換
- 合理高效的數(shù)據(jù)結(jié)構(gòu)
- 采用了非阻塞I/O多路復(fù)用機制
Redis 的數(shù)據(jù)結(jié)構(gòu)及使用場景
- String字符串:字符串類型是 Redis 最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),首先鍵都是字符串類型,而且 其他幾種數(shù)據(jù)結(jié)構(gòu)都是在字符串類型基礎(chǔ)上構(gòu)建的,我們常使用的 set key value 命令就是字符串。常用在緩存、計數(shù)、共享Session、限速等。
- Hash哈希:在Redis中,哈希類型是指鍵值本身又是一個鍵值對結(jié)構(gòu),哈希可以用來存放用戶信息,比如實現(xiàn)購物車。
- List列表(雙向鏈表):列表(list)類型是用來存儲多個有序的字符串。可以做簡單的消息隊列的功能。
- Set集合:集合(set)類型也是用來保存多個的字符串元素,但和列表類型不一 樣的是,集合中不允許有重復(fù)元素,并且集合中的元素是無序的,不能通過索引下標獲取元素。利用 Set 的交集、并集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。
- Sorted Set有序集合(跳表實現(xiàn)):Sorted Set 多了一個權(quán)重參數(shù) Score,集合中的元素能夠按 Score 進行排列??梢宰雠判邪駪?yīng)用,取 TOP N 操作。
Redis 的數(shù)據(jù)過期策略
Redis 中數(shù)據(jù)過期策略采用定期刪除+惰性刪除策略
- 定期刪除策略:Redis 啟用一個定時器定時監(jiān)視所有的 key,判斷key是否過期,過期的話就刪除。這種策略可以保證過期的 key 最終都會被刪除,但是也存在嚴重的缺點:每次都遍歷內(nèi)存中所有的數(shù)據(jù),非常消耗 CPU 資源,并且當(dāng) key 已過期,但是定時器還處于未喚起狀態(tài),這段時間內(nèi) key 仍然可以用。
- 惰性刪除策略:在獲取 key 時,先判斷 key 是否過期,如果過期則刪除。這種方式存在一個缺點:如果這個 key 一直未被使用,那么它一直在內(nèi)存中,其實它已經(jīng)過期了,會浪費大量的空間。
- 這兩種策略天然的互補,結(jié)合起來之后,定時刪除策略就發(fā)生了一些改變,不在是每次掃描全部的 key 了,而是隨機抽取一部分 key 進行檢查,這樣就降低了對 CPU 資源的損耗,惰性刪除策略互補了為檢查到的key,基本上滿足了所有要求。但是有時候就是那么的巧,既沒有被定時器抽取到,又沒有被使用,這些數(shù)據(jù)又如何從內(nèi)存中消失?沒關(guān)系,還有內(nèi)存淘汰機制,當(dāng)內(nèi)存不夠用時,內(nèi)存淘汰機制就會上場。淘汰策略分為:
- 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報錯。(Redis 默認策略)
- 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的 Key。(LRU推薦使用)
- 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,隨機移除某個 Key。
- 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,移除最近最少使用的 Key。這種情況一般是把 Redis 既當(dāng)緩存,又做持久化存儲的時候才用。
- 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,隨機移除某個 Key。
- 當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在設(shè)置了過期時間的鍵空間中,有更早過期時間的 Key 優(yōu)先移除。
Redis的LRU具體實現(xiàn):
傳統(tǒng)的LRU是使用棧的形式,每次都將最新使用的移入棧頂,但是用棧的形式會導(dǎo)致執(zhí)行select *的時候大量非熱點數(shù)據(jù)占領(lǐng)頭部數(shù)據(jù),所以需要改進。Redis每次按key獲取一個值的時候,都會更新value中的lru字段為當(dāng)前秒級別的時間戳。Redis初始的實現(xiàn)算法很簡單,隨機從dict中取出五個key,淘汰一個lru字段值最小的。在3.0的時候,又改進了一版算法,首先第一次隨機選取的key都會放入一個pool中(pool的大小為16),pool中的key是按lru大小順序排列的。接下來每次隨機選取的keylru值必須小于pool中最小的lru才會繼續(xù)放入,直到將pool放滿。放滿之后,每次如果有新的key需要放入,需要將pool中l(wèi)ru最大的一個key取出。淘汰的時候,直接從pool中選取一個lru最小的值然后將其淘汰。
如何解決 Redis 緩存雪崩問題
- 使用 Redis 高可用架構(gòu):使用 Redis 集群來保證 Redis 服務(wù)不會掛掉
- 緩存時間不一致,給緩存的失效時間,加上一個隨機值,避免集體失效
- 限流降級策略:有一定的備案,比如個性推薦服務(wù)不可用了,換成熱點數(shù)據(jù)推薦服務(wù)
如何解決 Redis 緩存穿透問題
.........
ZooKeeper
CAP定理:
一個分布式系統(tǒng)不可能同時滿足以下三種,一致性(C:Consistency),可用性(A:Available),分區(qū)容錯性(P:Partition Tolerance).在此ZooKeeper保證的是CP,ZooKeeper不能保證每次服務(wù)請求的可用性,在極端環(huán)境下,ZooKeeper可能會丟棄一些請求,消費者程序需要重新請求才能獲得結(jié)果。另外在進行l(wèi)eader選舉時集群都是不可用,所以說,ZooKeeper不能保證服務(wù)可用性。(Base理論CA強一致性和最終一致性)
ZAB協(xié)議:
ZAB協(xié)議包括兩種基本的模式:崩潰恢復(fù)和消息廣播。當(dāng)整個 Zookeeper 集群剛剛啟動或者Leader服務(wù)器宕機、重啟或者網(wǎng)絡(luò)故障導(dǎo)致不存在過半的服務(wù)器與 Leader 服務(wù)器保持正常通信時,所有服務(wù)器進入崩潰恢復(fù)模式,首先選舉產(chǎn)生新的 Leader 服務(wù)器,然后集群中 Follower 服務(wù)器開始與新的 Leader 服務(wù)器進行數(shù)據(jù)同步。當(dāng)集群中超過半數(shù)機器與該 Leader 服務(wù)器完成數(shù)據(jù)同步之后,退出恢復(fù)模式進入消息廣播模式,Leader 服務(wù)器開始接收客戶端的事務(wù)請求生成事物提案來進行事務(wù)請求處理。
選舉算法和流程:FastLeaderElection(默認提供的選舉算法)
目前有5臺服務(wù)器,每臺服務(wù)器均沒有數(shù)據(jù),它們的編號分別是1,2,3,4,5,按編號依次啟動,它們的選擇舉過程如下:
- 服務(wù)器1啟動,給自己投票,然后發(fā)投票信息,由于其它機器還沒有啟動所以它收不到反饋信息,服務(wù)器1的狀態(tài)一直屬于Looking。
- 服務(wù)器2啟動,給自己投票,同時與之前啟動的服務(wù)器1交換結(jié)果,由于服務(wù)器2的編號大所以服務(wù)器2勝出,但此時投票數(shù)沒有大于半數(shù),所以兩個服務(wù)器的狀態(tài)依然是LOOKING。
- 服務(wù)器3啟動,給自己投票,同時與之前啟動的服務(wù)器1,2交換信息,由于服務(wù)器3的編號最大所以服務(wù)器3勝出,此時投票數(shù)正好大于半數(shù),所以服務(wù)器3成為leader,服務(wù)器1,2成為follower。
- 服務(wù)器4啟動,給自己投票,同時與之前啟動的服務(wù)器1,2,3交換信息,盡管服務(wù)器4的編號大,但之前服務(wù)器3已經(jīng)勝出,所以服務(wù)器4只能成為follower。
- 服務(wù)器5啟動,后面的邏輯同服務(wù)器4成為follower。
..........
查看完整內(nèi)容
[精華集錦] 20+ 互聯(lián)網(wǎng)大廠Java面試題全面整理總結(jié)
Kotlin 開發(fā)者社區(qū)
國內(nèi)第一Kotlin 開發(fā)者社區(qū)公眾號,主要分享、交流 Kotlin 編程語言、Spring Boot、Android、React.js/Node.js、函數(shù)式編程、編程思想等相關(guān)主題。