redis詳解筆記

常見問題:

一、爲何使用redis面試

(一)性能redis

咱們在碰到須要執行耗時特別久,且結果不頻繁變更的SQL,就特別適合將運行結果放入緩存。這樣,後面的請求就去緩存中讀取,使得請求可以迅速響應。數據庫

(二)併發後端

在大併發的狀況下,全部的請求直接訪問數據庫,數據庫會出現鏈接異常。這個時候,就須要使用redis作一個緩衝操做,讓請求先訪問到redis,而不是直接訪問數據庫。緩存

2.使用redis有什麼缺點服務器

(一)緩存和數據庫雙寫一致性問題cookie

(二)緩存雪崩問題網絡

(三)緩存擊穿問題session

(四)緩存的併發競爭問題數據結構

三、單線程的redis爲何這麼快

(一)純內存操做

(二)單線程操做,避免了頻繁的上下文切換

(三)採用了非阻塞I/O多路複用機制

參照上圖,簡單來講,就是。咱們的redis-client在操做的時候,會產生具備不一樣事件類型的socket。在服務端,有一段I/0多路複用程序,將其置入隊列之中。而後,文件事件分派器,依次去隊列中取,轉發到不一樣的事件處理器中。

四、redis的數據類型,以及每種數據類型的使用場景

回答:一共五種

(一)String

這個其實沒啥好說的,最常規的set/get操做,value能夠是String也能夠是數字。通常作一些複雜的計數功能的緩存。

(二)hash

這裏value存放的是結構化的對象,比較方便的就是操做其中的某個字段。博主在作單點登陸的時候,就是用這種數據結構存儲用戶信息,以cookieId做爲key,設置30分鐘爲緩存過時時間,能很好的模擬出相似session的效果。

(三)list

使用List的數據結構,能夠作簡單的消息隊列的功能。另外還有一個就是,能夠利用lrange命令,作基於redis的分頁功能,性能極佳,用戶體驗好。本人還用一個場景,很合適---取行情信息。就也是個生產者和消費者的場景。LIST能夠很好的完成排隊,先進先出的原則。

(四)set

由於set堆放的是一堆不重複值的集合。因此能夠作全局去重的功能。爲何不用JVM自帶的Set進行去重?由於咱們的系統通常都是集羣部署,使用JVM自帶的Set,比較麻煩,難道爲了一個作一個全局去重,再起一個公共服務,太麻煩了。

另外,就是利用交集、並集、差集等操做,能夠計算共同喜愛,所有的喜愛,本身獨有的喜愛等功能。

(五)sorted set

sorted set多了一個權重參數score,集合中的元素可以按score進行排列。能夠作排行榜應用,取TOP N操做。

五、redis的過時策略以及內存淘汰機制

redis採用的是按期刪除+惰性刪除策略。

爲何不用定時刪除策略?

定時刪除,用一個定時器來負責監視key,過時則自動刪除。雖然內存及時釋放,可是十分消耗CPU資源。在大併發請求下,CPU要將時間應用在處理請求,而不是刪除key,所以沒有采用這一策略.

按期刪除+惰性刪除是如何工做的呢?

按期刪除,redis默認每一個100ms檢查,是否有過時的key,有過時key則刪除。須要說明的是,redis不是每一個100ms將全部的key檢查一次,而是隨機抽取進行檢查(若是每隔100ms,所有key進行檢查,redis豈不是卡死)。所以,若是隻採用按期刪除策略,會致使不少key到時間沒有刪除。

因而,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key若是設置了過時時間那麼是否過時了?若是過時了此時就會刪除。

採用按期刪除+惰性刪除就沒其餘問題了麼?

不是的,若是按期刪除沒刪除key。而後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會愈來愈高。那麼就應該採用內存淘汰機制。

在redis.conf中有一行配置

# maxmemory-policy volatile-lru

該配置就是配內存淘汰策略的(什麼,你沒配過?好好檢討一下本身)

1)noeviction:當內存不足以容納新寫入數據時,新寫入操做會報錯。應該沒人用吧。

2)allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。推薦使用,目前項目在用這種。

3)allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。應該也沒人用吧,你不刪最少使用Key,去隨機刪。

4)volatile-lru:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,移除最近最少使用的key。這種狀況通常是把redis既當緩存,又作持久化存儲的時候才用。不推薦

5)volatile-random:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,隨機移除某個key。依然不推薦

6)volatile-ttl:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,有更早過時時間的key優先移除。不推薦

ps:若是沒有設置 expire 的key, 不知足先決條件(prerequisites); 那麼 volatile-lru, volatile-random 和 volatile-ttl 策略的行爲, 和 noeviction(不刪除) 基本上一致。

六、redis和數據庫雙寫一致性問題

分析:一致性問題是分佈式常見問題,還能夠再分爲最終一致性和強一致性。數據庫和緩存雙寫,就必然會存在不一致的問題。答這個問題,先明白一個前提。就是若是對數據有強一致性要求,不能放緩存。咱們所作的一切,只能保證最終一致性。另外,咱們所作的方案其實從根本上來講,只能說下降不一致發生的機率,沒法徹底避免。所以,有強一致性要求的數據,不能放緩存。

首先,採起正確更新策略,先更新數據庫,再刪緩存。其次,由於可能存在刪除緩存失敗的問題,提供一個補償措施便可,例如利用消息隊列。

七、如何應對緩存穿透和緩存雪崩問題

分析:這兩個問題,說句實在話,通常中小型傳統軟件企業,很難碰到這個問題。若是有大併發的項目,流量有幾百萬左右。這兩個問題必定要深入考慮。

回答:以下所示

緩存穿透,即黑客故意去請求緩存中不存在的數據,致使全部的請求都懟到數據庫上,從而數據庫鏈接異常。

解決方案:

(一)利用互斥鎖,緩存失效的時候,先去得到鎖,獲得鎖了,再去請求數據庫。沒獲得鎖,則休眠一段時間重試

(二)採用異步更新策略,不管key是否取到值,都直接返回。value值中維護一個緩存失效時間,緩存若是過時,異步起一個線程去讀數據庫,更新緩存。須要作緩存預熱(項目啓動前,先加載緩存)操做。

(三)提供一個能迅速判斷請求是否有效的攔截機制,好比,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。若是不合法,則直接返回。

緩存雪崩,即緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而致使數據庫鏈接異常。

解決方案:

(一)給緩存的失效時間,加上一個隨機值,避免集體失效。

(二)使用互斥鎖,可是該方案吞吐量明顯降低了。

(三)雙緩存。咱們有兩個緩存,緩存A和緩存B。緩存A的失效時間爲20分鐘,緩存B不設失效時間。本身作緩存預熱操做。而後細分如下幾個小點

I 從緩存A讀數據庫,有則直接返回

II A沒有數據,直接從B讀數據,直接返回,而且異步啓動一個更新線程。

III 更新線程同時更新緩存A和緩存B。

八、如何解決redis的併發競爭key問題

分析:這個問題大體就是,同時有多個子系統去set一個key。這個時候要注意什麼呢?你們思考過麼。須要說明一下,博主提早百度了一下,發現答案基本都是推薦用redis事務機制。博主不推薦使用redis的事務機制。由於咱們的生產環境,基本都是redis集羣環境,作了數據分片操做。你一個事務中有涉及到多個key操做的時候,這多個key不必定都存儲在同一個redis-server上。所以,redis的事務機制,十分雞肋。

回答:以下所示

(1)若是對這個key操做,不要求順序

這種狀況下,準備一個分佈式鎖,你們去搶鎖,搶到鎖就作set操做便可,比較簡單。

(2)若是對這個key操做,要求順序

假設有一個key1,系統A須要將key1設置爲valueA,系統B須要將key1設置爲valueB,系統C須要將key1設置爲valueC.

指望按照key1的value值按照 valueA–>valueB–>valueC的順序變化。這種時候咱們在數據寫入數據庫的時候,須要保存一個時間戳。假設時間戳以下

系統A key 1 {valueA 3:00}

系統B key 1 {valueB 3:05}

系統C key 1 {valueC 3:10}

那麼,假設這會系統B先搶到鎖,將key1設置爲{valueB 3:05}。接下來系統A搶到鎖,發現本身的valueA的時間戳早於緩存中的時間戳,那就不作set操做了。以此類推。

其餘方法,好比利用隊列,將set方法變成串行訪問也能夠。總之,靈活變通。

9.Reids的特色

Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫通通加載在內存當中進行操做,按期經過異步操做把數據庫數據flush到硬盤上進行保存。由於是純內存操做,Redis的性能很是出色,每秒能夠處理超過 10萬次讀寫操做,是已知性能最快的Key-Value DB。

Redis的出色之處不只僅是性能,Redis最大的魅力是支持保存多種數據結構,此外單個value的最大限制是1GB,不像 memcached只能保存1MB的數據,所以Redis能夠用來實現不少有用的功能,比方說用他的List來作FIFO雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的Set能夠作高性能的tag系統等等。另外Redis也能夠對存入的Key-Value設置expire時間,所以也能夠被看成一 個功能增強版的memcached來用。

Redis的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上。

10.使用redis有哪些好處?

(1) 速度快,由於數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1)

(2) 支持豐富數據類型,支持string,list,set,sorted set,hash

(3) 支持事務,操做都是原子性,所謂的原子性就是對數據的更改要麼所有執行,要麼所有不執行

(4) 豐富的特性:可用於緩存,消息,按key設置過時時間,過時後將會自動刪除

11.redis相比memcached有哪些優點?

(1) memcached全部的值均是簡單的字符串,redis做爲其替代者,支持更爲豐富的數據類型

(2) redis的速度比memcached快不少 (3) redis能夠持久化其數據

12.Memcache與Redis的區別都有哪些?

1)、存儲方式 Memecache把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小。 Redis有部份存在硬盤上,這樣能保證數據的持久性。

2)、數據支持類型 Memcache對數據類型支持相對簡單。 Redis有複雜的數據類型。

3)、使用底層模型不一樣 它們之間底層實現方式 以及與客戶端之間通訊的應用協議不同。 Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。

13.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最好在同一個局域網內

14. mySQL裏有2000w數據,redis中只存20w的數據,如何保證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(驅逐):禁止驅逐數據

15.redis事物的瞭解CAS(check-and-set 操做實現樂觀鎖 )?

和衆多其它數據庫同樣,Redis做爲NoSQL數據庫也一樣提供了事務機制。在Redis中,MULTI/EXEC/DISCARD/WATCH這四個命令是咱們實現事務的基石。相信對有關係型數據庫開發經驗的開發者而言這一律念並不陌生,即使如此,咱們仍是會簡要的列出

Redis中

事務的實現特徵:

1). 在事務中的全部命令都將會被串行化的順序執行,事務執行期間,Redis不會再爲其它客戶端的請求提供任何服務,從而保證了事物中的全部命令被原子的執行。

2). 和關係型數據庫中的事務相比,在Redis事務中若是有某一條命令執行失敗,其後的命令仍然會被繼續執行。

3). 咱們能夠經過MULTI命令開啓一個事務,有關係型數據庫開發經驗的人能夠將其理解爲"BEGIN TRANSACTION"語句。在該語句以後執行的命令都將被視爲事務以內的操做,最後咱們能夠經過執行EXEC/DISCARD命令來提交/回滾該事務內的全部操做。這兩

個Redis命令可被視爲等同於關係型數據庫中的COMMIT/ROLLBACK語句。

4). 在事務開啓以前,若是客戶端與服務器之間出現通信故障並致使網絡斷開,其後全部待執行的語句都將不會被服務器執行。然而若是網絡中斷事件是發生在客戶端執行EXEC命令以後,那麼該事務中的全部命令都會被服務器執行。

5). 當使用Append-Only模式時,Redis會經過調用系統函數write將該事務內的全部寫操做在本次調用中所有寫入磁盤。然而若是在寫入的過程當中出現系統崩潰,如電源故障致使的宕機,那麼此時也許只有部分數據被寫入到磁盤,而另一部分數據卻已經丟失。

Redis服務器會在從新啓動時執行一系列必要的一致性檢測,一旦發現相似問題,就會當即退出並給出相應的錯誤提示。此時,咱們就要充分利用Redis工具包中提供的redis-check-aof工具,該工具能夠幫助咱們定位到數據不一致的錯誤,並將已經寫入的部

分數據進行回滾。修復以後咱們就能夠再次從新啓動Redis服務器了。

16.WATCH命令和基於CAS的樂觀鎖:

在Redis的事務中,WATCH命令可用於提供CAS(check-and-set)功能。假設咱們經過WATCH命令在事務執行以前監控了多個Keys,假若在WATCH以後有任何Key的值發生了變化,EXEC命令執行的事務都將被放棄,同時返回Null multi-bulk應答以通知調用者事務

執行失敗。例如,咱們再次假設Redis中並未提供incr命令來完成鍵值的原子性遞增,若是要實現該功能,咱們只能自行編寫相應的代碼。其僞碼以下:

val = GET mykey

val = val + 1

SET mykey $val

以上代碼只有在單鏈接的狀況下才能夠保證執行結果是正確的,由於若是在同一時刻有多個客戶端在同時執行該段代碼,那麼就會出現多線程程序中常常出現的一種錯誤場景--競態爭用(race condition)。好比,客戶端A和B都在同一時刻讀取了mykey的原有值,假設該值爲10,此後兩個客戶端又均將該值加一後set回Redis服務器,這樣就會致使mykey的結果爲11,而不是咱們認爲的12。爲了解決相似的問題,咱們須要藉助WATCH命令的幫助,見以下代碼:

WATCH mykey

val = GET mykey

val = val + 1

MULTI

SET mykey $val

EXEC

和此前代碼不一樣的是,新代碼在獲取mykey的值以前先經過WATCH命令監控了該鍵,此後又將set命令包圍在事務中,這樣就能夠有效的保證每一個鏈接在執行EXEC以前,若是當前鏈接獲取的mykey的值被其它鏈接的客戶端修改,那麼當前鏈接的EXEC命令將執行失敗。這樣調用者在判斷返回值後就能夠獲悉val是否被從新設置成功。

17.redis持久化的幾種方式

一、快照(snapshots)

缺省狀況狀況下,Redis把數據快照存放在磁盤上的二進制文件中,文件名爲dump.rdb。你能夠配置Redis的持久化策略,例如數據集中每N秒鐘有超過M次更新,就將數據寫入磁盤;或者你能夠手工調用命令SAVE或BGSAVE。

工做原理

. Redis forks.

. 子進程開始將數據寫到臨時RDB文件中。

. 當子進程完成寫RDB文件,用新文件替換老文件。

. 這種方式可使Redis使用copy-on-write技術。

二、AOF

快照模式並不十分健壯,當系統中止,或者無心中Redis被kill掉,最後寫入Redis的數據就會丟失。這對某些應用也許不是大問題,但對於要求高可靠性的應用來講,

Redis就不是一個合適的選擇。

Append-only文件模式是另外一種選擇。

你能夠在配置文件中打開AOF模式

三、虛擬內存方式

當你的key很小而value很大時,使用VM的效果會比較好.由於這樣節約的內存比較大.

當你的key不小時,能夠考慮使用一些很是方法將很大的key變成很大的value,好比你能夠考慮將key,value組合成一個新的value.

vm-max-threads這個參數,能夠設置訪問swap文件的線程數,設置最好不要超過機器的核數,若是設置爲0,那麼全部對swap文件的操做都是串行的.可能會形成比較長時間的延遲,可是對數據完整性有很好的保證.

本身測試的時候發現用虛擬內存性能也不錯。若是數據量很大,能夠考慮分佈式或者其餘數據庫

18.redis的緩存失效策略和主鍵失效機制

做爲緩存系統都要按期清理無效數據,就須要一個主鍵失效和淘汰策略.

在Redis當中,有生存期的key被稱爲volatile。在建立緩存時,要爲給定的key設置生存期,當key過時的時候(生存期爲0),它可能會被刪除。

一、影響生存時間的一些操做

生存時間能夠經過使用 DEL 命令來刪除整個 key 來移除,或者被 SET 和 GETSET 命令覆蓋原來的數據,也就是說,修改key對應的value和使用另外相同的key和value來覆蓋之後,當前數據的生存時間不一樣。

好比說,對一個 key 執行INCR命令,對一個列表進行LPUSH命令,或者對一個哈希表執行HSET命令,這類操做都不會修改 key 自己的生存時間。另外一方面,若是使用RENAME對一個 key 進行更名,那麼更名後的 key的生存時間和更名前同樣。

RENAME命令的另外一種多是,嘗試將一個帶生存時間的 key 更名成另外一個帶生存時間的 another_key ,這時舊的 another_key (以及它的生存時間)會被刪除,而後舊的 key 會更名爲 another_key ,所以,新的 another_key 的生存時間也和本來的 key 同樣。使用PERSIST命令能夠在不刪除 key 的狀況下,移除 key 的生存時間,讓 key 從新成爲一個persistent key 。

二、如何更新生存時間

能夠對一個已經帶有生存時間的 key 執行EXPIRE命令,新指定的生存時間會取代舊的生存時間。過時時間的精度已經被控制在1ms以內,主鍵失效的時間複雜度是O(1),

EXPIRE和TTL命令搭配使用,TTL能夠查看key的當前生存時間。設置成功返回 1;當 key 不存在或者不能爲 key 設置生存時間時,返回 0 。

最大緩存配置

在 redis 中,容許用戶設置最大使用內存大小

server.maxmemory

默認爲0,沒有指定最大緩存,若是有新的數據添加,超過最大內存,則會使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(驅逐):禁止驅逐數據

注意這裏的6種機制,volatile和allkeys規定了是對已設置過時時間的數據集淘汰數據仍是從所有數據集淘汰數據,後面的lru、ttl以及random是三種不一樣的淘汰策略,再加上一種no-enviction永不回收的策略。

使用策略規則:

一、若是數據呈現冪律分佈,也就是一部分數據訪問頻率高,一部分數據訪問頻率低,則使用allkeys-lru

二、若是數據呈現平等分佈,也就是全部的數據訪問頻率都相同,則使用allkeys-random

三種數據淘汰策略:

ttl和random比較容易理解,實現也會比較簡單。主要是Lru最近最少使用淘汰策略,設計上會對key 按失效時間排序,而後取最早失效的key進行淘汰

19.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提供的全部特性中,我感受這個是喜歡的人最少的一個,雖然它爲用戶提供若是此多功能。

20.Reids的特色

Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫通通加載在內存當中進行操做,按期經過異步操做把數據庫數據flush到硬盤上進行保存。由於是純內存操做,Redis的性能很是出色,每秒能夠處理超過 10萬次讀寫操做,是已知性能最快的Key-Value DB。

Redis的出色之處不只僅是性能,Redis最大的魅力是支持保存多種數據結構,此外單個value的最大限制是1GB,不像 memcached只能保存1MB的數據,所以Redis能夠用來實現不少有用的功能,比方說用他的List來作FIFO雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的Set能夠作高性能的tag系統等等。另外Redis也能夠對存入的Key-Value設置expire時間,所以也能夠被看成一 個功能增強版的memcached來用。

Redis的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上。

21.讀寫分離模型

經過增長Slave DB的數量,讀的性能能夠線性增加。爲了不Master DB的單點故障,集羣通常都會採用兩臺Master DB作雙機熱備,因此整個集羣的讀和寫的可用性都很是高。

讀寫分離架構的缺陷在於,無論是Master仍是Slave,每一個節點都必須保存完整的數據,若是在數據量很大的狀況下,集羣的擴展能力仍是受限於單個節點的存儲能力,並且對於Write-intensive類型的應用,讀寫分離架構並不適合。

22.數據分片模型

爲了解決讀寫分離模型的缺陷,能夠將數據分片模型應用進來。

能夠將每一個節點當作都是獨立的master,而後經過業務實現數據分片。

結合上面兩種模型,能夠將每一個master設計成由一個master和多個slave組成的模型。

23.使用過Redis分佈式鎖麼,它是什麼回事?

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

24.若是在setnx以後執行expire以前進程意外crash或者要重啓維護了,那會怎麼樣?

25.若是這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?

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

26.使用過Redis作異步隊列麼,你是怎麼用的?

通常使用list結構做爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。

若是對方追問可不能夠不用sleep呢?list還有個指令叫blpop,在沒有消息的時候,它會阻塞住直到消息到來。

若是對方追問能不能生產一次消費屢次呢?使用pub/sub主題訂閱者模式,能夠實現1:N的消息隊列。

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

若是對方追問redis如何實現延時隊列?我估計如今你很想把面試官一棒打死若是你手上有一根棒球棍的話,怎麼問的這麼詳細。可是你很剋制,而後神態自若的回答道:使用sortedset,拿時間戳做爲score,消息內容做爲key調用zadd來生產消息,消費者用zrangebyscore指令獲取N秒以前的數據輪詢進行處理。

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

27.若是有大量的key須要設置同一時間過時,通常須要注意什麼?

若是大量的key過時時間設置的過於集中,到過時的那個時間點,redis可能會出現短暫的卡頓現象。通常須要在時間上加一個隨機值,使得過時時間分散一些。

28.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,子進程建立後,父子進程共享數據段,父進程繼續提供讀寫服務,寫髒的頁面數據會逐漸和子進程分離開來。

29.Pipeline有什麼好處,爲何要用pipeline?

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

**附: 可是注意,若是使用`Pipeline`。當節點個數擴充後,會致使長鏈接數目成倍數上漲。**

30.Redis的同步機制瞭解麼?

Redis可使用主從同步,從從同步。第一次同步時,主節點作一次bgsave,並同時將後續修改操做記錄到內存buffer,待完成後將rdb文件全量同步到複製節點,複製節點接受完成後將rdb鏡像加載到內存。加載完成後,再通知主節點將期間修改的操做記錄同步到複製節點進行重放就完成了同步過程。

31.是否使用過Redis集羣,集羣的原理是什麼?

Redis Sentinal着眼於高可用,在master宕機時會自動將slave提高爲master,繼續提供服務。

Redis Cluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。

相關文章
相關標籤/搜索