這篇文章跟大家分享40道Redis面試題,內含答案解析和Redis知識點心智圖。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。
Redis影片教學】
Redis 優點(1)效能極高– Redis 能讀的速度是110000 次/ s,寫的速度是81000 次/s 。 (2)豐富的資料型別 – Redis 支援二進位案例的 Strings, Lists, Hashes, Sets 與Ordered Sets 資料型別運算。 (3)原子 – Redis 的所有操作都是原子性的,意思就是要嘛成功執行要嘛失敗完全不執行。單一操作是原子性的。多個操作也支援事務,即原子性,透過 MULTI 和 EXEC指令包起來。 (4)豐富的特性 – Redis 也支援 publish/subscribe, 通知, key 過期等等特性。 Redis 與其他 key-value 儲存有什麼不同? (1)Redis 有著更為複雜的資料結構並且提供對他們的原子性操作,這是一個不同於其他資料庫的進化路徑。 Redis 的資料類型都是基於基本資料結構的同時對程式設計師透明,無需進行額外的抽象。 (2)Redis 運行在記憶體中但是可以持久化到磁碟,所以在對不同資料集進行高速讀寫時需要權衡內存,因為資料量不能大於硬體記憶體。在記憶體資料庫方面的另一個優點是,相比在磁碟上相同的複雜的資料結構,在記憶體中操作起來非常簡單,這樣 Redis可以做很多內部複雜性很強的事情。同時,在磁碟格式方面他們是緊湊的以追加的方式產生的,因為他們並不需要進行隨機存取。Redis提供兩種持久化機制RDB 和AOF 機制:
1、RDBRedis DataBase)持久化方式:
是指用資料集快照的方式半持久化模式)記錄redis 資料庫的所有鍵值對,在某個時間點將資料寫入一個臨時文件,持久化結束後,用這個臨時文件替換上次持久化的文件,達到資料恢復。
優點:
(1)只有一個檔案 dump.rdb,方便持久化。
(2)容災性好,一個檔案可以儲存到安全的磁碟。
(3)效能最大化,fork 子程序來完成寫入操作,讓主程序繼續處理指令,所以是 IO最大化。使用單獨子程序來進行持久化,主程序不會進行任何 IO 操作,保證了 redis的高效能)
(4)相對於資料集大時,比 AOF 的啟動效率更高。
缺點:
資料安全性低。 RDB 是間隔一段時間進行持久化,如果持久化之間 redis 發生故障,會發生資料遺失。所以這種方式比較適合資料要求不嚴謹的時候
2、AOFAppend-only file)持久化方式:
是指所有的命令列記錄以redis 指令請求協定的格式完全持久化儲存)儲存為aof 檔案。
優點:
(1)資料安全,aof 持久化可以設定 appendfsync 屬性,有 always,每進行一次指令操作就會記錄到 aof 檔案一次。
(2)透過 append 模式寫入文件,即使中途伺服器宕機,可以透過 redis-check-aof工具解決資料一致性問題。
(3)AOF 機制的 rewrite 模式。 AOF 檔案沒被rewrite 之前(檔案過大時會對指令合併重寫),可以刪除其中的某些指令(例如誤操作的flushall))
缺點:
( 1)AOF 檔案比RDB 檔案大,且恢復速度慢。
(2)資料集大的時候,比 rdb 啟動效率低。
(1)Master 最好不要寫記憶體快照,如果Master 寫記憶體快照,save 指令調度rdbSave函數,會阻塞主執行緒的工作,當快照比較大時對效能影響是非常大的,會間斷性暫停服務
(2)如果資料比較重要,某個Slave 開啟AOF 備份數據,策略設定為每秒同步一
(3)為了主從複製的速度和連接的穩定性,Master 和Slave 最好在同一個區域網路
(4)盡量避免在壓力很大的主庫上增加從
(5)主從複製不要用圖狀結構,用單向鍊錶結構更為穩定,即:Master <- Slave1<- Slave2 <- Slave3…這樣的結構方便解決單點故障問題,實現Slave 對Master的替換。如果 Master 掛了,可以立刻啟用 Slave1 做 Master,其他不變。
(1)定時刪除:在設定鍵的過期時間的同時,建立一個定時器 timer). 讓定時器在鍵的過期時間來臨時,立即執行對鍵的刪除操作。
(2)惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵。
(3)定期刪除:每隔一段時間程式就會對資料庫進行一次檢查,刪除裡面的過期鍵。至於要刪除多少過期鍵,以及要檢查多少個資料庫,則由演算法決定。
volatile-lru:從已設定過期時間的資料集(server.db[i].expires )中挑選最近最少使用的資料淘汰
volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的資料淘汰
# volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰
allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
no-enviction(驅逐):禁止驅逐資料
注意這裡的6 種機制,volatile 和allkeys 規定了是對已設定過期時間的資料集淘汰資料還是從全部資料集淘汰數據,後面的lru、ttl 以及random 是三種不同的淘汰策略,再加上一種no-enviction 永不回收的策略。
使用策略規則:
(1)如果資料呈現冪律分佈,也就是一部分資料存取頻率高,且一部分資料存取頻率低,則使用allkeys-lru
(2)如果資料呈現平等分佈,也就是所有的資料存取頻率都相同,則使用allkeys-random
答案 :Redis 為了達到最快的讀寫速度將資料都讀到記憶體中,並透過非同步的方式將資料寫入磁碟。所以 redis 具有快速和資料持久化的特徵。如果不將資料放在記憶體中,磁碟 I/O 速度為嚴重影響 redis 的效能。在記憶體越來越便宜的今天,redis 將會越來越受歡迎。如果設定了最大使用的內存,則資料已有記錄數達到內存限值後不能繼續插入新值。
答案:Redis 可以使用主從同步,從同步。第一次同步時,主節點做一次 bgsave,並同時將後續修改操作記錄到記憶體 buffer,待完成後將 rdb 檔案全量同步到複製節點,複製節點接受完成後將 rdb 鏡像載入到記憶體。載入完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重播就完成了同步過程。
答案:可以將多次 IO 往返的時間縮減為一次,前提是 pipeline 執行的指令之間沒有因果相關性。使用 redis-benchmark 進行壓測的時候可以發現影響 redis 的 QPS峰值的一個重要因素是 pipeline 批次指令的數目。
(1)Redis Sentinal 著眼於高可用,在 master 宕機時會自動將 slave 提升為master,繼續提供服務。
(2)Redis Cluster 著眼於擴展性,在單一 redis 記憶體不足時,使用 Cluster 進行分片儲存。
答:有A,B,C 三個節點的集群,在沒有複製模型的情況下,如果節點B 失敗了,那麼整個集群就會以為缺少5501-11000 這個範圍的槽而不可用。
答:Redisson、Jedis、lettuce 等等,官方推薦使用 Redisson。
答:Jedis 是Redis 的Java 實作的客戶端,其API 提供了比較全面的Redis 指令的支援;Redisson 實作了分散式和可擴展的Java 資料結構,和Jedis 相比,功能較為簡單,不支援字串操作,不支援排序、事務、管道、分區等Redis 特性。
Redisson 的宗旨是促進使用者對 Redis 的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。
設定密碼:config set requirepass 123456
授權密碼:auth 123456
答案:Redis 集群並沒有使用一致性hash,而是引入了哈希槽的概念,Redis 集群有16384 個哈希槽,每個key 通過CRC16 校驗後對16384 取模來決定放置哪個槽,叢集的每個節點負責一部分hash 槽。
回答:為了使在部分節點失敗或大部分節點無法通訊的情況下叢集仍然可用,所以叢集使用了主從複製模型,每個節點都會有N-1 個複製品.
答案 :Redis 並不能保證資料的強一致性,這意味著這在實際中集群在特定的條件下可能會遺失寫入操作。
答:非同步複製
答:16384 個。
答案:Redis 叢集目前無法做資料庫選擇,預設在 0 資料庫。
答案:使用 ping 指令。
答:
(1)事務是一個單獨的隔離操作:交易中的所有命令都會序列化、依序執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。
(2)事務是一個原子操作:事務中的指令要麼全部被執行,要麼全部都不執行。
答案:MULTI、EXEC、DISCARD、WATCH
答案:EXPIRE 和 PERSIST 指令。
答:盡可能使用散列表(hashes),散列表(是說散列表裡面儲存的數少)使用的記憶體非常小,所以你應該盡可能的將你的資料模型抽像到一個散列表裡面。例如你的 web 系統中有一個用戶對象,不要為這個用戶的名稱,姓氏,郵箱,密碼設定單獨的 key,而是應該把這個用戶的所有資訊儲存到一張散列表裡面。
答案:一個客戶端運行了新的命令,新增了新的資料。 Redi 檢查記憶體使用情況,如果大於 maxmemory 的限制, 則根據設定好的策略進行回收。一個新的命令被執行,等等。所以我們不斷地穿越記憶體限制的邊界,透過不斷達到邊界然後不斷地回收回到邊界以下。如果一個指令的結果導致大量記憶體被使用(例如很大的集合的交集保存到一個新的鍵),那麼不用多久記憶體限制就會被這個記憶體使用量超越。
回答:如果你使用的是32 位元的Redis 實例,可以好好利用Hash,list,sorted set,set等集合類型數據,因為通常情況下很多小的Key-Value 可以用更緊湊的方式存放在一起。
答:如果達到設定的上限,Redis 的寫入指令會回傳錯誤訊息(但是讀取指令還可以正常回傳。)或者你可以將Redis 當快取來使用設定淘汰機制,當Redis達到記憶體上限時會沖刷掉舊的內容。
答:理論上 Redis 可以處理多達 232 的 keys,並且在實際中進行了測試,每個實例至少存放了 2 億 5 千萬的 keys。我們正在測試一些較大的值。任何 list、set、和 sorted set 都可以放 232 個元素。換句話說,Redis 的儲存極限是系統中的可用記憶體值。
答案:Redis 記憶體資料集大小上升到一定大小的時候,就會施加資料淘汰策略。
相關知識:Redis 提供6 種資料淘汰策略:
volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰
volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的資料淘汰
volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰
allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
no-enviction(驅逐):禁止驅逐資料
1、會話快取(Session Cache)
最常用的一種使用 Redis 的情境是會話快取(session cache)。用 Redis 快取會話比其他儲存(如 Memcached)的優點在於:Redis 提供持久化。當維護一個不是嚴格要求一致性的快取時,如果用戶的購物車資訊全部遺失,大部分人都會不高興的,現在,他們還會這樣嗎?幸運的是,隨著 Redis 這些年的改進,很容易找到怎麼恰當的使用 Redis 來快取會話的文檔。甚至廣為人知的商業平台Magento 也提供 Redis 的插件。
2、全頁快取(FPC)
除基本的會話 token 之外,Redis 還提供很簡單的 FPC 平台。回到一致性問題,即使重啟了 Redis 實例,因為有磁碟的持久化,使用者也不會看到頁面載入速度的下降,這是一個極大改進,類似 PHP 本地 FPC。再次以 Magento 為例,Magento提供一個外掛程式來使用 Redis 作為全頁快取後端。此外,對 WordPress 的使用者來說,Pantheon 有一個非常好的外掛程式 wp-redis,而這個外掛程式可以幫助你以最快速度載入你曾經瀏覽過的頁面。
3、佇列
Reids 在記憶體儲存引擎領域的一大優點是提供 list 和 set 操作,這使得 Redis能作為一個很好的訊息佇列平台來使用。 Redis 作為佇列使用的操作,就類似於本機程式語言(如 Python)對 list 的 push/pop 操作。如果你快速的在 Google中搜尋“Redis queues”,你馬上就能找到大量的開源項目,這些項目的目的就是利用 Redis 創建非常好的後端工具,以滿足各種隊列需求。例如,Celery 有一個後台是使用 Redis 作為 broker,你可以從這裡去查看。
4,排行榜/計數器
#Redis 在記憶體中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)也使得我們在執行這些運算的時候變的非常簡單,Redis 只是正好提供了這兩種資料結構。所以,我們要從排序集合中獲取到排名最靠前的10個用戶–我們稱之為“user_scores”,我們只需要像下面一樣執行即可: 當然,這是假定你是根據你用戶的分數做遞增的排序。如果你想回傳使用者及使用者的分數,你需要這樣執行: ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一個很好的例子,用Ruby 實現的,它的排行榜就是使用Redis 來儲存資料的,你可以在這裡看到。
5、發布/訂閱
最後(但肯定不是最不重要的)是 Redis 的發布/訂閱功能。發布/訂閱的使用場景確實非常多。我已看見人們在社交網路連結中使用,還可作為基於發布/訂閱的腳本觸發器,甚至用 Redis 的發布/訂閱功能來建立聊天系統!
答案:使用 keys 指令可以掃出指定模式的 key 清單。
對方接著追問:如果這個 redis 正在給線上的業務提供服務,那使用 keys 指令會有什麼問題?
這時候你要回答 redis 關鍵的一個特性:redis 的單線程的。 keys 指令會導致執行緒阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這時候可以使用scan 指令,scan 指令可以無阻塞的提取出指定模式的key 列表,但是會有一定的重複機率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys 指令長。
答案:如果大量的 key 過期時間設定的過於集中,到過期的那個時間點,redis 可能會出現短暫的卡頓現象。一般需要在時間上加一個隨機值,使得過期時間分散一些。
答案:一般使用 list 結構作為佇列,rpush 生產訊息,lpop 消費訊息。當 lpop 沒有消息的時候,要適當 sleep 一會兒再重試。如果對方追問可不可以不用 sleep 呢? list 還有個指令叫 blpop,在沒有訊息的時候,它會阻塞住直到訊息到來。如果對方追問能不能生產一次消費多次呢?使用 pub/sub 主題訂閱者模式,可以實作1:N 的訊息佇列。
如果對方追問 pub/sub 有什麼缺點?
在消費者下線的情況下,生產的訊息會遺失,得使用專業的訊息佇列如 RabbitMQ等。
如果對方追問 redis 如何實作延時佇列?
我估計現在你很想把麵試官一棒打死如果你手上有一根棒球棍的話,怎麼問的這麼詳細。但是你很克制,然後神態自若的回答道:使用 sortedset,拿時間戳作為score,訊息內容作為 key 呼叫 zadd 來生產訊息,消費者用 zrangebyscore 指令取得 N 秒之前的資料輪詢進行處理。到這裡,面試官暗地裡已經對你豎起了大拇指。但他不知道的是此刻你卻豎起了中指,在椅子背後。
先拿 setnx 來爭搶鎖,搶到之後,再用 expire 給鎖加一個過期時間防止鎖忘記了釋放。
這時候對方會告訴你說你回答得不錯,然後接著問如果在 setnx 之後執行 expire之前進程意外 crash 或者要重啟維護了,那會怎麼樣?這時候你要給予驚訝的回饋:唉,是喔,這個鎖就永遠得不到釋放了。緊接著你需要抓一抓自己得腦袋,故作思考片刻,好像接下來的結果是你主動思考出來的,然後回答:我記得set 指令有非常複雜的參數,這個應該是可以同時把setnx 和expire合成一條指令來用的!對方這時會露出笑容,心裡開始默念:摁,這小子還不錯。
#更多程式相關知識,請造訪:程式入門! !
以上是你不可錯過的40道Redis面試題(含答案和心智圖)的詳細內容。更多資訊請關注PHP中文網其他相關文章!