Redis 精要

huangdazhu發表於2019-09-16

1、使用redis有哪些好處?

  1. 速度快,因為資料存在記憶體中,類似於HashMap,HashMap的優勢就是查詢和操作的時間複雜度都是O(1)
  2. 支援豐富資料型別,支援string,list,set,sorted set,hash
  3. 支援事務,操作都是原子性,所謂的原子性就是對資料的更改要麼全部執行,要麼全部不執行
  4. 豐富的特性:可用於快取,訊息,按key設定過期時間,過期後將會自動刪除

2、redis相比memcached有哪些優勢?

  1. memcached所有的值均是簡單的字串,redis作為其替代者,支援更為豐富的資料型別
  2. redis的速度比memcached快很多
  3. redis可以持久化其資料

3、redis常見效能問題和解決方案:

  1. Master最好不要做任何持久化工作,如RDB記憶體快照和AOF日誌檔案
  2. 如果資料比較重要,某個Slave開啟AOF備份資料,策略設定為每秒同步一次
  3. 為了主從複製的速度和連線的穩定性,Master和Slave最好在同一個區域網內
  4. 儘量避免在壓力很大的主庫上增加從庫
  5. 主從複製不要用圖狀結構,用單向連結串列結構更為穩定,即:Master <- Slave1 <- Slave2 <- Slave3…

這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。

4、redis 最適合的場景

Redis最適合所有資料in-momory的場景,雖然Redis也提供持久化功能,但實際更多的是一個disk-backed的功能,跟傳統意義上的持久化有比較大的差別,那麼可能大家就會有疑問,似乎Redis更像一個加強版的Memcached,那麼何時使用Memcached,何時使用Redis呢?

如果簡單地比較Redis與Memcached的區別,大多數都會得到以下觀點:

  1. Redis不僅僅支援簡單的k/v型別的資料,同時還提供list,set,zset,hash等資料結構的儲存。
  2. Redis支援資料的備份,即master-slave模式的資料備份。
  3. Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用。

(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的釋出/訂閱功能來建立聊天系統!(不,這是真的,你可以去核實)。

Redis提供的所有特性中,我感覺這個是喜歡的人最少的一個,雖然它為使用者提供如果此多功能。

5、redis的一些其他特點

(1)Redis是單程式單執行緒的 redis利用佇列技術將併發訪問變為序列訪問,消除了傳統資料庫序列控制的開銷

(2)讀寫分離模型 透過增加Slave DB的數量,讀的效能可以線性增長。為了避免Master DB的單點故障,叢集一般都會採用兩臺Master DB做雙機熱備,所以整個叢集的讀和寫的可用性都非常高。讀寫分離架構的缺陷在於,不管是Master還是Slave,每個節點都必須儲存完整的資料,如果在資料量很大的情況下,叢集的擴充套件能力還是受限於單個節點的儲存能力,而且對於Write-intensive型別的應用,讀寫分離架構並不適合。

(3)資料分片模型 為了解決讀寫分離模型的缺陷,可以將資料分片模型應用進來。可以將每個節點看成都是獨立的master,然後透過業務實現資料分片。結合上面兩種模型,可以將每個master設計成由一個master和多個slave組成的模型。

(4)Redis的回收策略

  1. volatile-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰
  2. volatile-ttl:從已設定過期時間的資料集(server.db[i].expires)中挑選將要過期的資料淘汰
  3. volatile-random:從已設定過期時間的資料集(server.db[i].expires)中任意選擇資料淘汰
  4. allkeys-lru:從資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
  5. allkeys-random:從資料集(server.db[i].dict)中任意選擇資料淘汰
  6. no-enviction(驅逐):禁止驅逐資料

注意這裡的6種機制,volatile和allkeys規定了是對已設定過期時間的資料集淘汰資料還是從全部資料集淘汰資料,後面的lru、ttl以及random是三種不同的淘汰策略,再加上一種no-enviction永不回收的策略。

使用策略規則:

  1. 如果資料呈現冪律分佈,也就是一部分資料訪問頻率高,一部分資料訪問頻率低,則使用allkeys-lru
  2. 如果資料呈現平等分佈,也就是所有的資料訪問頻率都相同,則使用allkeys-random

6、mySQL裡有2000w資料

redis中只存20w的資料,如何保證redis中的資料都是熱點資料

相關知識:redis 記憶體資料集大小上升到一定大小的時候,就會施行資料淘汰策略。redis提供6種資料淘汰策略見上面一條

7、假如Redis裡面有1億個key

,其中有10w個key是以某個固定的已知的字首開頭的,如果將它們全部找出來?

使用keys指令可以掃出指定模式的key列表。

對方接著追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?

這個時候你要回答redis關鍵的一個特性:redis的單執行緒的。keys指令會導致執行緒阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重複機率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。

8、Redis 常見的效能問題都有哪些?如何解決?

  1. Master寫記憶體快照,save命令排程rdbSave函式,會阻塞主執行緒的工作,當快照比較大時對效能影響是非常大的,會間斷性暫停服務,所以Master最好不要寫記憶體快照。
  2. Master AOF持久化,如果不重寫AOF檔案,這個持久化方式對效能的影響是最小的,但是AOF檔案會不斷增大,AOF檔案過大會影響Master重啟的恢復速度。Master最好不要做任何持久化工作,包括記憶體快照和AOF日誌檔案,特別是不要啟用記憶體快照做持久化,如果資料比較關鍵,某個Slave開啟AOF備份資料,策略為每秒同步一次。
  3. Master呼叫BGREWRITEAOF重寫AOF檔案,AOF在重寫的時候會佔大量的CPU和記憶體資源,導致服務load過高,出現短暫服務暫停現象。
  4. Redis主從複製的效能問題,為了主從複製的速度和連線的穩定性,Slave和Master最好在同一個區域網內

9、Redis有哪些資料結構?

字串String、字典Hash、列表List、集合Set、有序集合SortedSet。

如果你是Redis中高階使用者,還需要加上下面幾種資料結構HyperLogLog、Geo、Pub/Sub。

如果你說還玩過Redis Module,像BloomFilter,RedisSearch,Redis-ML,面試官得眼睛就開始發亮了。

10、使用過Redis分散式鎖麼,它是什麼回事?

先拿setnx來爭搶鎖,搶到之後,再用expire給鎖加一個過期時間防止鎖忘記了釋放。

這時候對方會告訴你說你回答得不錯,然後接著問如果在setnx之後執行expire之前程式意外crash或者要重啟維護了,那會怎麼樣?

這時候你要給予驚訝的反饋:唉,是喔,這個鎖就永遠得不到釋放了。緊接著你需要抓一抓自己得腦袋,故作思考片刻,好像接下來的結果是你主動思考出來的,然後回答:我記得set指令有非常複雜的引數,這個應該是可以同時把setnx和expire合成一條指令來用的!對方這時會顯露笑容,心裡開始默唸:摁,這小子還不錯。

11、使用過Redis做非同步佇列麼,你是怎麼用的?

一般使用list結構作為佇列,rpush生產訊息,lpop消費訊息。當lpop沒有訊息的時候,要適當sleep一會再重試。

如果對方追問可不可以不用sleep呢?list還有個指令叫blpop,在沒有訊息的時候,它會阻塞住直到訊息到來。

如果對方追問能不能生產一次消費多次呢?使用pub/sub主題訂閱者模式,可以實現1:N的訊息佇列。

如果對方追問pub/sub有什麼缺點?在消費者下線的情況下,生產的訊息會丟失,得使用專業的訊息佇列如rabbitmq等。

如果對方追問redis如何實現延時佇列?我估計現在你很想把面試官一棒打死如果你手上有一根棒球棍的話,怎麼問的這麼詳細。但是你很剋制,然後神態自若的回答道:使用sortedset,拿時間戳作為score,訊息內容作為key呼叫zadd來生產訊息,消費者用zrangebyscore指令獲取N秒之前的資料輪詢進行處理。

到這裡,面試官暗地裡已經對你豎起了大拇指。但是他不知道的是此刻你卻豎起了中指,在椅子背後。

12、如果有大量的key需要設定同一時間過期,一般需要注意什麼?

如果大量的key過期時間設定的過於集中,到過期的那個時間點,redis可能會出現短暫的卡頓現象。一般需要在時間上加一個隨機值,使得過期時間分散一些。

13、為什麼Redis需要把所有資料放到記憶體中?

Redis為了達到最快的讀寫速度將資料都讀到記憶體中,並透過非同步的方式將資料寫入磁碟。所以redis具有快速和資料持久化的特徵。如果不將資料放在記憶體中,磁碟I/O速度為嚴重影響redis的效能。在記憶體越來越便宜的今天,redis將會越來越受歡迎。如果設定了最大使用的記憶體,則資料已有記錄數達到記憶體限值後不能繼續插入新值。

14、Redis 持久化機制

bgsave做映象全量持久化,aof做增量持久化。因為bgsave會耗費較長時間,不夠實時,在停機的時候會導致大量丟失資料,所以需要aof來配合使用。在redis例項重啟時,會使用bgsave持久化檔案重新構建記憶體,再使用aof重放近期的操作指令來實現完整恢復重啟之前的狀態。

對方追問那如果突然機器掉電會怎樣?取決於aof日誌sync屬性的配置,如果不要求效能,在每條寫指令時都sync一下磁碟,就不會丟失資料。但是在高效能的要求下每次都sync是不現實的,一般都使用定時sync,比如1s1次,這個時候最多就會丟失1s的資料。

對方追問bgsave的原理是什麼?你給出兩個詞彙就可以了,fork和cow。fork是指redis透過建立子程式來進行bgsave操作,cow指的是copy on write,子程式建立後,父子程式共享資料段,父程式繼續提供讀寫服務,寫髒的頁面資料會逐漸和子程式分離開來。

15、Redis提供了哪幾種持久化方式?

  1. RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存。
  2. AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾。Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大。
  3. 如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式。
  4. 你也可以同時開啟兩種持久化方式, 在這種情況下, 當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整。
  5. 最重要的事情是瞭解RDB和AOF持久化方式的不同,讓我們以RDB持久化方式開始。

16、如何選擇合適的持久化方式?

一般來說, 如果想達到足以媲美PostgreSQL的資料安全性, 你應該同時使用兩種持久化功能。如果你非常關心你的資料, 但仍然可以承受數分鐘以內的資料丟失,那麼你可以只使用RDB持久化。

有很多使用者都只使用AOF持久化,但並不推薦這種方式:因為定時生成RDB快照(snapshot)非常便於進行資料庫備份, 並且 RDB 恢復資料集的速度也要比AOF恢復的速度要快,除此之外, 使用RDB還可以避免之前提到的AOF程式的bug。

17、Pipeline有什麼好處,為什麼要用pipeline?

可以將多次IO往返的時間縮減為一次,前提是pipeline執行的指令之間沒有因果相關性。使用redis-benchmark進行壓測的時候可以發現影響redis的QPS峰值的一個重要因素是pipeline批次指令的數目。

18、Redis的同步機制瞭解麼?

Redis可以使用主從同步,從從同步。第一次同步時,主節點做一次bgsave,並同時將後續修改操作記錄到記憶體buffer,待完成後將rdb檔案全量同步到複製節點,複製節點接受完成後將rdb映象載入到記憶體。載入完成後,再通知主節點將期間修改的操作記錄同步到複製節點進行重放就完成了同步過程。

19、Redis 叢集方案與實現

Redis Sentinal著眼於高可用,在master當機時會自動將slave提升為master,繼續提供服務。

Redis Cluster著眼於擴充套件性,在單個redis記憶體不足時,使用Cluster進行分片儲存。

20、一個Redis例項最多能存放多少的keys?

List、Set、Sorted Set他們最多能存放多少元素?

理論上Redis可以處理多達232的keys,並且在實際中進行了測試,每個例項至少存放了2億5千萬的keys。我們正在測試一些較大的值。

任何list、set、和sorted set都可以放232個元素。

換句話說,Redis的儲存極限是系統中的可用記憶體值。

21、Redis持久化資料和快取怎麼做擴容?

  • 如果Redis被當做快取使用,使用一致性雜湊實現動態擴容縮容。
  • 如果Redis被當做一個持久化儲存使用,必須使用固定的keys-to-nodes對映關係,節點的數量一旦確定不能變化。否則的話(即Redis節點需要動態變化的情況),必須使用可以在執行時進行資料再平衡的一套系統,而當前只有Redis叢集可以做到這樣。

作者:Java筆記  | 來源:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28869493/viewspace-2657079/,如需轉載,請註明出處,否則將追究法律責任。

相關文章