Redis面試題集錦(精選)

Redis面試題集錦(精選)

1.什麼是 Redis?簡述它的優缺點?

Redis的全稱是:Remote Dictionary.Server,本質上是一個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 適合的場景主要侷限在較小數據量的高性能操做和運算上。html

2.Redis 支持的 Java 客戶端都有哪些?官方推薦用哪一個?

Redisson、Jedis、lettuce 等等,官方推薦使用 Redissonjava

3.Redis 與 Memcached 相比有哪些優點?

  • memcached 全部的值均是簡單的字符串,redis 做爲其替代者,支持更爲豐富的數據類型。
  • redis 的速度比 memcached 快不少。
  • redis 能夠持久化其數據。
    Redis 與 Memcached區別

4.Redis 支持哪幾種數據類型?並簡單介紹一下?

String(字符串)、Hash(哈希)、List(列表)、Set(集合)、Zset(sorted set:有序集合)mysql

String(字符串)
String是redis最基本的類型,你能夠理解成與Memcached如出一轍的類型,一個key對應一個value。
String類型是二進制安全的。意思是redis的string能夠包含任何數據。好比jpg圖片或者序列化的對象 。
String類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。git

一個鍵能存512M,可是取出來的時候就要注意了。若是存的value過大,卻用String接收的話,就會拋異常了。咱們就出現過線上問題~github

Hash(哈希)
Redis hash是一個鍵值對集合。
Redis hash是一個string類型的field和value的映射表,hash特別適合用於存儲對象。每一個 hash 能夠存儲 2^32 - 1鍵值對(40多億)。面試

List(列表)
Redis 列表是簡單的字符串列表,按照插入順序排序。你能夠添加一個元素導列表的頭部(左邊)或者尾部(右邊)。
列表最多可存儲 2^32 - 1元素 (4294967295, 每一個列表可存儲40多億)。redis

Set(集合)
Redis的Set是string類型的無序集合。
集合是經過哈希表實現的,因此添加,刪除,查找的複雜度都是O(1)。
sadd 命令:添加一個string元素到,key對應的set集合中,成功返回1,若是元素以及在集合中返回0,key對應的set不存在返回錯誤。算法

Zset
Redis zsetset同樣也是string類型元素的集合,且不容許重複的成員。不一樣的是每一個元素都會關聯一個double類型的分數。redis正是經過分數來爲集合中的成員進行從小到大的排序。
zset的成員是惟一的,但分數(score)卻能夠重複。
zadd命令:添加元素到集合,元素在集合中存在則更新對應score.sql

5.怎麼理解 Redis 事務?相關事務命令有哪些?並介紹一下

事務是一個單獨的隔離操做:事務中的全部命令都會序列化、按順序地執行,事務在執行的過程當中,不會被其餘客戶端發送來的命令請求所打斷。事務是一個原子操做:事務中的命令要麼所有被執行,要麼所有都不執行。數據庫

命令:MULTIEXECDISCARDWATCHUNWATCH.

  • DISCARD
    取消事務,放棄執行事務塊內的全部命令。
  • EXEC
    執行全部事務塊內的命令。
  • MULTI
    標記一個事務塊的開始。
  • UNWATCH
    取消 WATCH 命令對全部 key 的監視。
  • WATCH key [key ...]
    監視一個(或多個) key ,若是在事務執行以前這個(或這些) key 被其餘命令所改動,那麼事務將被打斷。

在傳統的關係式數據庫中,經常用 ACID 性質來檢驗事務功能的可靠性和安全性。在 Redis中,事務老是具備原子性(Atomicity)、一致性(Consistency)和隔離性(Isolation),而且當 Redis 運行在某種特定的持久化模式下時,事務也具備持久性(Durability)。

6.爲何要用 redis 而不用 map/guava 作緩存?

緩存分爲本地緩存和分佈式緩存。以 Java 爲例,使用自帶的map或者 guava實現的是本地緩存,最主要的特色是輕量以及快速,生命週期隨着 jvm 的銷燬而結束,而且在多實例的狀況下,每一個實例都須要各自保存一份緩存,緩存不具備一致性。

使用 redismemcached之類的稱爲分佈式緩存,在多實例的狀況下,各實例共用一份緩存數據,緩存具備一致性。缺點是須要保持 redismemcached服務的高可用,整個程序架構上較爲複雜。

7. redis 設置過時時間

Redis中有個設置時間過時的功能,即對存儲在 redis 數據庫中的值能夠設置一個過時時間。做爲一個緩存數據庫,這是很是實用的。如咱們通常項目中的 token 或者一些登陸信息,尤爲是短信驗證碼都是有時間限制的,按照傳統的數據庫處理方式,通常都是本身判斷過時,這樣無疑會嚴重影響項目性能。

咱們 set key 的時候,均可以給一個 expire time,就是過時時間,經過過時時間咱們能夠指定這個 key 能夠存活的時間。

若是假設你設置了一批 key 只能存活1個小時,那麼接下來1小時後,redis是怎麼對這批key進行刪除的?

按期刪除+惰性刪除

經過名字大概就能猜出這兩個刪除方式的意思了。

按期刪除:redis默認是每隔 100ms 就隨機抽取一些設置了過時時間的key,檢查其是否過時,若是過時就刪除。注意這裏是隨機抽取的。爲何要隨機呢?你想想假如 redis 存了幾十萬個 key ,每隔100ms就遍歷全部的設置過時時間的 key 的話,就會給 CPU 帶來很大的負載!
惰性刪除 :按期刪除可能會致使不少過時 key 到了時間並無被刪除掉。因此就有了惰性刪除。假如你的過時 key,靠按期刪除沒有被刪除掉,還停留在內存裏,除非你的系統去查一下那個 key,纔會被redis給刪除掉。這就是所謂的惰性刪除,也是夠懶的哈!

可是僅僅經過設置過時時間仍是有問題的。咱們想一下:若是按期刪除漏掉了不少過時 key,而後你也沒及時去查,也就沒走惰性刪除,此時會怎麼樣?若是大量過時key堆積在內存裏,致使redis內存塊耗盡了。怎麼解決這個問題呢?

8. 說一說Redis 內存淘汰機制(MySQL裏有2000w數據,Redis中只存20w的數據,如何保證Redis中的數據都是熱點數據?)

redis 配置文件 redis.conf 中有相關注釋,你們能夠自行查閱或者經過這個網址查看:
http://download.redis.io/redis-stable/redis.conf

redis 提供 6種數據淘汰策略:

volatile-lru:從已設置過時時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過時時間的數據集(server.db[i].expires)中挑選將要過時的數據淘汰
volatile-random:從已設置過時時間的數據集(server.db[i].expires)中任意選擇數據淘汰
allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key(這個是最經常使用的).
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-eviction:禁止驅逐數據,也就是說當內存不足以容納新寫入數據時,新寫入操做會報錯。這個應該沒人使用吧!

9. 如何解決 Redis 的併發競爭 Key 問題?

所謂 Redis 的併發競爭 Key 的問題也就是多個系統同時對一個 key 進行操做,可是最後執行的順序和咱們指望的順序不一樣,這樣也就致使告終果的不一樣!

推薦一種方案:分佈式鎖zookeeperredis 均可以實現分佈式鎖)。(若是不存在 Redis 的併發競爭 Key 問題,不要使用分佈式鎖,這樣會影響性能)

基於zookeeper臨時有序節點能夠實現的分佈式鎖。
大體思想爲:每一個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個惟一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只須要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除便可。同時,其能夠避免服務宕機致使的鎖沒法釋放,而產生的死鎖問題。完成業務流程後,刪除對應的子節點釋放鎖。

在實踐中,固然是從以可靠性爲主。因此首推Zookeeper

10.Redis 爲何是單線程的?

官方FAQ表示,由於Redis是基於內存的操做,CPU不是Redis的瓶頸,Redis的瓶頸最有多是機器內存的大小或者網絡帶寬。既然單線程容易實現,並且CPU不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了(畢竟採用多線程會有不少麻煩!)Redis利用隊列技術將併發訪問變爲串行訪問
1)絕大部分請求是純粹的內存操做(很是快速)
2)採用單線程,避免了沒必要要的上下文切換和競爭條件
3)非阻塞IO優勢:
1.速度快,由於數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1)

  1. 支持豐富數據類型,支持string,list,set,sorted set,hash
    3.支持事務,操做都是原子性,所謂的原子性就是對數據的更改要麼所有執行,要麼所有不執行
  2. 豐富的特性:可用於緩存,消息,按key設置過時時間,過時後將會自動刪除如何解決redis的併發競爭key問題

同時有多個子系統去set一個key。這個時候要注意什麼呢? 不推薦使用redis的事務機制。由於咱們的生產環境,基本都是redis集羣環境,作了數據分片操做。你一個事務中有涉及到多個key操做的時候,這多個key不必定都存儲在同一個redis-server上。所以,redis的事務機制,十分雞肋。
(1)若是對這個key操做,不要求順序: 準備一個分佈式鎖,你們去搶鎖,搶到鎖就作set操做便可
(2)若是對這個key操做,要求順序: 分佈式鎖+時間戳。 假設這會系統B先搶到鎖,將key1設置爲{valueB 3:05}。接下來系統A搶到鎖,發現本身的valueA的時間戳早於緩存中的時間戳,那就不作set操做了。以此類推。

(3) 利用隊列,將set方法變成串行訪問也能夠redis遇到高併發,若是保證讀寫key的一致性
對redis的操做都是具備原子性的,是線程安全的操做,你不用考慮併發問題,redis內部已經幫你處理好併發的問題了。

11.說一說Redis 持久化機制?

Redis是一個支持持久化的內存數據庫,經過持久化機制把內存中的數據同步到硬盤文件來保證數據持久化。當Redis重啓後經過把硬盤文件從新加載到內存,就能達到恢復數據的目的。
實現:單首創建fork()一個子進程,將當前父進程的數據庫數據複製到子進程的內存中,而後由子進程寫入到臨時文件中,持久化的過程結束了,再用這個臨時文件替換上次的快照文件,而後子進程退出,內存釋放。

  • RDBRedis默認的持久化方式。按照必定的時間週期策略把內存的數據以快照的形式保存到硬盤的二進制文件。即Snapshot快照存儲,對應產生的數據文件爲dump.rdb,經過配置文件中的save參數來定義快照的週期。( 快照能夠是其所表示的數據的一個副本,也能夠是數據的一個複製品。)
  • AOFRedis會將每個收到的寫命令都經過Write函數追加到文件最後,相似於MySQLbinlog。當Redis重啓是會經過從新執行文件中保存的寫命令來在內存中重建整個數據庫的內容。
    當兩種方式同時開啓時,數據恢復Redis會優先選擇AOF恢復。

12.熱點數據和冷數據是什麼?

熱點數據,緩存纔有價值
對於熱點數據,好比咱們的某IM產品,生日祝福模塊,當天的壽星列表,緩存之後可能讀取數十萬次。再舉個例子,某導航產品,咱們將導航信息,緩存之後可能讀取數百萬次。
對於冷數據而言,大部分數據可能尚未再次訪問到就已經被擠出內存,不只佔用內存,並且價值不大。頻繁修改的數據,看狀況考慮使用緩存
對於上面兩個例子,壽星列表、導航信息都存在一個特色,就是信息修改頻率不高,讀取一般很是高的場景。

數據更新前至少讀取兩次,緩存纔有意義。這個是最基本的策略,若是緩存尚未起做用就失效了,那就沒有太大價值了。
那存不存在,修改頻率很高,可是又不得不考慮緩存的場景呢?有!好比,這個讀取接口對數據庫的壓力很大,可是又是熱點數據,這個時候就須要考慮經過緩存手段,減小數據庫的壓力,好比咱們的某助手產品的,點贊數,收藏數,分享數等是很是典型的熱點數據,可是又不斷變化,此時就須要將數據同步保存到Redis緩存,減小數據庫壓力。

13. 簡單說一說緩存雪崩以及解決辦法?

緩存雪崩咱們能夠簡單的理解爲:因爲原有緩存失效,新緩存未到期間

(例如:咱們設置緩存時採用了相同的過時時間,在同一時刻出現大面積的緩存過時),全部本來應該訪問緩存的請求都去查詢數據庫了,而對數據庫CPU和內存形成巨大壓力,嚴重的會形成數據庫宕機。從而造成一系列連鎖反應,形成整個系統崩潰。

解決辦法
大多數系統設計者考慮用加鎖( 最多的解決方案)或者隊列的方式保證來保證不會有大量的線程對數據庫一次性進行讀寫,從而避免失效時大量的併發請求落到底層存儲系統上。還有一個簡單方案就時講緩存失效時間分散開。

14. 簡單說一說緩存穿透以及解決辦法?

緩存穿透是指用戶查詢數據,在數據庫沒有,天然在緩存中也不會有。這樣就致使用戶查詢的時候,在緩存中找不到,每次都要去數據庫再查詢一遍,而後返回空(至關於進行了兩次無用的查詢)。這樣請求就繞過緩存直接查數據庫,這也是常常提的緩存命中率問題。

解決辦法:
最多見的則是採用布隆過濾器,將全部可能存在的數據哈希到一個足夠大的bitmap中,一個必定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。
另外也有一個更爲簡單粗暴的方法,若是一個查詢返回的數據爲空(無論是數據不存在,仍是系統故障),咱們仍然把這個空結果進行緩存,但它的過時時間會很短,最長不超過五分鐘。經過這個直接設置的默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫,這種辦法最簡單粗暴。
5TB的硬盤上放滿了數據,請寫一個算法將這些數據進行排重。若是這些數據是一些32bit大小的數據該如何解決?若是是64bit的呢?
對於空間的利用到達了一種極致,那就是Bitmap和布隆過濾器(Bloom Filter)。
Bitmap: 典型的就是哈希表
缺點是,Bitmap對於每一個元素只能記錄1bit信息,若是還想完成額外的功能,恐怕只能靠犧牲更多的空間、時間來完成了。

布隆過濾器(推薦)
就是引入了k(k>1)k(k>1)個相互獨立的哈希函數,保證在給定的空間、誤判率下,完成元素判重的過程。
它的優勢是空間效率和查詢時間都遠遠超過通常的算法,缺點是有必定的誤識別率和刪除困難。
Bloom-Filter算法的核心思想就是利用多個不一樣的Hash函數來解決「衝突」。
Hash存在一個衝突(碰撞)的問題,用同一個Hash獲得的兩個URL的值有可能相同。爲了減小衝突,咱們能夠多引入幾個Hash,若是經過其中的一個Hash值咱們得出某元素不在集合中,那麼該元素確定不在集合中。只有在全部的Hash函數告訴咱們該元素在集合中時,才能肯定該元素存在於集合中。這即是Bloom-Filter的基本思想。
Bloom-Filter通常用於在大數據量的集合中斷定某元素是否存在。

15. 簡單說一說緩存預熱?

除了緩存服務器自帶的緩存失效策略以外(Redis默認的有6中策略可供選擇),咱們還能夠根據具體的業務需求進行自定義的緩存淘汰,常見的策略有兩種:
(1)定時去清理過時的緩存;
(2)當有用戶請求過來時,再判斷這個請求所用到的緩存是否過時,過時的話就去底層系統獲得新數據並更新緩存。
二者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較複雜!具體用哪一種方案,你們能夠根據本身的應用場景來權衡。

16. 簡單說一說緩存降級?

當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然須要保證服務仍是可用的,即便是有損服務。系統能夠根據一些關鍵數據進行自動降級,也能夠配置開關實現人工降級。
降級的最終目的是保證核心服務可用,即便是有損的。並且有些服務是沒法降級的(如加入購物車、結算)。
以參考日誌級別設置預案:
(1)通常:好比有些服務偶爾由於網絡抖動或者服務正在上線而超時,能夠自動降級;
(2)警告:有些服務在一段時間內成功率有波動(如在95~100%之間),能夠自動降級或人工降級,併發送告警;
(3)錯誤:好比可用率低於90%,或者數據庫鏈接池被打爆了,或者訪問量忽然猛增到系統能承受的最大閥值,此時能夠根據狀況自動降級或者人工降級;
(4)嚴重錯誤:好比由於特殊緣由數據錯誤了,此時須要緊急人工降級。

服務降級的目的,是爲了防止Redis服務故障,致使數據庫跟着一塊兒發生雪崩問題。所以,對於不重要的緩存數據,能夠採起服務降級策略,例如一個比較常見的作法就是,Redis出現問題,不去數據庫查詢,而是直接返回默認值給用戶。

17.Redis 常見性能問題和解決方案?

(1) Master 最好不要作任何持久化工做,如 RDB 內存快照和 AOF 日誌文件

(2) 若是數據比較重要,某個 Slave 開啓 AOF 備份數據,策略設置爲每秒同步一次

(3) 爲了主從複製的速度和鏈接的穩定性, Master 和 Slave 最好在同一個局域網內

(4) 儘可能避免在壓力很大的主庫上增長從庫

(5) 主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即: Master <- Slave1 <- Slave2 <- Slave3…

18.Redis如何實現分佈式鎖?

1.根據lockKey區進行setnx(set not exist,若是key值爲空,則正常設置,返回1,不然不會進行設置並返回0)操做,若是設置成功,表示已經得到鎖,不然並無獲取鎖。

2.若是沒有得到鎖,去Redis上拿到該key對應的值,在該key上咱們存儲一個時間戳(用毫秒錶示,t1),爲了不死鎖以及其餘客戶端佔用該鎖超過必定時間(5秒),使用該客戶端當前時間戳,與存儲的時間戳做比較。

3.若是沒有超過該key的使用時限,返回false,表示其餘人正在佔用該key,不能強制使用;若是已經超過期限,那咱們就能夠進行解鎖,使用咱們的時間戳來代替該字段的值。

4.可是若是在setnx失敗後,get該值卻沒法拿到該字段時,說明操做以前該鎖已經被釋放,這個時候,最好的辦法就是從新執行一遍setnx方法來獲取其值以得到該鎖。
Redis分佈式鎖流程圖

詳細內容能夠查看:Redis與Zookeeper實現分佈式鎖的區別(http://www.javashuo.com/article/p-qvsstlpa-gq.html

19.如何保證緩存與數據庫雙寫時的數據一致性?

你只要用緩存,就可能會涉及到緩存與數據庫雙存儲雙寫,你只要是雙寫,就必定會有數據一致性的問題,那麼你如何解決一致性問題?

通常來講,就是若是你的系統不是嚴格要求緩存+數據庫必須一致性的話,緩存能夠稍微的跟數據庫偶爾有不一致的狀況,最好不要作這個方案,讀請求和寫請求串行化,串到一個內存隊列裏去,這樣就能夠保證必定不會出現不一致的狀況

串行化以後,就會致使系統的吞吐量會大幅度的下降,用比正常狀況下多幾倍的機器去支撐線上的一個請求。

還有一種方式就是可能會暫時產生不一致的狀況,可是發生的概率特別小,就是先更新數據庫,而後再刪除緩存。

這種狀況不存在併發問題麼?

不是的。假設這會有兩個請求,一個請求A作查詢操做,一個請求B作更新操做,那麼會有以下情形產生

(1)緩存恰好失效
(2)請求A查詢數據庫,得一箇舊值
(3)請求B將新值寫入數據庫
(4)請求B刪除緩存
(5)請求A將查到的舊值寫入緩存

ok,若是發生上述狀況,確實是會發生髒數據。

然而,發生這種狀況的機率又有多少呢?

發生上述狀況有一個先天性條件,就是步驟(3)的寫數據庫操做比步驟(2)的讀數據庫操做耗時更短,纔有可能使得步驟(4)先於步驟(5)。但是,你們想一想,數據庫的讀操做的速度遠快於寫操做的(否則作讀寫分離幹嗎,作讀寫分離的意義就是由於讀操做比較快,耗資源少),所以步驟(3)耗時比步驟(2)更短,這一情形很難出現。

如何解決上述併發問題?

首先,給緩存設有效時間是一種方案。其次,採用異步延時刪除策略,保證讀請求完成之後,再進行刪除操做。

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

Redis Sentinal着眼於高可用,在master宕機時會自動將slave提高爲master,繼續提供服務。
Redis Cluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。

Slot:插槽,能夠存儲兩個數值的一個變量這個變量的取值範圍是:0-16383。
Cluster:集羣管理者,使集羣對外暴漏的是一個總體。
redis cluster:採用虛擬分區的方式,將整個集羣當作一個總體,而後分紅16384個槽位。
而後再將16484個槽位分別分配給集羣的各個節點,而後各個節點各自負責一部分槽位。

Redis集羣

原理:
節點1負責 0-5000之間的槽位,節點2負責5001-10000之間的槽位,節點3負責10001-16383之間的槽位。
k-v鍵值對數據只會和槽位相關,與物理機器無關。經過crc16算法計算出 k對應的整數值(有點相似hash),而後對算出的整數值%16384取模,計算出k-v對應在哪一個槽位上,而後再根據槽位與機器節點的映射關係,存儲到相應的節點上去。取的時候,也是相應的過 程因此整個集羣協同一致對外,給client看到的視圖就是完整的數據集。

21. 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服務器了。

22.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是否被從新設置成功。

23.redis 最適合的場景有哪些?  

Redis最適合全部數據in-momory的場景,雖然Redis也提供持久化功能,但實際更多的是一個disk-backed的功能,跟傳統意義上的持久化有比較大的差異,那麼可能你們就會有疑問,彷佛Redis更像一個增強版的Memcached,那麼什麼時候使用Memcached,什麼時候使用Redis呢?

若是簡單地比較Redis與Memcached的區別,大多數都會獲得如下觀點:

  • Redis不只僅支持簡單的k/v類型的數據,同時還提供listsetzsethash等數據結構的存儲。
  • Redis支持數據的備份,即master-slave模式的數據備份。
  • 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提供的全部特性中,我感受這個是喜歡的人最少的一個,雖然它爲用戶提供若是此多功能。

24. 說說Redis哈希槽的概念?

Redis集羣沒有使用一致性hash,而是引入了哈希槽的概念,Redis集羣有16384個哈希槽,每一個key經過CRC16校驗後對16384取模來決定放置哪一個槽,集羣的每一個節點負責一部分hash槽。

25. Redis集羣方案什麼狀況下會致使整個集羣不可用?

有A,B,C三個節點的集羣,在沒有複製模型的狀況下,若是節點B失敗了,那麼整個集羣就會覺得缺乏5501-11000這個範圍的槽而不可用。

關於Redis集羣架構更加詳細的內容,能夠看看大佬的文章:
那些年用過的Redis集羣架構(含面試解析):(http://www.javashuo.com/article/p-fcuuvfbr-kq.html)

推薦

Spring面試題集錦(精選)

SpringMVC面試題集錦(精選)

Spring全家桶註解一覽(精選)

ProcessOn是一個在線做圖工具的聚合平臺~

文末

歡迎關注我的微信公衆號:Coder編程
歡迎關注Coder編程公衆號,主要分享數據結構與算法、Java相關知識體系、框架知識及原理、Spring全家桶、微服務項目實戰、DevOps實踐之路、每日一篇互聯網大廠面試或筆試題以及PMP項目管理知識等。更多精彩內容正在路上~

文章收錄至
Github: https://github.com/CoderMerlin/coder-programming
Gitee: https://gitee.com/573059382/coder-programming
歡迎關注並star~
微信公衆號

相關文章
相關標籤/搜索