Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫通通加載在內存當中進行操做,按期經過異步操做把數據庫數據flush到硬盤上進行保存。Redis最大的魅力是支持保存多種數據結構面試
1.爲何redis須要把全部數據放到內存中?redis
Redis爲了達到最快的讀寫速度將數據都讀到內存中,並經過異步的方式將數據寫入磁盤。因此redis具備快速和數據持久化的特徵。若是設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值。數據庫
2. 使用Redis有哪些好處?緩存
速度快、支持多種類型、支持事務、支持設置過時時間;安全
3.redis相比memcached有哪些優點?數據結構
redis能夠存儲多種類型,而memcached只能存字符串;併發
redis的速度要比memcached快不少;dom
redis支持持久化存儲;異步
4. Memcache與Redis的區別都有哪些?分佈式
1)、存儲方式
Memecache把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小。
Redis有部份存在硬盤上,這樣能保證數據的持久性。
2)、數據支持類型
Memcache對數據類型支持相對簡單。
Redis有複雜的數據類型。
3)、使用底層模型不一樣
它們之間底層實現方式 以及與客戶端之間通訊的應用協議不同。
Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。
4)、value大小
redis最大能夠達到1GB,而memcache只有1MB
5. redis常見性能問題和解決方案:
Master最好不要作任何持久化工做,如RDB內存快照和AOF日誌文件
若是數據比較重要,某個Slave開啓AOF備份數據,策略設置爲每秒同步一次
爲了主從複製的速度和鏈接的穩定性,Master和Slave最好在同一個局域網內
儘可能避免在壓力很大的主庫上增長從庫
主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即:Master <- Slave1 <- Slave2 <- Slave3...
這樣的結構方便解決單點故障問題,實現Slave對Master的替換。若是Master掛了,能夠馬上啓用Slave1作Master,其餘不變。
6. MySQL裏有2000w數據,redis中只存20w的數據,如何保證redis中的數據都是熱點數據
相關知識:redis 內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略。
redis 提供6種數據淘汰策略,上文已經列出。
7.redis的存儲分類
redis的存儲分爲內存存儲、磁盤存儲和log文件三部分,配置文件中有三個參數對其進行配置。
redis能夠作優先級隊列的設置;
redis是一個key-value存儲系統。
Redis支持主從同步。
8.Redis有哪些數據結構?
(1)字符串String,常規計數:微博數,粉絲數等。命令:get / set / del / expire
(2)字典Hash,Redis的散列能夠存儲多個鍵值對之間的映射。和字符串同樣,散列存儲的值既能夠是字符串又能夠是數字值,而且用戶一樣能夠對散列存儲的數字執行自增操做或者是自減操做。命令:hget / hset / hdel / hgetall
(3)列表List,存儲某個key的list;使用場景:微博 TimeLine、消息隊列
rpush users zhangsan(將給定值推送到列表右端),
lpush users lisi(將給定值推送到列表左端)
rpop users(獲取給定值最右端一個值,調用後會從users的key中刪除該值),
lpop users(獲取給定值最左端一個值,調用後會從users的key中刪除該值),
lrange users 0-1 獲取給定key,給定範圍全部值
lindex users 1 獲取下標(從0位開始計算)1位置值
(4)集合Set:Redis的集合使用的是無序的方式存儲元素,因此不能夠像List列表那樣,將元素推入集合的某一端,或者從集合的某一端彈出元素。使用場景:共同好友、二度好友,利用惟一性,能夠統計訪問網站的全部獨立 IP,好友推薦的時候,根據 tag 求交集,大於某個 threshold 就能夠推薦
(1)經常使用命令以下:
(2)除了常見的命令以外,還有交集、並集、差集的計算,以下:
(5)有序集合SortedSet:和set相比,sorted set增長了一個權重參數score,使得集合中的元素可以按score進行有序排列;場景:排行榜應用,取TOP N操做;這個需求與上面需求的不一樣之處在於,前面操做以時間爲權重,這個是以某個條件爲權重
//將登陸次數和用戶統一存儲在一個sorted set裏 zadd login:login_times 5 1 zadd login:login_times 1 2 zadd login:login_times 2 3 //當用戶登陸時,對該用戶的登陸次數自增1 ret = r.zincrby("login:login_times", 1, uid) //那麼如何得到登陸次數最多的用戶呢,逆序排列取得排名前N的用戶 ret = r.zrevrange("login:login_times", 0, N-1)
若是你是Redis中高級用戶,還須要加上下面幾種數據結構HyperLogLog、Geo、Pub/Sub。
Pub/Sub 從字面上理解就是發佈(Publish)與訂閱(Subscribe),在Redis中,你能夠設定對某一個key值進行消息發佈及消息訂閱,當一個key值上進行了消息發佈後,全部訂閱它的客戶端都會收到相應的消息。這一功能最明顯的用法就是用做實時消息系統,好比普通的即時聊天,羣聊等功能。
若是你說還玩過Redis Module,像BloomFilter,RedisSearch,Redis-ML,面試官得眼睛就開始發亮了。
9.使用過Redis分佈式鎖麼,它是什麼回事?
先拿setnx來爭搶鎖,搶到以後,再用expire給鎖加一個過時時間防止鎖忘記了釋放。
而後接着問若是在setnx以後執行expire以前進程意外crash或者要重啓維護了,那會怎麼樣?
是喔,這個鎖就永遠得不到釋放了。而後回答:我記得set指令有很是複雜的參數,這個應該是能夠同時把setnx和expire合成一條指令來用的!
10.假如Redis裏面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,若是將它們所有找出來?
使用keys指令能夠掃出指定模式的key列表。
對方接着追問:若是這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?
這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會致使線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可使用scan指令,scan指令能夠無阻塞的提取出指定模式的key列表,可是會有必定的重複機率,在客戶端作一次去重就能夠了,可是總體所花費的時間會比直接用keys指令長。
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如何作持久化的?
bgsave作鏡像全量持久化,aof作增量持久化。由於bgsave會耗費較長時間,不夠實時,在停機的時候會致使大量丟失數據,因此須要aof來配合使用。在redis實例重啓時,優先使用aof來恢復內存的狀態,若是沒有aof日誌,就會使用rdb文件來恢復。
若是再問aof文件過大恢復時間過長怎麼辦?你告訴面試官,Redis會按期作aof重寫,壓縮aof文件日誌大小。若是面試官不夠滿意,再拿出殺手鐗答案,Redis4.0以後有了混合持久化的功能,將bgsave的全量和aof的增量作了融合處理,這樣既保證了恢復的效率又兼顧了數據的安全性。這個功能甚至不少面試官都不知道,他們確定會對你另眼相看。
若是對方追問那若是忽然機器掉電會怎樣?取決於aof日誌sync屬性的配置,若是不要求性能,在每條寫指令時都sync一下磁盤,就不會丟失數據。可是在高性能的要求下每次都sync是不現實的,通常都使用定時sync,好比1s1次,這個時候最多就會丟失1s的數據。
若是對方追問bgsave的原理是什麼?你給出兩個詞彙就能夠了,fork和cow。fork是指redis經過建立子進程來進行bgsave操做,cow指的是copy on write,子進程建立後,父子進程共享數據段,父進程繼續提供讀寫服務,寫髒的頁面數據會逐漸和子進程分離開來。
14.Pipeline有什麼好處,爲何要用pipeline?
能夠將屢次IO往返的時間縮減爲一次,前提是pipeline執行的指令之間沒有因果相關性。使用redis-benchmark進行壓測的時候能夠發現影響redis的QPS峯值的一個重要因素是pipeline批次指令的數目。
15.Redis的同步機制瞭解麼?
Redis可使用主從同步,從從同步。第一次同步時,主節點作一次bgsave,並同時將後續修改操做記錄到內存buffer,待完成後將rdb文件全量同步到複製節點,複製節點接受完成後將rdb鏡像加載到內存。加載完成後,再通知主節點將期間修改的操做記錄同步到複製節點進行重放就完成了同步過程。
16.是否使用過Redis集羣,集羣的原理是什麼?
Redis Sentinal着眼於高可用,在master宕機時會自動將slave提高爲master,繼續提供服務。
Redis Cluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。
17.使用redis有什麼缺點
分析:你們用redis這麼久,這個問題是必需要了解的,基本上使用redis都會碰到一些問題,常見的也就幾個。
回答:主要是四個問題
(一)緩存和數據庫雙寫一致性問題
(二)緩存雪崩問題
(三)緩存擊穿問題
(四)緩存的併發競爭問題
18.Redis常見命令:
獲取鏈接:redis-cli -p 端口 -a 密碼
獲取全部key:keys *
獲取某個key:keys *USER_RELATION_KEY_*
獲取某個key中值:get USER_RELATION_KEY_*
清空全部數據:flushdb
數量獲取:dbsize
查看redis信息:info
19.單線程的redis爲何這麼快
分析:這個問題實際上是對redis內部機制的一個考察。其實根據博主的面試經驗,不少人其實都不知道redis是單線程工做模型。因此,這個問題仍是應該要複習一下的。
回答:主要是如下三點
(一)純內存操做
(二)單線程操做,避免了頻繁的上下文切換
(三)採用了非阻塞I/O多路複用機制
題外話:咱們如今要仔細的說一說I/O多路複用機制,由於這個說法實在是太通俗了,通俗到通常人都不懂是什麼意思。博主打一個比方:小曲在S城開了一家快遞店,負責同城快送服務。小曲由於資金限制,僱傭了一批快遞員,而後小曲發現資金不夠了,只夠買一輛車送快遞。
20.redis的過時策略以及內存淘汰機制
分析:這個問題其實至關重要,到底redis有沒用到家,這個問題就能夠看出來。好比你redis只能存5G數據,但是你寫了10G,那會刪5G的數據。怎麼刪的,這個問題思考過麼?還有,你的數據已經設置了過時時間,可是時間到了,內存佔用率仍是比較高,有思考過緣由麼?
回答:
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(不刪除) 基本上一致。
21.redis和數據庫雙寫一致性問題
分析:一致性問題是分佈式常見問題,還能夠再分爲最終一致性和強一致性。數據庫和緩存雙寫,就必然會存在不一致的問題。答這個問題,先明白一個前提。就是若是對數據有強一致性要求,不能放緩存。咱們所作的一切,只能保證最終一致性。另外,咱們所作的方案其實從根本上來講,只能說下降不一致發生的機率,沒法徹底避免。所以,有強一致性要求的數據,不能放緩存。
首先,採起正確更新策略,先更新數據庫,再刪緩存。其次,由於可能存在刪除緩存失敗的問題,提供一個補償措施便可,例如利用消息隊列。
22.如何應對緩存穿透和緩存雪崩問題
分析:這兩個問題,說句實在話,通常中小型傳統軟件企業,很難碰到這個問題。若是有大併發的項目,流量有幾百萬左右。這兩個問題必定要深入考慮。
回答:以下所示
緩存穿透,即黑客故意去請求緩存中不存在的數據,致使全部的請求都懟到數據庫上,從而數據庫鏈接異常。
解決方案:
(一)利用互斥鎖,緩存失效的時候,先去得到鎖,獲得鎖了,再去請求數據庫。沒獲得鎖,則休眠一段時間重試
(二)採用異步更新策略,不管key是否取到值,都直接返回。value值中維護一個緩存失效時間,緩存若是過時,異步起一個線程去讀數據庫,更新緩存。須要作緩存預熱(項目啓動前,先加載緩存)操做。
(三)提供一個能迅速判斷請求是否有效的攔截機制,好比,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。若是不合法,則直接返回。
緩存雪崩,即緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而致使數據庫鏈接異常。
解決方案:
(一)給緩存的失效時間,加上一個隨機值,避免集體失效。
(二)使用互斥鎖,可是該方案吞吐量明顯降低了。
(三)雙緩存。咱們有兩個緩存,緩存A和緩存B。緩存A的失效時間爲20分鐘,緩存B不設失效時間。本身作緩存預熱操做。而後細分如下幾個小點
I 從緩存A讀數據庫,有則直接返回
II A沒有數據,直接從B讀數據,直接返回,而且異步啓動一個更新線程。
III 更新線程同時更新緩存A和緩存B。
23.如何解決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方法變成串行訪問也能夠。總之,靈活變通。