您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關關于redis緩存的面試題有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
區別:
memcached可緩存圖片和視頻。redis支持除k/v更多的數據結構;
redis可以使用虛擬內存,redis可持久化和aof災難恢復,redis通過主從支持數據備份;
3.redis可以做消息隊列。
原因:memcached多線程模型引入了緩存一致性和鎖,加鎖帶來了性能損耗。
主從復制實現:主節點將自己內存中的數據做一份快照,將快照發給從節點,從節點將數據恢復到內存中。之后再每次增加新數據的時候,主節點以類似于mysql的二進制日志方式將語句發送給從節點,從節點拿到主節點發送過來的語句進行重放。
分片方式:
客戶端分片
基于代理的分片
Twemproxy
codis
路由查詢分片
Redis-cluster體身提供了自動將數據分散到RedisCluster不同節點的能力,整個數據集合的某個數據子集存儲在哪個節點對于用戶來說是透明的)
redis-cluster分片原理:Cluster中有一個16384長度的槽(虛擬槽),編號分別為0-16383。每個Master節點都會負責一部分的槽,當有某個key被映射到某個Master負責的槽,那么這個Master負責為這個key提供服務,至于哪個Master節點負責哪個槽,可以由用戶指定,也可以在初始化的時候自動生成,只有Master才擁有槽的所有權。Master節點維護著一個16384/8字節的位序列,Master節點用bit來標識對于某個槽自己是否擁有。比如對于編號為1的槽,Master只要判斷序列的第二位(索引從0開始)是不是為1即可。這種結構很容易添加或者刪除節點。比如如果我想新添加個節點D,我需要從節點A、B、C中得部分槽到D上。
【相關推薦:Redis視頻教程】
redis:
線程Asetnx(上鎖的對象超時時的時間戳tl),如果返回true,獲得鎖。
線程B用get獲取t1,與當前時間戳比較,判斷是是否超時,沒超時false,若超時執行第3步;
計算新的超時時間t2,使用getset命令返回t3(該值可能其他線程已經修改過),如果t1==t3,獲得鎖,如果t1!=t3說明鎖被其他線程獲取了。
獲取鎖后,處理完業務邏輯,再去判斷鎖是否超時,如果沒超時刪除鎖,如果已超時,不用處理(防止刪除其他線程的鎖)。
zk:
客戶端對某個方法加鎖時,在zk上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點node1;
客戶端獲取該路徑下所有已經創建的子節點,如果發現自己創建的node1的序號是最小的,就認為這個客戶端獲得了鎖。
如果發現node1不是最小的,則監聽比自己創建節點序號小的最大的節點,進入等待。
獲取鎖后,處理完邏輯,刪除自己創建的node1即可。區別:zk性能差一些,開銷大,實現簡單。
RDB(RedisDataBase:在不同的時間點將redis的數據生成的快照同步到磁盤等介質上):內存到硬盤的快照,定期更新。缺點:耗時,耗性能(fork+io操作),易丟失數據。
AOF(AppendOnlyFile:將redis所執行過的所有指令都記錄下來,在下次redis重啟時,只需要執行指令就可以了):寫日志。缺點:體積大,恢復速度慢。
bgsave做鏡像全量持久化,aof做增量持久化。因為bgsave會消耗比較長的時間,不夠實時,在停機的時候會導致大量的數據丟失,需要aof來配合,在redis實例重啟時,優先使用aof來恢復內存的狀態,如果沒有aof日志,就會使用rdb文件來恢復。Redis會定期做aof重寫,壓縮aof文件日志大小。Redis4.0之后有了混合持久化的功能,將bgsave的全量和aof的增量做了融合處理,這樣既保證了恢復的效率又兼顧了數據的安全性。bgsave的原理,fork和cow,fork是指redis通過創建子進程來進行bgsave操作,cow指的是copyonwrite,子進程創建后,父子進程共享數據段,父進程繼續提供讀寫服務,寫臟的頁面數據會逐漸和子進程分囲開來。
過期策略:
定時過期(一key一定時器),惰性過期:只有使用key時才判斷key是否已過期,過期則清除。定期過期:前兩者折中。
LRU:newLinkedHashMap<K,V>(capacity,DEFAULT_LOAD_FACTORY,true);第三個參數置為true,代表linkedlist按訪問順序排序,可作為LRU緩存;設為false代表按插入順序排序,可作為FIFO緩存
LRU算法實現:
通過雙向鏈表來實現,新數據插入到鏈表頭部;
每當緩存命中(即緩存數據被訪問),則將數據移到鏈表頭部;
當鏈表滿的時候,將鏈表尾部的數據丟棄。
LinkedHashMap:HashMap和雙向鏈表合二為一即是LinkedHashMap。HashMap是無序的,LinkedHashMap通過維護一個額外的雙向鏈表保證了迭代順序。該迭代順序可以是插入順序(默認),也可以是訪問順序。
**緩存穿透:**指查詢一個一定不存在的數據,如果從存儲層查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到DB去查詢,可能導致DB掛掉。
解決方案:
查詢返回的數據為空,仍把這個空結果進行緩存,但過期時間會比較短;
布隆過濾器:將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被這個bitmap攔截掉,從而避免了對DB的查詢。
**緩存擊穿:**對于設置了過期時間的key,緩存在某個時間點過期的時候,恰好這時間點對這個Key有大量的并發請求過來,這些請求發現緩存過期一般都會從后端DB加載數據并回設到緩存,這個時候大并發的請求可能會瞬間把DB壓垮。
解決方案:
使用互斥鎖:當緩存失效時,不立即去Ioaddb,先使用如Redis的setnx去設置一個互斥鎖,當操作成功返回時再進行Ioaddb的操作并回設緩存,否則重試get緩存的方法。
永遠不過期:物理不過期,但邏輯過期(后臺異步線程去刷新)。緩存雪崩:設置緩存時采用了相同的過期時間,導致緩存在某一時刻同時失效,請求全部轉發到DB,DB瞬時壓力過重雪崩。與緩存擊穿的區別:雪崩是很多key,擊穿是某一個key緩存。
解決方案:
將緩存失效時間分散開,比如可以在原有的失效時間基礎上增加一個隨機值,比如1-5分鐘隨機,這樣每一個緩存的過期時間的重復率就會降低,就很難引發集體失效的事件。
選擇redis的情況:
復雜數據結構,value的數據是哈希,列表,集合,有序集合等這種情況下,會選擇redis,因為memcache無法滿足這些數據結構,最典型的的使用場景是,用戶訂單列表,用戶消息,帖子評論等。
需要進行數據的持久化功能,但是注意,不要把redis當成數據庫使用,如果redis掛了,內存能夠快速恢復熱數據,不會將壓力瞬間壓在數據庫上,沒有cache預熱的過程。對于只讀和數據一致性要求不高的場景可以采用持久化存儲
高可用,redis支持集群,可以實現主動復制,讀寫分離,而對于memcache如果想要實現高可用,需要進行二次開發。
存儲的內容比較大,memcache存儲的value最大為1M。
選擇memcache的場景:
純KV,數據量非常大的業務,使用memcache更合適,原因是:
memcache的內存分配采用的是預分配內存池的管理方式,能夠省去內存分配的時間,redis是臨時申請空間,可能導致碎片化。
虛擬內存使用,memcache將所有的數據存儲在物理內存里,redis有自己的vm機制,理論上能夠存儲比物理內存更多的數據,當數據超量時,引發swap,把冷數據刷新到磁盤上,從這點上,數據量大時,memcache更快
網絡模型,memcache使用非阻塞的10復用模型,redis也是使用非阻塞的I。復用模型,但是redis還提供了一些非KV存儲之外的排序,聚合功能,復雜的CPU計算,會阻塞整個I0調度,從這點上由于redis提供的功能較多,memcache更快些
線程模型,memcache使用多線程,主線程監聽,worker子線程接受請求,執行讀寫,這個過程可能存在鎖沖突。redis使用的單線程,雖然無鎖沖突,但是難以利用多核的特性提升吞吐量。
假設采用的主存分離,讀寫分離的數據庫,
如果一個線程A先刪除緩存數據,然后將數據寫入到主庫當中,這個時候,主庫和從庫同步沒有完成,線程B從緩存當中讀取數據失敗,從從庫當中讀取到舊數據,然后更新至緩存,這個時候,緩存當中的就是舊的數據。
發生上述不一致的原因在于,主從庫數據不一致問題,加入了緩存之后,主從不一致的時間被拉長了。
處理思路:在從庫有數據更新之后,將緩存當中的數據也同時進行更新,即當從庫發生了數據更新之后,向緩存發出刪除,淘汰這段時間寫入的舊數據。
場景描述,對于主從庫,讀寫分離,如果主從庫更新同步有時差,就會導致主從庫數據的不一致
忽略這個數據不一致,在數據一致性要求不高的業務下,未必需要時時一致性
強制讀主庫,使用一個高可用的主庫,數據庫讀寫都在主庫,添加一個緩存,提升數據讀取的性能。
選擇性讀主庫,添加一個緩存,用來記錄必須讀主庫的數據,將哪個庫,哪個表,哪個主鍵,作為緩存的key,設置緩存失效的時間為主從庫同步的時間,如果緩存當中有這個數據,直接讀取主庫,如果緩存當中沒有這個主鍵,就到對應的從庫中讀取。
master最好不要做持久化工作,如RDB內存快照和AOF日志文件
如果數據比較重要,某個slave開啟AOF備份,策略設置成每秒同步一次
為了主從復制的速度和連接的穩定性,master和Slave最好在一個局域網內
盡量避免在壓力大得主庫上增加從庫
主從復制不要米用網狀結構,盡量是線性結構,Master<–Slave1<—Slave2…
voltile-lru從已經設置過期時間的數據集中挑選最近最少使用的數據淘汰
voltile-ttl從已經設置過期時間的數據庫集當中挑選將要過期的數據
voltile-random從已經設置過期時間的數據集任意選擇淘汰數據
allkeys-lru從數據集中挑選最近最少使用的數據淘汰
allkeys-random從數據集中任意選擇淘汰的數據
no-eviction禁止驅逐數據
字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。如果是咼級用戶,那么還會有,如果你是Redis中高級用戶,還需要加上下面幾種數據結構HyperLogLog、Geo、Pub/Sub。
使用keys指令可以掃出指定模式的key列表。
對方接著追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什么問題?
這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重復概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
使用list類型保存數據信息,rpush生產消息,lpop消費消息,當lpop沒有消息時,可以sleep一段時間,然后再檢查有沒有信息,如果不想sleep的話,可以使用blpop,在沒有信息的時候,會一直阻塞,直到信息的到來。redis可以通過pub/sub主題訂閱模式實現一個生產者,多個消費者,當然也存在一定的缺點,當消費者下線時,生產的消息會丟失。
使用sortedset,使用時間戳做score,消息內容作為key,調用zadd來生產消息,消費者使用zrangbyscore獲取n秒之前的數據做輪詢處理。
Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據flush到硬盤上進行保存。
因為是純內存操作,Redis的性能非常出色,每秒可以處理超過10萬次讀寫操作,是已知性能最快的Key-ValueDB。
Redis的出色之處不僅僅是性能,Redis最大的魅力是支持保存多種數據
結構,此外單個value的最大限制是1GB,不像memcached只能保存1MB的數據,因此Redis可以用來實現很多有用的功能。
比方說用他的List來做FIFO雙向鏈表,實現一個輕量級的高性能消息隊列服務,用他的Set可以做高性能的tag系統等等。
另外Redis也可以對存入的Key-Value設置expire時間,因此也可以被當作一個功能加強版的memcached來用。Redis的主要缺點是數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis適合的場景主要局限在較小數據量的高性能操作和運算上。
memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富數據類型
Redis的速度比memcached快很多
redis可以持久化其數據
String、List、Set、SortedSet、hashes
內存。
Remote Dictionary Server
noeviction:返回錯誤當內存限制達到并且客戶端嘗試執行會讓更多內存被使用的命令(大部分的寫入指令,但DEL和幾個例外)
allkeys-lru:嘗試回收最少使用的鍵(LRU),使得新添加的數據有空間存放。
volatile-lru:嘗試回收最少使用的鍵(LRU),但僅限于在過期集合的鍵,使得新添加的數據有空間存放。
allkeys-random:回收隨機的鍵使得新添加的數據有空間存放。
volatile-random:回收隨機的鍵使得新添加的數據有空間存放,但僅限于在過期集合的鍵。
volatile-ttl:回收在過期集合的鍵,并且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
因為目前Linux版本已經相當穩定,而且用戶量很大,無需開發windows版本,反而會帶來兼容性等問題。
512M
Redis為了達到最快的讀寫速度將數據都讀到內存中,并通過異步的方式將數據寫入磁盤。
所以redis具有快速和數據持久化的特征。如果不將數據放在內存中,磁盤I/O速度為嚴重影響redis的性能。
在內存越來越便宜的今天,redis將會越來越受歡迎。如果設置了最大使用的內存,則數據已有記錄數達到內存限值后不能繼續插入新值。
codis。
目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在節點數量改變情況下,舊節點數據可恢復到新hash節點。
rediscluster3.0自帶的集群,特點在于他的分布式算法不是一致性hash,而是hash槽的概念,以及自身支持節點設置從節點。具體看官方文檔介紹。
在業務代碼層實現,起幾個毫無關聯的redis實例,在代碼層,對key進行hash計算,然后去對應的redis實例操作數據。這種方式對hash層代碼要求比較高,考慮部分包括,節點失效后的替代算法方案,數據震蕩后的自動腳本恢復,實例的監控,等等。
有A,B,C三個節點的集群,在沒有復制模型的情況下,如果節點B失敗了,那么整個集群就會以為缺少5501-11000這個范圍的槽而不可用。
redis內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。
會話緩存(SessionCache)
最常用的一種使用Redis的情景是會話緩存(sessioncache)。用Redis緩存會話比其他存儲(如Memcached)的優勢在于:Redis提供持久化。當維護一個不是嚴格要求一致性的緩存時,如果用戶的購物車信息全部丟失,大部分人都會不高興的,現在,他們還會這樣嗎?
幸運的是,隨著Redis這些年的改進,很容易找到怎么恰當的使用Redis來緩存會話的文檔。甚至廣為人知的商業平臺Magento也提供Redis的插件。
全頁緩存(FPC)
除基本的會話token之外,Redis還提供很簡便的FPC平臺。回到一致性問題,即使重啟了Redis實例,因為有磁盤的持久化,用戶也不會看到頁面加載速度的下降,這是一個極大改進,類似PHP本地FPC。
再次以Magento為例,Magento提供一個插件來使用Redis作為全頁緩存后端。
此外,對WordPress的用戶來說,Pantheon有一個非常好的插件wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
隊列
Reids在內存存儲引擎領域的一大優點是提供list和set操作,這使得Redis能作為一個很好的消息隊列平臺來使用。Redis作為隊列使用的操作,就類似于本地程序語言(如Python)對list的push/pop操作。
如果你快速的在Google中搜索"Redisqueues",你馬上就能找到大量的開源項目,這些項目的目的就是利用Redis創建非常好的后端工具,以滿足各種隊列需求。例如,Celery有一個后臺就是使用Redis作為broker,你可以從這里去查看。
排行榜/計數器
Redis在內存中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(SortedSet)也使得我們在執行這些操作的時候變的非常簡單,Redis只是正好提供了這兩種數據結構。所以,我們要從排序集合中獲取到排名最靠前的10個用戶-我們稱之為“user_scores”,我們只需要像下面一樣執行即可:
當然,這是假定你是根據你用戶的分數做遞增的排序。如果你想返回用戶及用戶的分數,你需要這樣執行:
ZRANGEuser_scores010WITHSCORES
AgoraGames就是一個很好的例子,用Ruby實現的,它的排行榜就是使用Redis來存儲數據的,你可以在這里看到。
發布/訂閱
最后(但肯定不是最不重要的)是Redis的發布/訂閱功能。發布/訂閱的使用場景確實非常多。我已看見人們在社交網絡連接中使用,還可作為基于發布/訂閱的腳本觸發器,甚至用Redis的發布/訂閱功能來建立聊天系統!
Redisson、Jedis、lettuce等等,官方推薦使用Redisson。
Redisson是一個高級的分布式協調Redis客服端,能幫助用戶在分布式環境中輕松實現一些Java的對象(Bloomfilter,BitSet,Set,SetMultimap,ScoredSortedSet,SortedSet,Map,ConcurrentMap,List,ListMultimap,Queue,BlockingQueue,Deque,BlockingDeque,Semaphore,Lock,ReadWriteLock,AtomicLong,CountDownLatch,Publish/Subscribe,HyperLogLog)。
Jedis是Redis的Java實現的客戶端,其API提供了比較全面的Redis命令的支持;
Redisson實現了分布式和可擴展的Java數據結構,和Jedis相比,功能較為簡單,不支持字符串操作,不支持排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,從而讓使用者能夠將精力更集中地放在處理業務邏輯上。
設置密碼:config set require pass 123456 授權密碼:auth223456
Redis集群沒有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽,集群的每個節點負責一部分hash槽。
為了使在部分節點失敗或者大部分節點無法通信的情況下集群仍然可用,所以集群使用了主從復制模型,每個節點都會有N-1個復制品.
Redis并不能保證數據的強一致性,這意味這在實際中集群在特定的條件下可能會丟失寫操作。
異步復制
16384個。
Redis集群目前無法做數據庫選擇,默認在0數據庫。
ping
一次請求/響應服務器能實現處理新的請求即使舊的請求還未被響應。這樣就可以將多個命令發送到服務器,而不用等待回復,最后在一個步驟中讀取該答復。
這就是管道(pipelining),是一種幾十年來廣泛使用的技術。例如許多POP3協議已經實現支持這個功能,大大加快了從服務器下載新郵件的過程。
事務是一個單獨的隔離操作:事務中的所有命令都會序列化、按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。事務是一個原子操作:事務中的命令要么全部被執行,要么全部都不執行。
MULTI、EXEC、DISCARD、WATCH
EXPIRE和PERSIST命令。
盡可能使用散列表(hashes),散列表(是說散列表里面存儲的數少)使用的內存非常小,所以你應該盡可能的將你的數據模型抽象到一個散列表里面。比如你的web系統中有一個用戶對象,不要為這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶的所有信息存儲到一張散列表里面。
一個客戶端運行了新的命令,添加了新的數據。
Redi檢查內存使用情況,如果大于maxmemory的限制,則根據設定好的策略進行回收。一個新的命令被執行,等等。
所以我們不斷地穿越內存限制的邊界,通過不斷達到邊界然后不斷地回收回到邊界以下。
如果一個命令的結果導致大量內存被使用(例如很大的集合的交集保存到一個新的鍵),不用多久內存限制就會被這個內存使用量超越。
關于“關于redis緩存的面試題有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。