Java面試題——Redis
一、Redis簡介
簡單來說Redis(Remote Dictionary Server(遠端資料服務))就是一個數據庫,不過與傳統的資料庫不同的是Redis的資料是存在記憶體中的,所以讀寫速度非常快,因此Redis被廣泛應用於快取方向。另外Redis也經常用來做分散式鎖。Redis提供了多種資料型別來支援不同的業務場景。除此之外,Redis支援事務、持久化、LUA指令碼、LRU驅動事件、多種叢集方案等。
二、Redis面試題
1、Redis的特點
- 支援多種資料結構,如string(字串)、list(雙向連結串列)、dict(hash表)、set(集合)、zset(排序set)、hyperloglog(基數估算)
- 支援持久化操作,可以進行aof及rdb資料持久化到磁碟,從而進行資料備份或資料恢復等操作,較好的防止資料丟失的手段。
- 單程序請求,所有命令序列執行,併發情況下不需要考慮資料一致性問題。
- 支援通過Replication進行資料複製,通過master-slave機制,可以實時進行資料的同步複製,支援多級複製和增量複製,master-slave機制是Redis進行HA的重要手段。(HA :redis的高可用HA)
2、Redis持久化機制
Redis是一個支援持久化的記憶體資料庫,通過持久化機制把記憶體中的資料同步到硬碟檔案來保證資料持久化。當Redis重啟後通過把硬碟檔案重新載入到記憶體,就能達到恢復資料的目的。 實現:單獨建立fork()一個子程序,將當前父程序的資料庫資料複製到子程序的記憶體中,然後由子程序寫入到臨時檔案中,持久化的過程結束了,再用這個臨時檔案替換上次的快照檔案,然後子程序退出,記憶體釋放 RDB:是Redis預設的持久化方式。按照一定的時間週期策略把記憶體的資料以快照的形式儲存到硬碟的二進位制檔案。即Snapshot快照儲存,對應產生的資料檔案為dump.rdb,通過配置檔案中的save引數來定義快照的週期。( 快照可以是其所表示的資料的一個副本,也可以是資料的一個複製品。) AOF:Redis會將每一個收到的寫命令都通過Write函式追加到檔案最後,類似於MySQL的binlog。當Redis重啟是會通過重新執行檔案中儲存的寫命令來在記憶體中重建整個資料庫的內容。當兩種方式同時開啟時,資料恢復Redis會優先選擇AOF恢復3、熱點資料和冷資料是什麼?
4、單執行緒的Redis為什麼那麼快?
- 純記憶體操作
- 單執行緒操作,避免了頻繁的上下文切換
- 採用了非阻塞I/O多路複用機制
5、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操作6、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該配置就是配記憶體淘汰策略的(什麼,你沒配過?好好反省一下自己) 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(驅逐):禁止驅逐資料,新寫入操作會報錯 ps:如果沒有設定 expire 的key, 不滿足先決條件(prerequisites); 那麼 volatile-lru, volatile-random 和volatile-ttl 策略的行為和noeviction(不刪除)基本一致
7、Redis常見效能問題和解決方案?
- Master最好不要做任何的持久化工作,如RDB記憶體快照和AOF日誌檔案
- 如果資料比較重要,某個Slave開啟AOF備份資料,策略設定為每秒同步一次
- 為了主從複製的速度和連線的穩定性,Master和Slave最好在同一個區域網內
- 儘量避免在壓力很大的主庫上新增從庫
- 主從複製不要用圖狀結構,用單向連結串列結構更為穩定,即Master<-Slave1<-Slave2...
8、為什麼Redis的操作是原子性的,怎麼保證原子性的?
對於Redis而言,命令的原子性指的是:一個操作的不可以再分,操作要麼執行,要麼不執行、
Redis的操作之所以是原子性的,是因為Redis是單執行緒的
Redis本身提供的所有API都是原子操作,Redis中的事務其實是要保證批量操作的原子性。
多個命令在併發中也是原子性的嗎?
不一定,將get和set改成單命令操作,incr。使用Redis的事務,或者使用Redis+Lua==的方式實現
9、Redis 的持久化機制是什麼?各自的優缺點?
Redis 提供兩種持久化機制 RDB 和 AOF 機制: 1、RDBRedis DataBase)持久化方式: 是指用資料集快照的方式半持久化模式)記錄 redis 資料庫的所有鍵值對,在某個時間點將資料寫入一個臨時檔案,持久化結束後,用這個臨時檔案替換上次持久化的檔案,達到資料恢復。 優點: 1、只有一個檔案 dump.rdb,方便持久化。 2、容災性好,一個檔案可以儲存到安全的磁碟。 3、效能最大化,fork 子程序來完成寫操作,讓主程序繼續處理命令,所以是 IO最大化。使用單獨子程序來進行持久化,主程序不會進行任何 IO 操作,保證了 redis的高效能) 4.相對於資料集大時,比 AOF的啟動效率更高。 缺點: 1、資料安全性低。RDB 是間隔一段時間進行持久化,如果持久化之間 redis 發生故障,會發生資料丟失。所以這種方式更適合資料要求不嚴謹的時候) 2、AOFAppend-only fifile)持久化方式: 是指所有的命令列記錄以 redis 命令請求協議的格式完全持久化儲存)儲存為 aof 檔案。 優點: 1、資料安全,aof 持久化可以配置 appendfsync 屬性,有 always,每進行一次命令操作就記錄到 aof檔案中一次。 2、通過 append 模式寫檔案,即使中途伺服器宕機,可以通過 redis-check-aof工具解決資料一致性問題。 3、AOF 機制的 rewrite 模式。AOF 檔案沒被 rewrite 之前(檔案過大時會對命令進行合併重寫),可以刪除其中的某些命令(比如誤操作的 flflushall)) 缺點: 1、AOF 檔案比 RDB 檔案大,且恢復速度慢。 2、資料集大的時候,比 rdb 啟動效率低。10、Jedis與Redission對比有什麼特點?
Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis支援;Redission實現了分散式和可擴充套件的Java資料結構,和Jedis相比,功能較為簡單,不支援字串操作、不支援排序、事務、管道、分割槽等Redis特性。Redission的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中的放在處理業務邏輯上。
11、怎麼測試Redis的連通性?
使用ping命令
12、Redis 如何做記憶體優化?
儘可能使用散列表(hashes),散列表(是說散列表裡面儲存的數少)使用的記憶體非常小,所以你應該儘可能的將你的資料模型抽象到一個散列表裡面。比如你的 web 系統中有一個使用者物件,不要為這個使用者的名稱,姓氏,郵箱,密碼設定單獨的 key,而是應該把這個使用者的所有資訊儲存到一張散列表裡面.13、Redis 的記憶體用完了會發生什麼?
如果達到設定的上限,Redis的寫命令會返回錯誤資訊(但是讀命令還可以正常返回)或者你可以將Redis當快取來使用配置淘汰機制,當Redis達到記憶體上限時會沖刷掉舊的內容
14、Redis最適合的場景?
- 會話快取(Session Cache) 最常用的一種使用 Redis 的情景是會話快取(session cache)。用 Redis 快取會話比其他儲存(如 Memcached)的優勢在於:Redis 提供持久化。當維護一個不是嚴格要求一致性的快取時,如果使用者 的購物車資訊全部丟失,大部分人都會不高興的,現在,他們還會這樣嗎? 幸運的是,隨著 Redis 這些 年的改進,很容 易找到怎麼恰當的使用 Redis 來快取會話的文件。甚至廣為人知的商業平臺Magento 也提供 Redis 的 外掛。
- 全頁快取(FPC) 除基本的會話 token 之外,Redis 還提供很簡便的 FPC 平臺。回到一致性問題,即使重啟了 Redis 實 例,因為有磁碟的持久化,使用者也不會看到頁面載入速度的下降,這是一個極大改進,類似 PHP 本地 FPC。 再次以 agento 為例,Magento提供一個外掛來使用 Redis 作為全頁快取後端。 此外,對 WordPress 的使用者來說,Pantheon 有一個非常好的外掛 wp-redis,這個外掛能幫助你以最快速度加 載你曾瀏覽過的頁面。
- 佇列 Reids 在記憶體儲存引擎領域的一大優點是提供 list 和 set 操作,這使得 Redis能作為一個很好的訊息隊 列平臺來使用。Redis 作為佇列使用的操作,就類似於本地程式語言(如 Python)對 list 的 push/pop 操作。 如果你快速的在 Google中搜索“Redis queues”,你馬上就能找到大量的開源專案,這些專案的 目的就是利用 Redis 建立非常好的後端工具,以滿足各種佇列需求。例如,Celery 有一個後臺就是使用 Redis 作為 broker,你可以從這裡去檢視。
- 排行榜/計數器 Redis 在記憶體中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)也 使得我們在執行這些操作的時候變的非常簡單,Redis 只是正好提供了這兩種資料結構。所以,我們要 從排序集合中獲取到排名最靠前的 10個使用者–我們稱之為“user_scores”,我們只需要像下面一樣執行即 可: 當然,這是假定你是根據你使用者的分數做遞增的排序。如果你想返回使用者及使用者的分數,你需要這 樣執行: ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一個很好的例子,用 Ruby 實現 的,它的排行榜就是使用 Redis 來儲存資料的, 你可以在這裡看到。
-
釋出/訂閱
最後(但肯定不是最不重要的)是 Redis 的釋出/訂閱功能。釋出/訂閱的使用場景確實非常多。我已看
見人們在社交網路連線中使用,還可作為基於釋出/訂閱的指令碼觸發器,甚至用 Redis 的釋出/訂閱功能
來建立聊天系統!
15、
一個小小後端的爬行痕跡