史上最全、最新的Redis面試題(2020最新版)!

做者:ThinkWon
原文:https://thinkwon.blog.csdn.ne...

技術人面試,不管是開發、運維、測試、仍是架構師,Redis技術是必問的點。公衆號後臺、羣裏,一直也有人問有沒有相關的面試題彙總,有時候想看看查漏補缺一下,面試也有可能用的上。因此,今天,民工哥給你們帶這篇彙總文章。前端

什麼是Redisnode

Redis(Remote Dictionary Server) 是一個使用 C 語言編寫的,開源的(BSD許可)高性能非關係型(NoSQL)的鍵值對數據庫。web

Redis 能夠存儲鍵和五種不一樣類型的值之間的映射。鍵的類型只能爲字符串,值支持五種數據類型:字符串、列表、集合、散列表、有序集合。面試

與傳統數據庫不一樣的是 Redis 的數據是存在內存中的,因此讀寫速度很是快,所以 redis 被普遍應用於緩存方向,每秒能夠處理超過 10萬次讀寫操做,是已知性能最快的Key-Value DB。另外,Redis 也常常用來作分佈式鎖。除此以外,Redis 支持事務 、持久化、LUA腳本、LRU驅動事件、多種集羣方案。redis

Redis有哪些優缺點算法

優勢數據庫

  • 讀寫性能優異, Redis能讀的速度是110000次/s,寫的速度是81000次/s。
  • 支持數據持久化,支持AOF和RDB兩種持久化方式。
  • 支持事務,Redis的全部操做都是原子性的,同時Redis還支持對幾個操做合併後的原子性執行。
  • 數據結構豐富,除了支持string類型的value外還支持hash、set、zset、list等數據結構。
  • 支持主從複製,主機會自動將數據同步到從機,能夠進行讀寫分離。

缺點windows

  • 數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上。
  • Redis 不具有自動容錯和恢復功能,主機從機的宕機都會致使前端部分讀寫請求失敗,須要等待機器重啓或者手動切換前端的IP才能恢復。
  • 主機宕機,宕機前有部分數據未能及時同步到從機,切換IP後還會引入數據不一致的問題,下降了系統的可用性。
  • Redis 較難支持在線擴容,在集羣容量達到上限時在線擴容會變得很複雜。爲避免這一問題,運維人員在系統上線時必須確保有足夠的空間,這對資源形成了很大的浪費。

爲何要用 Redis /爲何要用緩存後端

主要從「高性能」和「高併發」這兩點來看待這個問題。緩存

高性能:

假如用戶第一次訪問數據庫中的某些數據。這個過程會比較慢,由於是從硬盤上讀取的。將該用戶訪問的數據存在數緩存中,這樣下一次再訪問這些數據的時候就能夠直接從緩存中獲取了。操做緩存就是直接操做內存,因此速度至關快。若是數據庫中的對應數據改變的以後,同步改變緩存中相應的數據便可!

高併發:

直接操做緩存可以承受的請求是遠遠大於直接訪問數據庫的,因此咱們能夠考慮把數據庫中的部分數據轉移到緩存中去,這樣用戶的一部分請求會直接到緩存這裏而不用通過數據庫。

爲何要用 Redis 而不用 map/guava 作緩存?

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

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

Redis爲何這麼快

一、徹底基於內存,絕大部分請求是純粹的內存操做,很是快速。數據存在內存中,相似於 HashMap,HashMap 的優點就是查找和操做的時間複雜度都是O(1);

二、數據結構簡單,對數據操做也簡單,Redis 中的數據結構是專門進行設計的;

三、採用單線程,避免了沒必要要的上下文切換和競爭條件,也不存在多進程或者多線程致使的切換而消耗 CPU,不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗;

四、使用多路 I/O 複用模型,非阻塞 IO;

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

數據類型

Redis有哪些數據類型

Redis主要有5種數據類型,包括String,List,Set,Zset,Hash,知足大部分的使用要求

**Redis的應用場景
**

總結一

計數器

能夠對 String 進行自增自減運算,從而實現計數器功能。Redis 這種內存型數據庫的讀寫性能很是高,很適合存儲頻繁讀寫的計數量。

緩存

將熱點數據放到內存中,設置內存的最大使用量以及淘汰策略來保證緩存的命中率。

會話緩存

能夠使用 Redis 來統一存儲多臺應用服務器的會話信息。當應用服務器再也不存儲用戶的會話信息,也就再也不具備狀態,一個用戶能夠請求任意一個應用服務器,從而更容易實現高可用性以及可伸縮性。

全頁緩存(FPC)

除基本的會話token以外,Redis還提供很簡便的FPC平臺。以Magento爲例,Magento提供一個插件來使用Redis做爲全頁緩存後端。此外,對WordPress的用戶來講,Pantheon有一個很是好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。

查找表

例如 DNS 記錄就很適合使用 Redis 進行存儲。查找表和緩存相似,也是利用了 Redis 快速的查找特性。可是查找表的內容不能失效,而緩存的內容能夠失效,由於緩存不做爲可靠的數據來源。

消息隊列(發佈/訂閱功能)

List 是一個雙向鏈表,能夠經過 lpush 和 rpop 寫入和讀取消息。不過最好使用 Kafka、RabbitMQ 等消息中間件。

分佈式鎖實現

在分佈式場景下,沒法使用單機環境下的鎖來對多個節點上的進程進行同步。能夠使用 Redis 自帶的 SETNX 命令實現分佈式鎖,除此以外,還能夠使用官方提供的 RedLock 分佈式鎖實現。

其它

Set 能夠實現交集、並集等操做,從而實現共同好友等功能。ZSet 能夠實現有序性操做,從而實現排行榜等功能。

總結二

Redis相比其餘緩存,有一個很是大的優點,就是支持多種數據類型。

數據類型說明string字符串,最簡單的k-v存儲hashhash格式,value爲field和value,適合ID-Detail這樣的場景。list簡單的list,順序列表,支持首位或者末尾插入數據set無序list,查找速度快,適合交集、並集、差集處理sorted set有序的set

其實,經過上面的數據類型的特性,基本就能想到合適的應用場景了。

string——適合最簡單的k-v存儲,相似於memcached的存儲結構,短信驗證碼,配置信息等,就用這種類型來存儲。

hash——通常key爲ID或者惟一標示,value對應的就是詳情了。如商品詳情,我的信息詳情,新聞詳情等。

list——由於list是有序的,比較適合存儲一些有序且數據相對固定的數據。如省市區表、字典表等。由於list是有序的,適合根據寫入的時間來排序,如:最新的***,消息隊列等。

set——能夠簡單的理解爲ID-List的模式,如微博中一我的有哪些好友,set最牛的地方在於,能夠對兩個set提供交集、並集、差集操做。例如:查找兩我的共同的好友等。

Sorted Set——是set的加強版本,增長了一個score參數,自動會根據score的值進行排序。比較適合相似於top 10等不根據插入的時間來排序的數據。

如上所述,雖然Redis不像關係數據庫那麼複雜的數據結構,可是,也能適合不少場景,比通常的緩存數據結構要多。瞭解每種數據結構適合的業務場景,不只有利於提高開發效率,也能有效利用Redis的性能。

持久化

什麼是Redis持久化?

持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。

Redis 的持久化機制是什麼?各自的優缺點?

Redis 提供兩種持久化機制 RDB(默認) 和 AOF 機制:

RDB:是Redis DataBase縮寫快照

RDB是Redis默認的持久化方式。按照必定的時間將內存的數據以快照的形式保存到硬盤中,對應產生的數據文件爲dump.rdb。經過配置文件中的save參數來定義快照的週期。

優勢:

一、只有一個文件 dump.rdb,方便持久化。

二、容災性好,一個文件能夠保存到安全的磁盤。

三、性能最大化,fork 子進程來完成寫操做,讓主進程繼續處理命令,因此是 IO 最大化。使用單獨子進程來進行持久化,主進程不會進行任何 IO 操做,保證了 redis 的高性能

4.相對於數據集大時,比 AOF 的啓動效率更高。

缺點:

一、數據安全性低。RDB 是間隔一段時間進行持久化,若是持久化之間 redis 發生故障,會發生數據丟失。因此這種方式更適合數據要求不嚴謹的時候)

二、AOF(Append-only file)持久化方式:是指全部的命令行記錄以 redis 命令請 求協議的格式徹底持久化存儲)保存爲 aof 文件。

AOF:持久化

AOF持久化(即Append Only File持久化),則是將Redis執行的每次寫命令記錄到單獨的日誌文件中,當重啓Redis會從新將持久化的日誌中文件恢復數據。

當兩種方式同時開啓時,數據恢復Redis會優先選擇AOF恢復。

優勢:

一、數據安全,aof 持久化能夠配置 appendfsync 屬性,有 always,每進行一次 命令操做就記錄到 aof 文件中一次。

二、經過 append 模式寫文件,即便中途服務器宕機,能夠經過 redis-check-aof 工具解決數據一致性問題。

三、AOF 機制的 rewrite 模式。AOF 文件沒被 rewrite 以前(文件過大時會對命令 進行合併重寫),能夠刪除其中的某些命令(好比誤操做的 flushall))

缺點:

一、AOF 文件比 RDB 文件大,且恢復速度慢。

二、數據集大的時候,比 rdb 啓動效率低。

優缺點是什麼?

  • AOF文件比RDB更新頻率高,優先使用AOF還原數據。
  • AOF比RDB更安全也更大
  • RDB性能比AOF好
  • 若是兩個都配了優先加載AOF

如何選擇合適的持久化方式

  • 通常來講, 若是想達到足以媲美PostgreSQL的數據安全性,你應該同時使用兩種持久化功能。在這種狀況下,當 Redis 重啓的時候會優先載入AOF文件來恢復原始的數據,由於在一般狀況下AOF文件保存的數據集要比RDB文件保存的數據集要完整。
  • 若是你很是關心你的數據, 但仍然能夠承受數分鐘之內的數據丟失,那麼你能夠只使用RDB持久化。
  • 有不少用戶都只使用AOF持久化,但並不推薦這種方式,由於定時生成RDB快照(snapshot)很是便於進行數據庫備份, 而且 RDB 恢復數據集的速度也要比AOF恢復的速度要快,除此以外,使用RDB還能夠避免AOF程序的bug。
  • 若是你只但願你的數據在服務器運行的時候存在,你也能夠不使用任何持久化方式。

Redis持久化數據和緩存怎麼作擴容?

  • 若是Redis被當作緩存使用,使用一致性哈希實現動態擴容縮容。
  • 若是Redis被當作一個持久化存儲使用,必須使用固定的keys-to-nodes映射關係,節點的數量一旦肯定不能變化。不然的話(即Redis節點須要動態變化的狀況),必須使用能夠在運行時進行數據再平衡的一套系統,而當前只有Redis集羣能夠作到這樣。

過時鍵的刪除策略

Redis的過時鍵的刪除策略

咱們都知道,Redis是key-value數據庫,咱們能夠設置Redis中緩存的key的過時時間。Redis的過時策略就是指當Redis中緩存的key過時了,Redis如何處理。

過時策略一般有如下三種:

  • 定時過時:每一個設置過時時間的key都須要建立一個定時器,到過時時間就會當即清除。該策略能夠當即清除過時的數據,對內存很友好;可是會佔用大量的CPU資源去處理過時的數據,從而影響緩存的響應時間和吞吐量。
  • 惰性過時:只有當訪問一個key時,纔會判斷該key是否已過時,過時則清除。該策略能夠最大化地節省CPU資源,卻對內存很是不友好。極端狀況可能出現大量的過時key沒有再次被訪問,從而不會被清除,佔用大量內存。
  • 按期過時:每隔必定的時間,會掃描必定數量的數據庫的expires字典中必定數量的key,並清除其中已過時的key。該策略是前二者的一個折中方案。經過調整定時掃描的時間間隔和每次掃描的限定耗時,能夠在不一樣狀況下使得CPU和內存資源達到最優的平衡效果。

(expires字典會保存全部設置了過時時間的key的過時時間數據,其中,key是指向鍵空間中的某個鍵的指針,value是該鍵的毫秒精度的UNIX時間戳表示的過時時間。鍵空間是指該Redis集羣中保存的全部鍵。)

Redis中同時使用了惰性過時和按期過時兩種過時策略。

Redis key的過時時間和永久有效分別怎麼設置?

EXPIRE和PERSIST命令。

咱們知道經過expire來設置key 的過時時間,那麼對過時的數據怎麼處理呢?

除了緩存服務器自帶的緩存失效策略以外(Redis默認的有6中策略可供選擇),咱們還能夠根據具體的業務需求進行自定義的緩存淘汰,常見的策略有兩種:

  • 定時去清理過時的緩存;
  • 當有用戶請求過來時,再判斷這個請求所用到的緩存是否過時,過時的話就去底層系統獲得新數據並更新緩存。

二者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效,邏輯相對比較複雜!具體用哪一種方案,你們能夠根據本身的應用場景來權衡。

內存相關

MySQL裏有2000w數據,redis中只存20w的數據,如何保證redis中的數據都是熱點數據

redis內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略。

Redis的內存淘汰策略有哪些

Redis的內存淘汰策略是指在Redis的用於緩存的內存不足時,怎麼處理須要新寫入且須要申請額外空間的數據。

全局的鍵空間選擇性移除

  • noeviction:當內存不足以容納新寫入數據時,新寫入操做會報錯。
  • allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。(這個是最經常使用的)
  • allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。

設置過時時間的鍵空間選擇性移除

  • volatile-lru:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,移除最近最少使用的key。
  • volatile-random:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,隨機移除某個key。
  • volatile-ttl:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,有更早過時時間的key優先移除。

總結

Redis的內存淘汰策略的選取並不會影響過時的key的處理。內存淘汰策略用於處理內存不足時的須要申請額外空間的數據;過時策略用於處理過時的緩存數據。

Redis主要消耗什麼物理資源?

內存。

Redis的內存用完了會發生什麼?

若是達到設置的上限,Redis的寫命令會返回錯誤信息(可是讀命令還能夠正常返回。)或者你能夠配置內存淘汰機制,當Redis達到內存上限時會沖刷掉舊的內容。

Redis如何作內存優化?

能夠好好利用Hash,list,sorted set,set等集合類型數據,由於一般狀況下不少小的Key-Value能夠用更緊湊的方式存放到一塊兒。儘量使用散列表(hashes),散列表(是說散列表裏面存儲的數少)使用的內存很是小,因此你應該儘量的將你的數據模型抽象到一個散列表裏面。好比你的web系統中有一個用戶對象,不要爲這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶的全部信息存儲到一張散列表裏面

線程模型

Redis線程模型

Redis基於Reactor模式開發了網絡事件處理器,這個處理器被稱爲文件事件處理器(file event handler)。它的組成結構爲4部分:多個套接字、IO多路複用程序、文件事件分派器、事件處理器。由於文件事件分派器隊列的消費是單線程的,因此Redis才叫單線程模型。

  • 文件事件處理器使用 I/O 多路複用(multiplexing)程序來同時監聽多個套接字, 並根據套接字目前執行的任務來爲套接字關聯不一樣的事件處理器。
  • 當被監聽的套接字準備好執行鏈接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操做時, 與操做相對應的文件事件就會產生, 這時文件事件處理器就會調用套接字以前關聯好的事件處理器來處理這些事件。

雖然文件事件處理器以單線程方式運行, 但經過使用 I/O 多路複用程序來監聽多個套接字, 文件事件處理器既實現了高性能的網絡通訊模型, 又能夠很好地與 redis 服務器中其餘一樣以單線程方式運行的模塊進行對接, 這保持了 Redis 內部單線程設計的簡單性。

事務

什麼是事務?

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

事務是一個原子操做:事務中的命令要麼所有被執行,要麼所有都不執行。

Redis事務的概念

Redis 事務的本質是經過MULTI、EXEC、WATCH等一組命令的集合。事務支持一次執行多個命令,一個事務中全部命令都會被序列化。在事務執行過程,會按照順序串行化執行隊列中的命令,其餘客戶端提交的命令請求不會插入到事務執行命令序列中。

總結說:redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列命令。

Redis事務的三個階段

  • 事務開始 MULTI
  • 命令入隊
  • 事務執行 EXEC

事務執行過程當中,若是服務端收到有EXEC、DISCARD、WATCH、MULTI以外的請求,將會把請求放入隊列中排隊

Redis事務相關命令

Redis事務功能是經過MULTI、EXEC、DISCARD和WATCH 四個原語實現的

Redis會將一個事務中的全部命令序列化,而後按順序執行。

  • redis 不支持回滾,「Redis 在事務失敗時不進行回滾,而是繼續執行餘下的命令」, 因此 Redis 的內部能夠保持簡單且快速。
  • 若是在一個事務中的命令出現錯誤,那麼全部的命令都不會執行;
  • 若是在一個事務中出現運行錯誤,那麼正確的命令會被執行。
  • WATCH 命令是一個樂觀鎖,能夠爲 Redis 事務提供 check-and-set (CAS)行爲。能夠監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),以後的事務就不會執行,監控一直持續到EXEC命令。
  • MULTI命令用於開啓一個事務,它老是返回OK。MULTI執行以後,客戶端能夠繼續向服務器發送任意多條命令,這些命令不會當即被執行,而是被放到一個隊列中,當EXEC命令被調用時,全部隊列中的命令纔會被執行。
  • EXEC:執行全部事務塊內的命令。返回事務塊內全部命令的返回值,按命令執行的前後順序排列。當操做被打斷時,返回空值 nil 。
  • 經過調用DISCARD,客戶端能夠清空事務隊列,並放棄執行事務, 而且客戶端會從事務狀態中退出。
  • UNWATCH命令能夠取消watch對全部key的監控。

事務管理(ACID)概述

原子性(Atomicity)

原子性是指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生。

一致性(Consistency)

事務先後數據的完整性必須保持一致。

隔離性(Isolation)

多個事務併發執行時,一個事務的執行不該影響其餘事務的執行。

持久性(Durability)

持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即便數據庫發生故障也不該該對其有任何影響

Redis的事務老是具備ACID中的一致性和隔離性,其餘特性是不支持的。當服務器運行在AOF持久化模式下,而且appendfsync選項的值爲always時,事務也具備耐久性。

Redis事務支持隔離性嗎

Redis 是單進程程序,而且它保證在執行事務時,不會對事務進行中斷,事務能夠運行直到執行完全部事務隊列中的命令爲止。所以,Redis 的事務是老是帶有隔離性的。

Redis事務保證原子性嗎,支持回滾嗎

Redis中,單條命令是原子性執行的,但事務不保證原子性,且沒有回滾。事務中任意命令執行失敗,其他的命令仍會被執行。

Redis事務其餘實現

  • 基於Lua腳本,Redis能夠保證腳本內的命令一次性、按順序地執行,其同時也不提供事務運行錯誤的回滾,執行過程當中若是部分命令運行錯誤,剩下的命令仍是會繼續運行完
  • 基於中間標記變量,經過另外的標記變量來標識事務是否執行完成,讀取數據時先讀取該標記變量判斷是否事務執行完成。但這樣會須要額外寫代碼實現,比較繁瑣

集羣方案

哨兵模式

哨兵的介紹

sentinel,中文名是哨兵。哨兵是 redis 集羣機構中很是重要的一個組件,主要有如下功能:

  • 集羣監控:負責監控 redis master 和 slave 進程是否正常工做。
  • 消息通知:若是某個 redis 實例有故障,那麼哨兵負責發送消息做爲報警通知給管理員。
  • 故障轉移:若是 master node 掛掉了,會自動轉移到 slave node 上。
  • 配置中心:若是故障轉移發生了,通知 client 客戶端新的 master 地址。

哨兵用於實現 redis 集羣的高可用,自己也是分佈式的,做爲一個哨兵集羣去運行,互相協同工做。

  • 故障轉移時,判斷一個 master node 是否宕機了,須要大部分的哨兵都贊成才行,涉及到了分佈式選舉的問題。
  • 即便部分哨兵節點掛掉了,哨兵集羣仍是能正常工做的,由於若是一個做爲高可用機制重要組成部分的故障轉移系統自己是單點的,那就很坑爹了。

哨兵的核心知識

  • 哨兵至少須要 3 個實例,來保證本身的健壯性。
  • 哨兵 + redis 主從的部署架構,是不保證數據零丟失的,只能保證 redis 集羣的高可用性。
  • 對於哨兵 + redis 主從這種複雜的部署架構,儘可能在測試環境和生產環境,都進行充足的測試和演練。

官方Redis Cluster 方案(服務端路由查詢)

redis 集羣模式的工做原理能說一下麼?在集羣模式下,redis 的 key 是如何尋址的?分佈式尋址都有哪些算法?瞭解一致性 hash 算法嗎?

簡介

Redis Cluster是一種服務端Sharding技術,3.0版本開始正式提供。Redis Cluster並無使用一致性hash,而是採用slot(槽)的概念,一共分紅16384個槽。將請求發送到任意節點,接收到請求的節點會將查詢請求發送到正確的節點上執行

方案說明

  • 經過哈希的方式,將數據分片,每一個節點均分存儲必定哈希槽(哈希值)區間的數據,默認分配了16384 個槽位
  • 每份數據分片會存儲在多個互爲主從的多節點上
  • 數據寫入先寫主節點,再同步到從節點(支持配置爲阻塞同步)
  • 同一分片多個節點間的數據不保持一致性
  • 讀取數據時,當客戶端操做的key沒有分配在該節點上時,redis會返回轉向指令,指向正確的節點
  • 擴容時時須要須要把舊節點的數據遷移一部分到新節點

在 redis cluster 架構下,每一個 redis 要放開兩個端口號,好比一個是 6379,另一個就是 加1w 的端口號,好比 16379。

16379 端口號是用來進行節點間通訊的,也就是 cluster bus 的東西,cluster bus 的通訊,用來進行故障檢測、配置更新、故障轉移受權。cluster bus 用了另一種二進制的協議,gossip 協議,用於節點間進行高效的數據交換,佔用更少的網絡帶寬和處理時間。

節點間的內部通訊機制

基本通訊原理

集羣元數據的維護有兩種方式:集中式、Gossip 協議。redis cluster 節點間採用 gossip 協議進行通訊。

分佈式尋址算法

  • hash 算法(大量緩存重建)
  • 一致性 hash 算法(自動緩存遷移)+ 虛擬節點(自動負載均衡)
  • redis cluster 的 hash slot 算法

優勢

  • 無中心架構,支持動態擴容,對業務透明
  • 具有Sentinel的監控和自動Failover(故障轉移)能力
  • 客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可
  • 高性能,客戶端直連redis服務,免去了proxy代理的損耗

缺點

  • 運維也很複雜,數據遷移須要人工干預
  • 只能使用0號數據庫
  • 不支持批量操做(pipeline管道操做)
  • 分佈式邏輯和存儲模塊耦合等

基於客戶端分配

簡介

Redis Sharding是Redis Cluster出來以前,業界廣泛使用的多Redis實例集羣方法。其主要思想是採用哈希算法將Redis數據的key進行散列,經過hash函數,特定的key會映射到特定的Redis節點上。Java redis客戶端驅動jedis,支持Redis Sharding功能,即ShardedJedis以及結合緩存池的ShardedJedisPool

優勢

優點在於很是簡單,服務端的Redis實例彼此獨立,相互無關聯,每一個Redis實例像單服務器同樣運行,很是容易線性擴展,系統的靈活性很強

缺點

因爲sharding處理放到客戶端,規模進一步擴大時給運維帶來挑戰。

客戶端sharding不支持動態增刪節點。服務端Redis實例羣拓撲結構有變化時,每一個客戶端都須要更新調整。鏈接不能共享,當應用規模增大時,資源浪費制約優化

基於代理服務器分片

簡介

客戶端發送請求到一個代理組件,代理解析客戶端的數據,並將請求轉發至正確的節點,最後將結果回覆給客戶端

特徵

  • 透明接入,業務程序不用關心後端Redis實例,切換成本低
  • Proxy 的邏輯和存儲的邏輯是隔離的
  • 代理層多了一次轉發,性能有所損耗

業界開源方案

  • Twtter開源的Twemproxy
  • 豌豆莢開源的Codis

Redis 主從架構

單機的 redis,可以承載的 QPS 大概就在上萬到幾萬不等。對於緩存來講,通常都是用來支撐讀高併發的。所以架構作成主從(master-slave)架構,一主多從,主負責寫,而且將數據複製到其它的 slave 節點,從節點負責讀。全部的讀請求所有走從節點。這樣也能夠很輕鬆實現水平擴容,支撐讀高併發。

redis replication -> 主從架構 -> 讀寫分離 -> 水平擴容支撐讀高併發

redis replication 的核心機制

  • redis 採用異步方式複製數據到 slave 節點,不過 redis2.8 開始,slave node 會週期性地確認本身每次複製的數據量;
  • 一個 master node 是能夠配置多個 slave node 的;
  • slave node 也能夠鏈接其餘的 slave node;
  • slave node 作複製的時候,不會 block master node 的正常工做;
  • slave node 在作複製的時候,也不會 block 對本身的查詢操做,它會用舊的數據集來提供服務;可是複製完成的時候,須要刪除舊數據集,加載新數據集,這個時候就會暫停對外服務了;
  • slave node 主要用來進行橫向擴容,作讀寫分離,擴容的 slave node 能夠提升讀的吞吐量。

注意,若是採用了主從架構,那麼建議必須開啓 master node 的持久化,不建議用 slave node 做爲 master node 的數據熱備,由於那樣的話,若是你關掉 master 的持久化,可能在 master 宕機重啓的時候數據是空的,而後可能一通過複製, slave node 的數據也丟了。

另外,master 的各類備份方案,也須要作。萬一本地的全部文件丟失了,從備份中挑選一份 rdb 去恢復 master,這樣才能確保啓動的時候,是有數據的,即便採用了後續講解的高可用機制,slave node 能夠自動接管 master node,但也可能 sentinel 還沒檢測到 master failure,master node 就自動重啓了,仍是可能致使上面全部的 slave node 數據被清空。

redis 主從複製的核心原理

當啓動一個 slave node 的時候,它會發送一個 PSYNC 命令給 master node。

若是這是 slave node 初次鏈接到 master node,那麼會觸發一次 full resynchronization 全量複製。此時 master 會啓動一個後臺線程,開始生成一份 RDB 快照文件,

同時還會將從客戶端 client 新收到的全部寫命令緩存在內存中。RDB 文件生成完畢後, master 會將這個 RDB 發送給 slave,slave 會先寫入本地磁盤,而後再從本地磁盤加載到內存中,

接着 master 會將內存中緩存的寫命令發送到 slave,slave 也會同步這些數據。

slave node 若是跟 master node 有網絡故障,斷開了鏈接,會自動重連,鏈接以後 master node 僅會複製給 slave 部分缺乏的數據。

過程原理

  • 當從庫和主庫創建MS關係後,會向主數據庫發送SYNC命令
  • 主庫接收到SYNC命令後會開始在後臺保存快照(RDB持久化過程),並將期間接收到的寫命令緩存起來
  • 當快照完成後,主Redis會將快照文件和全部緩存的寫命令發送給從Redis
  • 從Redis接收到後,會載入快照文件而且執行收到的緩存的命令
  • 以後,主Redis每當接收到寫命令時就會將命令發送從Redis,從而保證數據的一致

缺點

全部的slave節點數據的複製和同步都由master節點來處理,會照成master節點壓力太大,使用主從從結構來解決

Redis集羣的主從複製模型是怎樣的?

爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有N-1個複製品

生產環境中的 redis 是怎麼部署的?

redis cluster,10 臺機器,5 臺機器部署了 redis 主實例,另外 5 臺機器部署了 redis 的從實例,每一個主實例掛了一個從實例,5 個節點對外提供讀寫服務,每一個節點的讀寫高峯qps可能能夠達到每秒 5 萬,5 臺機器最可能是 25 萬讀寫請求/s。

機器是什麼配置?32G 內存+ 8 核 CPU + 1T 磁盤,可是分配給 redis 進程的是10g內存,通常線上生產環境,redis 的內存儘可能不要超過 10g,超過 10g 可能會有問題。

5 臺機器對外提供讀寫,一共有 50g 內存。

由於每一個主實例都掛了一個從實例,因此是高可用的,任何一個主實例宕機,都會自動故障遷移,redis 從實例會自動變成主實例繼續提供讀寫服務。

你往內存裏寫的是什麼數據?每條數據的大小是多少?商品數據,每條數據是 10kb。100 條數據是 1mb,10 萬條數據是 1g。常駐內存的是 200 萬條商品數據,佔用內存是 20g,僅僅不到總內存的 50%。目前高峯期每秒就是 3500 左右的請求量。

其實大型的公司,會有基礎架構的 team 負責緩存集羣的運維。

說說Redis哈希槽的概念?

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

Redis集羣會有寫操做丟失嗎?爲何?

Redis並不能保證數據的強一致性,這意味這在實際中集羣在特定的條件下可能會丟失寫操做。

Redis集羣之間是如何複製的?

異步複製

Redis集羣最大節點個數是多少?

16384個

Redis集羣如何選擇數據庫?

Redis集羣目前沒法作數據庫選擇,默認在0數據庫。

分區

Redis是單線程的,如何提升多核CPU的利用率?

能夠在同一個服務器部署多個Redis的實例,並把他們看成不一樣的服務器來使用,在某些時候,不管如何一個服務器是不夠的, 因此,若是你想使用多個CPU,你能夠考慮一下分片(shard)。

爲何要作Redis分區?

分區可讓Redis管理更大的內存,Redis將能夠使用全部機器的內存。若是沒有分區,你最多隻能使用一臺機器的內存。分區使Redis的計算能力經過簡單地增長計算機獲得成倍提高,Redis的網絡帶寬也會隨着計算機和網卡的增長而成倍增加。

你知道有哪些Redis分區實現方案?

  • 客戶端分區就是在客戶端就已經決定數據會被存儲到哪一個redis節點或者從哪一個redis節點讀取。大多數客戶端已經實現了客戶端分區。
  • 代理分區 意味着客戶端將請求發送給代理,而後代理決定去哪一個節點寫數據或者讀數據。代理根據分區規則決定請求哪些Redis實例,而後根據Redis的響應結果返回給客戶端。redis和memcached的一種代理實現就是Twemproxy
  • 查詢路由(Query routing) 的意思是客戶端隨機地請求任意一個redis實例,而後由Redis將請求轉發給正確的Redis節點。Redis Cluster實現了一種混合形式的查詢路由,但並非直接將請求從一個redis節點轉發到另外一個redis節點,而是在客戶端的幫助下直接redirected到正確的redis節點。

Redis分區有什麼缺點?

  • 涉及多個key的操做一般不會被支持。例如你不能對兩個集合求交集,由於他們可能被存儲到不一樣的Redis實例(實際上這種狀況也有辦法,可是不能直接使用交集指令)。
  • 同時操做多個key,則不能使用Redis事務.
  • 分區使用的粒度是key,不能使用一個很是長的排序key存儲一個數據集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set)
  • 當使用分區的時候,數據處理會很是複雜,例如爲了備份你必須從不一樣的Redis實例和主機同時收集RDB / AOF文件。
  • 分區時動態擴容或縮容可能很是複雜。Redis集羣在運行時增長或者刪除Redis節點,能作到最大程度對用戶透明地數據再平衡,但其餘一些客戶端分區或者代理分區方法則不支持這種特性。然而,有一種預分片的技術也能夠較好的解決這個問題。

分佈式問題

Redis實現分佈式鎖

Redis爲單進程單線程模式,採用隊列模式將併發訪問變成串行訪問,且多客戶端對Redis的鏈接並不存在競爭關係Redis中能夠使用SETNX命令實現分佈式鎖。

當且僅當 key 不存在,將 key 的值設爲 value。若給定的 key 已經存在,則 SETNX 不作任何動做。

SETNX 是『SET if Not eXists』(若是不存在,則 SET)的簡寫。

返回值:設置成功,返回 1 。設置失敗,返回 0 。

使用SETNX完成同步鎖的流程及事項以下:

使用SETNX命令獲取鎖,若返回0(key已存在,鎖已存在)則獲取失敗,反之獲取成功

爲了防止獲取鎖後程序出現異常,致使其餘線程/進程調用SETNX命令老是返回0而進入死鎖狀態,須要爲該key設置一個「合理」的過時時間。

釋放鎖,使用DEL命令將鎖數據刪除。

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

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

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

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

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

分佈式Redis是前期作仍是後期規模上來了再作好?爲何?

既然Redis是如此的輕量(單實例只使用1M內存),爲防止之後的擴容,最好的辦法就是一開始就啓動較多實例。即使你只有一臺服務器,你也能夠一開始就讓Redis以分佈式的方式運行,使用分區,在同一臺服務器上啓動多個實例。

一開始就多設置幾個Redis實例,例如32或者64個實例,對大多數用戶來講這操做起來可能比較麻煩,可是從長久來看作這點犧牲是值得的。

這樣的話,當你的數據不斷增加,須要更多的Redis服務器時,你須要作的就是僅僅將Redis實例從一臺服務遷移到另一臺服務器而已(而不用考慮從新分區的問題)。一旦你添加了另外一臺服務器,你須要將你一半的Redis實例從第一臺機器遷移到第二臺機器。

什麼是 RedLock

Redis 官方站提出了一種權威的基於 Redis 實現分佈式鎖的方式名叫 Redlock,此種方式比原先的單節點的方法更安全。它能夠保證如下特性:

  • 安全特性:互斥訪問,即永遠只有一個 client 能拿到鎖
  • 避免死鎖:最終 client 均可能拿到鎖,不會出現死鎖的狀況,即便本來鎖住某資源的 client crash 了或者出現了網絡分區
  • 容錯性:只要大部分 Redis 節點存活就能夠正常提供服務

緩存異常

緩存雪崩

緩存雪崩是指緩存同一時間大面積的失效,因此,後面的請求都會落到數據庫上,形成數據庫短期內承受大量請求而崩掉。

解決方案

  • 緩存數據的過時時間設置隨機,防止同一時間大量數據過時現象發生。
  • 通常併發量不是特別多的時候,使用最多的解決方案是加鎖排隊。
  • 給每個緩存數據增長相應的緩存標記,記錄緩存的是否失效,若是緩存標記失效,則更新數據緩存。

緩存穿透

緩存穿透是指緩存和數據庫中都沒有的數據,致使全部的請求都落到數據庫上,形成數據庫短期內承受大量請求而崩掉。

解決方案

  • 接口層增長校驗,如用戶鑑權校驗,id作基礎校驗,id<=0的直接攔截;
  • 從緩存取不到的數據,在數據庫中也沒有取到,這時也能夠將key-value對寫爲key-null,緩存有效時間能夠設置短點,如30秒(設置太長會致使正常狀況也無法使用)。這樣能夠防止攻擊用戶反覆用同一個id暴力攻擊
  • 採用布隆過濾器,將全部可能存在的數據哈希到一個足夠大的 bitmap 中,一個必定不存在的數據會被這個 bitmap 攔截掉,從而避免了對底層存儲系統的查詢壓力

附加

對於空間的利用到達了一種極致,那就是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通常用於在大數據量的集合中斷定某元素是否存在。

緩存擊穿

緩存擊穿是指緩存中沒有但數據庫中有的數據(通常是緩存時間到期),這時因爲併發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引發數據庫壓力瞬間增大,形成過大壓力。和緩存雪崩不一樣的是,緩存擊穿指併發查同一條數據,緩存雪崩是不一樣數據都過時了,不少數據都查不到從而查數據庫。

解決方案

  • 設置熱點數據永遠不過時。
  • 加互斥鎖,互斥鎖

緩存預熱

緩存預熱就是系統上線後,將相關的緩存數據直接加載到緩存系統。這樣就能夠避免在用戶請求的時候,先查詢數據庫,而後再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!

解決方案

  • 直接寫個緩存刷新頁面,上線時手工操做一下;
  • 數據量不大,能夠在項目啓動的時候自動進行加載;
  • 定時刷新緩存;

緩存降級

當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然須要保證服務仍是可用的,即便是有損服務。系統能夠根據一些關鍵數據進行自動降級,也能夠配置開關實現人工降級。

緩存降級的最終目的是保證核心服務可用,即便是有損的。並且有些服務是沒法降級的(如加入購物車、結算)。

在進行降級以前要對系統進行梳理,看看系統是否是能夠丟卒保帥;從而梳理出哪些必須誓死保護,哪些可降級;好比能夠參考日誌級別設置預案:

  • 通常:好比有些服務偶爾由於網絡抖動或者服務正在上線而超時,能夠自動降級;
  • 警告:有些服務在一段時間內成功率有波動(如在95~100%之間),能夠自動降級或人工降級,併發送告警;
  • 錯誤:好比可用率低於90%,或者數據庫鏈接池被打爆了,或者訪問量忽然猛增到系統能承受的最大閥值,此時能夠根據狀況自動降級或者人工降級;
  • 嚴重錯誤:好比由於特殊緣由數據錯誤了,此時須要緊急人工降級。

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

熱點數據和冷數據

熱點數據,緩存纔有價值

對於冷數據而言,大部分數據可能尚未再次訪問到就已經被擠出內存,不只佔用內存,並且價值不大。頻繁修改的數據,看狀況考慮使用緩存

對於熱點數據,好比咱們的某IM產品,生日祝福模塊,當天的壽星列表,緩存之後可能讀取數十萬次。再舉個例子,某導航產品,咱們將導航信息,緩存之後可能讀取數百萬次。

數據更新前至少讀取兩次,緩存纔有意義。這個是最基本的策略,若是緩存尚未起做用就失效了,那就沒有太大價值了。

那存不存在,修改頻率很高,可是又不得不考慮緩存的場景呢?有!好比,這個讀取接口對數據庫的壓力很大,可是又是熱點數據,這個時候就須要考慮經過緩存手段,減小數據庫的壓力,好比咱們的某助手產品的,點贊數,收藏數,分享數等是很是典型的熱點數據,可是又不斷變化,此時就須要將數據同步保存到Redis緩存,減小數據庫壓力。

緩存熱點key

緩存中的一個Key(好比一個促銷商品),在某個時間點過時的時候,剛好在這個時間點對這個Key有大量的併發請求過來,這些請求發現緩存過時通常都會從後端DB加載數據並回設到緩存,這個時候大併發的請求可能會瞬間把後端DB壓垮。

解決方案

對緩存查詢加鎖,若是KEY不存在,就加鎖,而後查DB入緩存,而後解鎖;其餘進程若是發現有鎖就等待,而後等解鎖後返回數據或者進入DB查詢

經常使用工具

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

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

Redis和Redisson有什麼關係?

Redisson是一個高級的分佈式協調Redis客服端,能幫助用戶在分佈式環境中輕鬆實現一些Java的對象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

Jedis與Redisson對比有什麼優缺點?

Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支持;Redisson實現了分佈式和可擴展的Java數據結構,和Jedis相比,功能較爲簡單,不支持字符串操做,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者可以將精力更集中地放在處理業務邏輯上。

其餘問題

Redis與Memcached的區別

二者都是非關係型內存鍵值數據庫,如今公司通常都是用 Redis 來實現緩存,並且 Redis 自身也愈來愈強大了!Redis 與 Memcached 主要有如下不一樣:

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

(2) redis的速度比memcached快不少

(3) redis能夠持久化其數據

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

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

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

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

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

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

  • Master最好不要作任何持久化工做,包括內存快照和AOF日誌文件,特別是不要啓用內存快照作持久化。
  • 若是數據比較關鍵,某個Slave開啓AOF備份數據,策略爲每秒同步一次。
  • 爲了主從複製的速度和鏈接的穩定性,Slave和Master最好在同一個局域網內。
  • 儘可能避免在壓力較大的主庫上增長從庫
  • Master調用BGREWRITEAOF重寫AOF文件,AOF在重寫的時候會佔大量的CPU和內存資源,致使服務load太高,出現短暫服務暫停現象。
  • 爲了Master的穩定性,主從複製不要用圖狀結構,用單向鏈表結構更穩定,即主從關係爲:Master<–Slave1<–Slave2<–Slave3…,這樣的結構也方便解決單點故障問題,實現Slave對Master的替換,也即,若是Master掛了,能夠立馬啓用Slave1作Master,其餘不變。

Redis官方爲何不提供Windows版本?

由於目前Linux版本已經至關穩定,並且用戶量很大,無需開發windows版本,反而會帶來兼容性等問題。

一個字符串類型的值能存儲最大容量是多少?

512M

Redis如何作大量數據插入?

Redis2.6開始redis-cli支持一種新的被稱之爲pipe mode的新模式用於執行大量數據插入工做。

假如Redis裏面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,若是將它們所有找出來?

使用keys指令能夠掃出指定模式的key列表。

對方接着追問:若是這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?

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

使用Redis作過異步隊列嗎,是如何實現的?

使用list類型保存數據信息,rpush生產消息,lpop消費消息,當lpop沒有消息時,能夠sleep一段時間,而後再檢查有沒有信息,若是不想sleep的話,能夠使用blpop, 在沒有信息的時候,會一直阻塞,直到信息的到來。redis能夠經過pub/sub主題訂閱模式實現一個生產者,多個消費者,固然也存在必定的缺點,當消費者下線時,生產的消息會丟失。

Redis如何實現延時隊列?

使用sortedset,使用時間戳作score, 消息內容做爲key,調用zadd來生產消息,消費者使用zrangbyscore獲取n秒以前的數據作輪詢處理。

Redis回收進程如何工做的?

一個客戶端運行了新的命令,添加了新的數據。

Redis檢查內存使用狀況,若是大於maxmemory的限制, 則根據設定好的策略進行回收。

一個新的命令被執行,等等。

因此咱們不斷地穿越內存限制的邊界,經過不斷達到邊界而後不斷地回收回到邊界如下。

若是一個命令的結果致使大量內存被使用(例如很大的集合的交集保存到一個新的鍵),不用多久內存限制就會被這個內存使用量超越。

Redis回收使用的是什麼算法?

LRU算法

相關文章
相關標籤/搜索