1. Redis有哪些數據結構?
2. 使用過Redis分布式鎖么,它是什么回事?
3. 假如Redis里面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,如果將它們全部找出來?
4. 如果這個redis正在給線上的業務提供服務,那使用keys指令會有什么問題?
5. 使用過Redis做異步隊列么,你是怎么用的?
6. 如果對方追問redis如何實現延時隊列?
7. 如果有大量的key需要設置同一時間過期,一般需要注意什么
8. Redis如何做持久化的?
9. Pipeline有什么好處,為什么要用pipeline?
10. Redis的同步機制了解么?
11. 是否使用過Redis集群,集群的原理是什么?
12. 使用redis有哪些好處?
13. redis相比memcached有哪些優勢?
14. Memcache與Redis的區別都有哪些?
15. redis常見性能問題和解決方案:
16. 為什么redis需要把所有數據放到內存中?
17. Redis是單進程單線程的
18. redis的並發競爭問題如何解決?
19. redis事物的了解CAS(check-and-set 操作實現樂觀鎖 )?
20. redis持久化的幾種方式
21. redis 最適合的場景
一、Redis有哪些數據結構?
字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。 如果你是Redis中高級用戶,還需要加上下面幾種數據結構HyperLogLog、Geo、Pub/Sub。
二、使用過Redis分布式鎖么,它是什么回事?
先拿setnx來爭搶鎖,搶到之后,再用expire給鎖加一個過期時間防止鎖忘記了釋放。
這時候對方會告訴你說你回答得不錯,然后接着問如果在setnx之后執行expire之前進程意外crash或者要重啟維護了,那會怎么樣?
這時候你要給予驚訝的反饋:唉,是喔,這個鎖就永遠得不到釋放了。緊接着你需要抓一抓自己得腦袋,故作思考片刻,好像接下來的結果是你主動思考出來的,然后回答:我記得set指令有非常復雜的參數,這個應該是可以同時把setnx和expire合成一條指令來用的!對方這時會顯露笑容,心里開始默念:摁,這小子還不錯。
jedis.set(String key, String value, String nx, String expx, int time),這個set()方法一共有五個形參:
第一個為key,我們使用key來當鎖,因為key是唯一的。 第二個為value,我們傳的是requestId,很多童鞋可能不明白,有key作為鎖不就夠了嗎,為什么還要用到value?
原因就是我們在上面講到可靠性時,分布式鎖要滿足第四個條件解鈴還須系鈴人,通過給value賦值為requestId,我們就知道這把鎖是哪個請求加的了,在解鎖的時候就可以有依據。
requestId可以使用UUID.randomUUID().toString()方法生成。 第三個為nx,這個參數我們填的是NX,意思是SET IF NOT EXIST,即當key不存在時,我們進行set操作;若key已經存在,則不做任何操作; 第四個為expx,這個參數我們傳的是PX,意思是我們要給這個key加一個過期的設置,具體時間由第五個參數決定。 第五個為time,與第四個參數相呼應,代表key的過期時間。
三、假如Redis里面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,如果將它們全部找出來?
使用keys指令可以掃出指定模式的key列表:keys pre*
四、如果這個redis正在給線上的業務提供服務,那使用keys指令會有什么問題?
這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。
這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重復概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
五、 使用過Redis做異步隊列么,你是怎么用的?
一般使用list結構作為隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。 如果對方追問可不可以不用sleep呢?list還有個指令叫blpop,在沒有消息的時候,它會阻塞住直到消息到來。 如果對方追問能不能生產一次消費多次呢?使用pub/sub主題訂閱者模式,可以實現1:N的消息隊列。 如果對方追問pub/sub有什么缺點?在消費者下線的情況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。redis中pub/sub缺陷
六、如果對方追問redis如何實現延時隊列?
我估計現在你很想把面試官一棒打死如果你手上有一根棒球棍的話,怎么問的這么詳細。但是你很克制,然后神態自若的回答道:
使用有序集合,拿時間戳作為score,消息內容作為key調用zadd來生產消息,消費者用zrangebyscore指令獲取N秒之前的數據輪詢進行處理。
七、 如果有大量的key需要設置同一時間過期,一般需要注意什么
如果大量的key過期時間設置的過於集中,到過期的那個時間點,redis可能會出現短暫的卡頓現象。一般需要在時間上加一個隨機值,使得過期時間分散一些。
八、 Redis如何做持久化的?
8.1. RDB做鏡像全量持久化,AOF做增量持久化。
RDB持久化也分兩種:SAVE和BGSAVE。 •SAVE是阻塞式的RDB持久化,當執行這個命令時redis的主進程把內存里的數據庫狀態寫入到RDB文件中,直到該文件創建完畢的這段時間內redis將不能處理任何命令請求;
•BGSAVE屬於非阻塞式的持久化,它會創建一個子進程專門去把內存中的數據庫狀態寫入RDB文件里,同時主進程還可以處理來自客戶端的命令請求。
但子進程基本是復制的父進程,這等於兩個相同大小的redis進程在系統上運行,會造成內存使用率的大幅增加。
8.2. AOF的持久化是通過命令追加、文件寫入和文件同步三個步驟實現的。
當reids開啟AOF后(redis備份方式默認是RDB), 服務端每執行一次寫操作(如set、sadd、rpush)就會把該條命令追加到一個單獨的AOF緩沖區的末尾,這就是命令追加; 然后把AOF緩沖區的內容寫入AOF文件里。看上去第二步就已經完成AOF持久化了那第三步是干什么的呢?這就需要從系統的文件寫入機制說起:一般我們現在所使用的操作系統,為了提高文件的寫入效率,都會有一個寫入策略,即當你往
硬盤寫入數據時,操作系統不是實時的將數據寫入硬盤,而是先把數據暫時的保存在一個內存緩沖區里,等到這個內存緩沖區的空間被填滿或者是超過了設定的時限后才會真正的把緩沖區內的數據寫入硬盤中。也就是說當redis進行到第二
步文件寫入的時候,從用戶的角度看是已經把AOF緩沖區里的數據寫入到AOF文件了,但對系統而言只不過是把AOF緩沖區的內容放到了另一個內存緩沖區里而已,之后redis還需要進行文件同步把該內存緩沖區里的數據真正寫入硬盤上
才算是完成了一次持久化。而何時進行文件同步則是根據配置的appendfsync來進行:appendfsync有三個選項:always、everysec和no:
九、Pipeline有什么好處,為什么要用pipeline?
可以將多次IO往返的時間縮減為一次,前提是pipeline執行的指令之間沒有因果相關性。使用redis-benchmark進行壓測的時候可以發現影響redis的QPS峰值的一個重要因素是pipeline批次指令的數目。
十、Redis的同步機制了解么?
Redis可以使用主從同步,從從同步。第一次同步時,主節點做一次bgsave,並同時將后續修改操作記錄到內存buffer,待完成后將rdb文件全量同步到復制節點,復制節點接受完成后將rdb鏡像加載到內存。
加載完成后,再通知主節點將期間修改的操作記錄同步到復制節點進行重放就完成了同步過程。
十一、是否使用過Redis集群,集群的原理是什么?
Redis Sentinal着眼於高可用,在master宕機時會自動將slave提升為master,繼續提供服務。 Redis Cluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。
十二、使用redis有哪些好處?
(1) 速度快,因為數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間復雜度都是O(1) (2) 支持豐富數據類型,支持string,list,set,sorted set,hash (3) 支持事務,操作都是原子性,所謂的原子性就是對數據的更改要么全部執行,要么全部不執行 (4) 豐富的特性:可用於緩存,消息,按key設置過期時間,過期后將會自動刪除
十三、redis相比memcached有哪些優勢?
(1) memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數據類型 (2) redis的速度比memcached快很多 (3) redis可以持久化其數據
十四、Memcache與Redis的區別都有哪些?
1)、存儲方式 Memecache把數據全部存在內存之中,斷電后會掛掉,數據不能超過內存大小。 Redis有部份存在硬盤上,這樣能保證數據的持久性。 2)、數據支持類型 Memcache對數據類型支持相對簡單。 Redis有復雜的數據類型。 3)、使用底層模型不同 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。 Redis直接自己構建了VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
十五、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最好在同一個局域網內
十六、為什么redis需要把所有數據放到內存中?
Redis為了達到最快的讀寫速度將數據都讀到內存中,並通過異步的方式將數據寫入磁盤。所以redis具有快速和數據持久化的特征。如果不將數據放在內存中,磁盤I/O速度為嚴重影響redis的性能。
在內存越來越便宜的今天,redis將會越來越受歡迎。如果設置了最大使用的內存,則數據已有記錄數達到內存限值后不能繼續插入新值。
十七、Redis是單進程單線程的
redis利用隊列技術將並發訪問變為串行訪問,消除了傳統數據庫串行控制的開銷。
十八、redis的並發競爭問題如何解決?
Redis為單進程單線程模式,采用隊列模式將並發訪問變為串行訪問。Redis本身沒有鎖的概念,Redis對於多個客戶端連接並不存在競爭,但是在Jedis客戶端對Redis進行並發訪問時會發生連接超時、數據轉換錯誤、阻塞、客戶端關閉連接等問題,這些問題均是由於客戶端連接混亂造成。對此有2種解決方法:
1).客戶端角度,為保證每個客戶端間正常有序與Redis進行通信,對連接進行池化,同時對客戶端讀寫Redis操作采用內部鎖synchronized。 2).服務器角度,利用setnx實現鎖。 注:對於第一種,需要應用程序自己處理資源的同步,可以使用的方法比較通俗,可以使用synchronized也可以使用lock;第二種需要用到Redis的setnx命令,但是需要注意一些問題。
十九、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服務器了。
二十、 redis持久化的幾種方式
1).快照(snapshots)
缺省情況情況下,Redis把數據快照存放在磁盤上的二進制文件中,文件名為dump.rdb。你可以配置Redis的持久化策略,例如數據集中每N秒鍾有超過M次更新,就將數據寫入磁盤;或者你可以手工調用命令SAVE或BGSAVE。 工作原理: . Redis forks. . 子進程開始將數據寫到臨時RDB文件中。 . 當子進程完成寫RDB文件,用新文件替換老文件。 . 這種方式可以使Redis使用copy-on-write技術。
2).AOF
快照模式並不健壯,當系統停止,或者無意中Redis被kill掉,最后寫入Redis的數據就會丟失。這對某些應用也許不是大問題,但對於要求高可靠性的應用來說,Redis就不是一個合適的選擇。
Append-only文件模式是另一種選擇。你可以在配置文件中打開AOF模式。
3).虛擬內存方式
當你的key很小而value很大時,使用VM的效果會比較好.因為這樣節約的內存比較大. 當你的key不小時,可以考慮使用一些非常方法將很大的key變成很大的value,比如你可以考慮將key,value組合成一個新的value. vm-max-threads這個參數,可以設置訪問swap文件的線程數,設置最好不要超過機器的核數,如果設置為0,那么所有對swap文件的操作都是串行的.可能會造成比較長時間的延遲,但是對數據完整性有很好的保證.
二十一、 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提供持久化。 (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的發布/訂閱功能來建立聊天系統!