Redis常見面試題

1、Redis分佈鎖是怎麼實現的?
先拿setnx來爭搶鎖,搶到之後再用expire給鎖加一個過期時間防止鎖忘記釋放。
如果在setnx之後執行expire之前的進程意外crash或重啓維護了,那會咋樣?Set指令 有非常複雜的參數,可以同時把setnx和expire合成一條指令來用的。
2、使用過Redis做異步隊列麼,你是怎麼用的?有什麼缺點?
一般使用list結構作爲隊列,rpush生成消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep,一會在再重試。
缺點:在消費者下線的情況下,生產者的消息會丟失,所以得使用專業的消息隊列如rabbitmq等。
能不能生產一次消費多次呢?使用pub/sub主題訂閱者模式,可以實現1:N的消息隊列。
3、什麼是緩存穿透?如何避免?什麼是緩存雪崩?如何避免?
(1)一般的緩存系統,都是按照key去緩存查詢,如何不存在就去對應的value,就應該去後端系統查找(比如DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對後端系統造成很大的壓力,這就叫緩存穿透。
(2)如何避免緩存穿透?
①對查詢結果爲空的情況也進行緩存,緩存時間設置短一點或者是該key對應的數據insert之後清理緩存。
②對一定不存在的key進行過濾。可以把所有可能存在的key放到一個大的bitMap中,查詢時通過該BitMap過濾。
(3)緩存雪崩
①當緩存服務器重啓或大量緩存集中在某一個時間段失效,這樣在失效的時候會給後端系統帶來很大的壓力,導致系統崩潰。
(4)如何避免緩存雪崩?
①當緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的數量。比如對某個key只允許一個線程查詢數據寫緩存,其他線程等待。
②做二級緩存,A1爲原始緩存,A2爲拷貝緩存,當A1失效時可以訪問A2,A1緩存失效時間設置爲短期,A2 設置爲長期
③不同的key設置不同的過期時間,讓緩存失效時間點儘量均勻。
4、Redis中的管道有什麼用?
一次請求/響應服務器能實現處理新的請求即使舊的請求還未被響應,這樣就可以將多個命令發送到服務器,而不用等待回覆,最後在一個步驟中讀取該答覆。這就是管道,是一種幾十年來廣泛使用的技術。例如許多POP3協議已經實現支持這個功能,大大加快了從服務器下載新郵件的功能。
5、怎麼理解Redis事務?
事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序的進行,事務在執行的過程中不會被其他客戶端發送來的命令請求所打斷。事務就是一個原子操作:事務中的命令要麼全部被執行,要麼全部不執行。
6、Redis事務相關的命令有哪幾個?
MULTI、EXSC、DISCARD、WATCH
7、Redis key的過期時間和永久有效分別怎麼設置?
EXPIRE和PERSIST命令
8、Redis如何做內存優化?
儘可能的使用散列表(hashes),散列表(是說散列表裏面存儲的數少)使用的內存非常小,所以你應該儘可能將你的數據模型抽象到一個散列表裏面。比如你的web系統中有一個用戶對象,不要爲這個用戶的名稱、姓氏、郵箱、密碼設置單獨key,而是將這個用戶的所有信息存儲到一張散列表裏面。
9、Redis回收進程是如何工作的?
一個客戶端運行了新的命令,添加了新的數據。Redis檢查內存使用情況,如果大於maxmemory的限制,就會根據設定好的策略進行回收,一個新的命令被執行,等等。所以我們不斷的穿越內存限制的邊界,通過不斷達到邊界然後不斷的回收到邊界以下。如果一個命令的結果導致大量內存被使用(例如很大的集合的交集保存到一個新的鍵),不用多久內存限制就會被這個內存使用量超越。
10、Redis支持的java客戶端都有哪些?官方推薦有那個?
Redisson、Jedis、lettuce等等,官方推薦使用Redisson
11、Redis和Redisson的關係?
Redisson是一個高級的分佈式協調Redis客戶端,能幫助用戶在分佈式環境中輕鬆實現一些java的對象(Bloom filter、BitSet、Set、SetMultimap、ScoredSortedSet、SortedSet、Map、List、Queue、ConcurrentMap、ListMultimap、BlockingQueue、Deque、BlockingDeque、Semaphore、Lock、ReadWriteLock、AtomicLong、CountDownLatch、Publish/Subscribe、HyperLogLog)
12、Jedis和Redisson對比有什麼優缺點?
Jedis是Redis的java實現的客戶端,其中API提供了比較全面的Redis命令的支持; Redisson實現了分佈式和擴展的java數據結構,和Jedis相比功能比較簡單,不支持字 符串操作,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用 者對Redis的關注分離,從而讓使用者能夠將精力更集中的放在處理業務邏輯上。
13、說說Redis哈希槽的概念?
Redis集羣沒有使用一致性hash,而是引入了哈希槽的概念,Redis集羣有16384個哈希槽,每個key通過CRC16效驗後對16384取模來決定放置哪個槽,集羣的每個節點負責一部分hash槽。
14、Redis集羣的主從複製模型是怎樣的?
爲了使在部分節點失敗或者大部份節點無法通信得情況下集羣仍然可用,所以集羣使用 了主從複製模型,每個節點都有N-1個複製品。
15、Redis集羣會有寫操作丟失嗎?爲什麼?
Redis並不能保證數據的強一致性,這意味着在實際中集羣在特定條件下可能會丟失寫操作。
16、一個字符串類型的值能存儲最大容量是多少?
521M
17、爲什麼Redis需要把所有數據放到內存當中?
Redis爲了達到最快的讀寫速度將數據都讀到內存中,並通過異步的方式將數據寫入磁 盤。所以Redis具有快速和數據持久化的特徵,如果不將數據放到放在內存中,磁盤I/O 速度嚴重影響Redis的性能。在內存越來越便宜的今天,Redis將會越來越受歡迎,如 果設置自了使用的最大內存,則數據已有記錄數達到內存限值後不能繼續插入新值。
18、Redis集羣方案應該怎麼做?都有哪些方案?
(1)Codis2 目前用的最多的集羣方案,基本和twemproxy一致的效果,但他支持在節點數量改變情況下,舊節點數據可以恢復到新的hash節點。
(2)Redis cluster3.0 自帶的集羣,特點在於他的分佈式算法不是一致性hash,而是hash槽的概念,以及自身支持節點設置節點。
(3)在業務代碼層實現,起幾個毫無關聯的Redis實例,在代碼層對key進行hash計算,然後去對應Redis實例操作數據,這種方式對hash層代碼要求比較高,考慮部分包括節點失效後的替代方案,數據震盪後的自動腳本恢復,實例監控等等。
19、Redis集羣方案什麼情況下會導致整個集羣不可用?
有A、B、C三個節點的集羣,在沒有複製模型的情況下,如果節點B失敗了,那麼整 個整個集羣就會以爲缺少5501-11000這個範圍的槽而不可用。
20、MySQL裏有2000W數據,Redis中只存20W的數據,如何保證Redis中的數據都是熱點 數據?
Redis內存數據集大小上升到一定大小的時候,就會實施數據淘汰策略
20、Redis有哪些適合的場景?
(1)回話緩存:購物車信息
(2)全頁緩存:
(3)隊列
(4)排行榜/計數器,Redis在內存中對數字進行遞歸增或減的操作實現的非常好。集合(set)和有序集合(sortedSet)也使得我們在執行這些操作的時候變得非常簡單,Redis只是正好提供了這兩種數據結構
(5)發佈/訂閱
21、什麼是Redis?他的優缺點
Redis是一個key-value類型的內存數據庫,很像memcached,整個數據庫統統加載在內 存當中進行操作,定期通過異步操作把數據flush到硬盤上進行保存。因爲是純內存操 作Redis的性能非常出色,每秒可以處理10萬次讀寫操作,是已知性能最快的Key-Value 數據庫,Redis的出色不僅僅是性能,Redis最大的魅力是支持保存多種數據結構,此外 單個Value的最大限制爲1G,不想memcached只能保存1MB的數據,因此Redis可以 用來實現很多有用的功能。比如說用它的list來做FIFO雙向鏈表,實現一個輕量級的高 性能消息隊列,用它的Set 可以做高性能的tag系統等等,另外Redis也可以對存入的 key-Value設置expire時間,因此也可以被當做一個功能加強版的memcached來用。
缺點:數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis 適合的場景主要侷限在較小數據量的高性能操作和運算上。
22、Redis和memcached相比有哪些優勢?
(1)Memcached所有的值均是簡單的字符串,Redis作爲其替代者,支持更爲豐富的數據類型
(2)Redis的速度比memcached快很多
(3)Redis可以持久化其數據
23、Redis支持哪幾種數據類型?
String、List、Set、SortedSet、hash
24、Redis主要消耗什麼物理資源?
內存
25、Redis有哪幾種數據淘汰策略?
(1)Noevication:返回錯誤當內存限制達到,並且客戶端嘗試執行讓更多的內存被使用的命令
(2)Allkeys-lru:嘗試回收使用最少的鍵(LRU),使得新添加的數據有空間存放
(3)Volatile-LRU:嘗試回收最少使用的鍵(LRU),但僅限於在過期集合的鍵,使得新添加的數據有空間存放。
(4)Allkeys-random:回收隨機的鍵使得新添加的數據有空間存放。
(5)Volatile-random:回收隨機的建使得新添加的數據有空間存放,但僅限於在過期集合的鍵
(6)Volatile-ttl:回收過期集合的鍵,並且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
26、Redis和MQ如何平滑的擴容和縮容?
MQ的消息是存放在內存或者磁盤中的,在縮減集羣數量時,必須要遷移節點的數據。 增加節點時,要重新配置集羣。這麼看來是無法平滑縮容和擴容的。
27、MQ的消息生產比消費速度快的多,有什麼解決方案嗎?
生產消息比消費消息快的多,這個本身是沒有問題的,因爲MQ的一個作用就是削峯。 如果要提高消費速度可以增加多個消費者。
28、Redis和memcached有什麼區別?
(1)Redis相對於memcached來說擁有更豐富的數據類型,可以使用更多的複雜場景
(2)Redis原生就是支持cluster集羣模式的,但是memcached沒有原生的集羣模式,需要依靠客戶端實現往集羣中分片寫入數據
(3)Redis使用的是單核,memcached使用的是多核,所以Redis在存儲小數據時候性能比較高,memcached在存儲大一點的數據時候性能更好。
(4)Memcached在使用簡單的key-value存儲時內存的利用率更高,但Redis如果採用hash的結構來做存儲,內存使用率會較好。
29、爲什麼Redis單線程模型效率很高?
首先Redis裏的數據是存儲在內存中,對Redis裏的數據操作的時候實際上是純內存操作;其次他的文件事件處理器的核心機制是非阻塞的IO多路複用程序;最重要的是單線程反而避免了多線程頻繁上下文切換帶來的損耗。
30、Redis的過期策略和內存淘汰機制?
(1)在我們平常使用的Redis做緩存的時候,我們經常給這個緩存設置一個過期時間,那 麼大家知道如果我們在查過期後的key時是不會有數據的。
(2)那麼所有過期key的數據已經被刪除了麼?是如何被刪除的?
其實如果一個key過期了,但是數據不一定已經被刪除了,因爲Redis採用的是定期刪 除和惰性刪除。定期刪除是指Redis默認會每隔100ms會隨機抽取一些設置了過期時間 的key檢查是否過期了,如果過期了就刪除。
(3)那麼爲什麼不遍歷刪除所有而是隨機抽取一些呢?
因爲可能Redis中放置了大量的key,如果每隔100ms都遍歷,那麼CPU肯定會爆炸, Redis也就GG了。
(4)那麼這樣的話,爲什麼去查過期的key的話會查不到?
其實這就是Redis的惰性刪除,當你去查key的時候,Redis會檢查一下這個key時是否 設置了過期時間和是否已經過期了,如果已經過期Redis會刪除這個key,並且返回空。
(5)其實當內存佔用過多的時候,此時會進行內存淘汰,Redis提供了幾種內存淘汰策 略:
①Noeviction:當內存不足以容納寫入數據是,新寫入的數據會報錯
②Allkeys-LRU:當內存不足以容納新寫入數據時,會移除最近最少使用的key
③Allkeys-random:當內存不足以容納新寫入數據時,會隨機移除某個key
④Volatile-LRU:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的key
⑤Volatile-random:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,隨機移除某個key
⑥Volatile-TTL:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的key優先刪除。
以上幾個策略最常用的應該是allkeys-LRU,其實這也要根據業務場景去選擇
31、Redis的併發競爭問題以及解決方案:
當並發表的去set某個值時可能結果與我們期望的不同,這時我們就要採取一些措施來避免,首先我們可以採用分佈鎖來保證,其次我們可以採用Redis的CAS 事務。Redis使用WATCH命令實現事務的“檢查再設置”(CAS)行爲。作爲WATCH命令的參數的鍵會受到Redis的監控,Redis能檢測他們的變化。在執行EXEC命令之前,如果Redis檢測到至少有一個鍵被修改,那麼整個事務便會中止運行,然後EXEC命令會返回一個 null值,提醒用戶事務運行失敗。
32、緩存雪崩和穿透:
(1)緩存雪崩:發生在高併發的情況下,如果Redis宕機不可用時大量的請求涌入數據庫,導致數據庫崩潰以至於整個數據庫不可用,在這種情況下數據庫會直接無法重啓,因爲起來會被再次打掛。所以要想避免緩存雪崩可以考慮採用以下措施:首先儘量保證Redis的高可用(可以通過主從+哨兵或者Redis cluster來提供高可用),其次可以使用一些限流降級組件(例如hystrix)來避免MySQL被打掛,最後如果不是分佈式可以考慮本地緩存一些數據
緩存穿透:發生在一些惡意攻擊下,在有些惡意攻擊中會僞造請求來訪問服務器,由於僞造 的錯誤數據在Redis中不能找到,所以請求直接打到數據庫,導致高併發吧數據庫打掛,同緩存雪崩一樣,在這個情況下即使重啓數據庫也不能解決問題。想避免這種問題可以採用以下措施:首先對請求過來的參數做合法性效驗,例如用戶的id不能是負數;其次可以考慮如果有參數頻繁訪問數據庫而不能查到,可以在Redis給他搞一個空值,避免請求直接打在數據庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章