1.================================================================================================================================前端
Redis的內存回收主要圍繞如下兩個方面:java
1.Redis過時策略
刪除過時時間的key值mysql
2.Redis淘汰策略
內存使用到達maxmemory上限時觸發內存淘汰數據程序員
Redis的過時策略和內存淘汰策略不是一件事,實際研發中不要弄混淆了,下面會完整的介紹二者。web
過時策略一般有如下三種:面試
1.定時過時redis
每一個設置過時時間的key都須要建立一個定時器,到過時時間就會當即清除。該策略能夠當即清除過時的數據,對內存很友好;可是會佔用大量的CPU資源去處理過時的數據,從而影響緩存的響應時間和吞吐量。算法
2.惰性過時sql
只有當訪問一個key時,纔會判斷該key是否已過時,過時則清除。該策略能夠最大化地節省CPU資源,卻對內存很是不友好。極端狀況可能出現大量的過時key沒有再次被訪問,從而不會被清除,佔用大量內存。數據庫
3.按期過時
每隔必定的時間,會掃描必定數量的數據庫的expires字典中必定數量的key,並清除其中已過時的key。該策略是前二者的一個折中方案。經過調整定時掃描的時間間隔和每次掃描的限定耗時,能夠在不一樣狀況下使得CPU和內存資源達到最優的平衡效果。
Redis中同時使用了惰性過時和按期過時兩種過時策略。
1.簡介
Redis的內存淘汰策略,是指當內存使用達到maxmemory極限時,須要使用LAU淘汰算法來決定清理掉哪些數據,以保證新數據的存入。
二、LRU算法
Redis默認狀況下就是使用LRU策略算法。
LRU算法(least RecentlyUsed),最近最少使用算法,也就是說默認刪除最近最少使用的鍵。
可是必定要注意一點!redis中並不會準確的刪除全部鍵中最近最少使用的鍵,而是隨機抽取3個鍵,刪除這三個鍵中最近最少使用的鍵。
那麼3這個數字也是能夠能夠設置採樣的大小,若是設置爲10,那麼效果會更好,不過也會耗費更多的CPU資源。對應位置是配置文件中的maxmeory-samples。
3.緩存清理配置
maxmemory用來設置redis存放數據的最大的內存大小,一旦超出這個內存大小以後,就會當即使用LRU算法清理掉部分數據。
對於64 bit的機器,若是maxmemory設置爲0,那麼就默認不限制內存的使用,直到耗盡機器中全部的內存爲止;,可是對於32 bit的機器,有一個隱式的閒置就是3GB
4.Redis數據淘汰策略
maxmemory-policy,能夠設置內存達到最大閒置後,採起什麼策略來處理。
對應的淘汰策略規則以下:
高併發架構系列:Redis的內存回收原理,及內存過時淘汰策略詳解
1)noeviction:當內存不足以容納新寫入數據時,新寫入操做會報錯。
2)allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。
3)allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。
4)volatile-lru:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,移除最近最少使用的key。
5)volatile-random:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,隨機移除某個key。
6)volatile-ttl:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,有更早過時時間的key優先移除。
5.緩存清理的流程
1)客戶端執行數據寫入操做
2)redis server接收到寫入操做以後,檢查maxmemory的限制,若是超過了限制,那麼就根據對應的policy清理掉部分數據
3)寫入操做完成執行。
總結
redis的內存淘汰策略用於處理內存不足時的須要申請額外空間的數據,內存淘汰策略的選取並不會影響過時的key的處理。過時策略用於處理過時的緩存數據。
2.============================================================================================================================================
在不少場景中,咱們爲了保證數據的最終一致性,須要不少的技術方案來支持,好比分佈式事務、分佈式鎖等。那具體什麼是分佈式鎖,分佈式鎖應用在哪些業務場景、如何來實現分佈式鎖呢?今天來探討分佈式鎖這個話題。
什麼是分佈式鎖
要介紹分佈式鎖,首先要提到與分佈式鎖相對應的是線程鎖、進程鎖。
1.線程鎖
主要用來給方法、代碼塊加鎖。當某個方法或代碼使用鎖,在同一時刻僅有一個線程執行該方法或該代碼段。線程鎖只在同一JVM中有效果,由於線程鎖的實如今根本上是依靠線程之間共享內存實現的,好比Synchronized、Lock等。
2.進程鎖
爲了控制同一操做系統中多個進程訪問某個共享資源,由於進程具備獨立性,各個進程沒法訪問其餘進程的資源,所以沒法經過synchronized等線程鎖實現進程鎖。
3.分佈式鎖
當多個進程不在同一個系統中,用分佈式鎖控制多個進程對資源的訪問。
分佈式鎖的由來
在傳統單機部署的狀況下,可使用Java併發處理相關的API(如ReentrantLcok或synchronized)進行互斥控制。
可是在分佈式系統後,因爲分佈式系統多線程、多進程而且分佈在不一樣機器上,這將使原單機併發控制鎖策略失效,爲了解決這個問題就須要一種跨JVM的互斥機制來控制共享資源的訪問,這就是分佈式鎖的由來。
當多個進程不在同一個系統中,就須要用分佈式鎖控制多個進程對資源的訪問。
分佈式鎖的特色
首先,爲了確保分佈式鎖可用,咱們至少要確保鎖的實現同時知足如下四個條件:
一、互斥性:任意時刻,只能有一個客戶端獲取鎖,不能同時有兩個客戶端獲取到鎖。
二、安全性:鎖只能被持有該鎖的客戶端刪除,不能由其它客戶端刪除。
三、死鎖:獲取鎖的客戶端由於某些緣由(如down機等)而未能釋放鎖,其它客戶端再也沒法獲取到該鎖。
四、容錯:當部分節點(redis節點等)down機時,客戶端仍然可以獲取鎖和釋放鎖。
分佈式鎖的具體實現
分佈式鎖通常有三種實現方式:
數據庫樂觀鎖;
基於ZooKeeper的分佈式鎖;
3.基於Redis的分佈式鎖;
Redis實現分佈式鎖
基於Redis命令:SET key value NX EX max-lock-time
這裏補充下: 從2.6.12版本後, 就可使用set來獲取鎖, Lua 腳原本釋放鎖。setnx是老黃曆了,set命令nx,xx等參數, 是爲了實現 setnx 的功能。
1.加鎖
public class RedisTool { private static final String LOCK_SUCCESS =
「OK」; private static final String SET_IF_NOT_EXIST = 「NX」; private
static final String SET_WITH_EXPIRE_TIME = 「PX」; /** * 嘗試獲取分佈式鎖 *
@param jedis Redis客戶端 * @param lockKey 鎖 * @param requestId 請求標識 *
@param expireTime 超期時間 * @return 是否獲取成功 */ public static boolean
tryGetDistributedLock(Jedis jedis, String lockKey, String requestId,
int expireTime) { String result = jedis.set(lockKey, requestId,
SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); if
(LOCK_SUCCESS.equals(result)) {return true;}return false;} }jedis.set(String key, String value, String nxxx, String expx, int
time)
這個set()方法一共有五個形參:
第一個爲key,咱們使用key來當鎖,由於key是惟一的。
第二個爲value,咱們傳的是requestId,不少童鞋可能不明白,有key做爲鎖不就夠了嗎,爲何還要用到value?緣由就是咱們在上面講到可靠性時,分佈式鎖要知足第四個條件解鈴還須繫鈴人,經過給value賦值爲requestId,咱們就知道這把鎖是哪一個請求加的了,在解鎖的時候就能夠有依據。requestId可使用UUID.randomUUID().toString()方法生成。
第三個爲nxxx,這個參數咱們填的是NX,意思是SET IF NOT EXIST,即當key不存在時,咱們進行set操做;若key已經存在,則不作任何操做;
第四個爲expx,這個參數咱們傳的是PX,意思是咱們要給這個key加一個過時的設置,具體時間由第五個參數決定。
第五個爲time,與第四個參數相呼應,表明key的過時時間。
總的來講,執行上面的set()方法就只會致使兩種結果:1. 當前沒有鎖(key不存在),那麼就進行加鎖操做,並對鎖設置個有效期,同時value表示加鎖的客戶端。2. 已有鎖存在,不作任何操做。
2.解鎖
public class RedisTool { private static final Long RELEASE_SUCCESS =
1L; /** * 釋放分佈式鎖 * @param jedis Redis客戶端 * @param lockKey 鎖 * @param
requestId 請求標識 * @return 是否釋放成功 */ public static boolean
releaseDistributedLock(Jedis jedis, String lockKey, String requestId)
{ String script = 「if redis.call(‘get’, KEYS[1]) == ARGV[1] then
return redis.call(‘del’, KEYS[1]) else return 0 end」; Object result =
jedis.eval(script,
Collections.singletonList(lockKey),Collections.singletonList(requestId));if
(RELEASE_SUCCESS.equals(result)) {return true;}return false;} }
那麼這段Lua代碼的功能是什麼呢?其實很簡單,首先獲取鎖對應的value值,檢查是否與requestId相等,若是相等則刪除鎖(解鎖)。以上就是redis實現分佈式鎖詳解。
3.==========================================================================================================================================
1.Redis高併發的問題
Redis緩存的高性能有目共睹,應用的場景也是很是普遍,可是在高併發的場景下,也會出現問題:緩存擊穿、緩存雪崩、緩存和數據一致性,以及今天要談到的緩存併發競爭。
這裏的併發指的是多個redis的client同時set key引發的併發問題。
2.出現併發設置Key的緣由
Redis是一種單線程機制的nosql數據庫,基於key-value,數據可持久化落盤。因爲單線程因此Redis自己並無鎖的概念,多個客戶端鏈接並不存在競爭關係,可是利用jedis等客戶端對Redis進行併發訪問時會出現問題。
好比:同時有多個子系統去set一個key。這個時候要注意什麼呢?
3.舉一個例子
多客戶端同時併發寫一個key,一個key的值是1,原本按順序修改成2,3,4,最後是4,可是順序變成了4,3,2,最後變成了2。
如何解決redis的併發競爭key問題呢?下面給到2個Redis併發競爭的解決方案。
第一種方案:分佈式鎖+時間戳
1.總體技術方案
這種狀況,主要是準備一個分佈式鎖,你們去搶鎖,搶到鎖就作set操做。
加鎖的目的實際上就是把並行讀寫改爲串行讀寫的方式,從而來避免資源競爭。
2.Redis分佈式鎖的實現
主要用到的redis函數是setnx()
用SETNX實現分佈式鎖
利用SETNX很是簡單地實現分佈式鎖。例如:某客戶端要得到一個名字youzhi的鎖,客戶端使用下面的命令進行獲取:
SETNX lock.youzhi<current Unix time + lock timeout + 1>
如返回1,則該客戶端得到鎖,把lock.youzhi的鍵值設置爲時間值表示該鍵已被鎖定,該客戶端最後能夠經過DEL lock.foo來釋放該鎖。
如返回0,代表該鎖已被其餘客戶端取得,這時咱們能夠先返回或進行重試等對方完成或等待鎖超時。
3.時間戳
因爲上面舉的例子,要求key的操做須要順序執行,因此須要保存一個時間戳判斷set順序。
系統A key 1 {ValueA 7:00}
系統B key 1 { ValueB 7:05}
假設系統B先搶到鎖,將key1設置爲{ValueB 7:05}。接下來系統A搶到鎖,發現本身的key1的時間戳早於緩存中的時間戳(7:00<7:05),那就不作set操做了。
4.什麼是分佈式鎖
由於傳統的加鎖的作法(如java的synchronized和Lock)這裏沒用,只適合單點。由於這是分佈式環境,須要的是分佈式鎖。
固然,分佈式鎖能夠基於不少種方式實現,好比zookeeper、redis等,無論哪一種方式實現,基本原理是不變的:用一個狀態值表示鎖,對鎖的佔用和釋放經過狀態值來標識。
第二種方案:利用消息隊列
在併發量過大的狀況下,能夠經過消息中間件進行處理,把並行讀寫進行串行化。
把Redis.set操做放在隊列中使其串行化,必須的一個一個執行。
這種方式在一些高併發的場景中算是一種通用的解決方案。
以上就是Redis併發競爭key技術方案詳解,相關的Redis高併發問題具體還能夠參考:高併發架構系列:如何解決Redis雪崩、穿透、併發等5大難題
我是mikechen,每日分享bat架構+面試+技術乾貨!堅持原創不易,以爲不錯點贊支持,送你【分佈式架構23期學習資料合集】,加QQ 649449578領取資料、深度交流,驗證通關暗號【架構】。
1、需求原由
在高併發的業務場景下,數據庫大多數狀況都是用戶併發訪問最薄弱的環節。因此,就須要使用redis作一個緩衝操做,讓請求先訪問到redis,而不是直接訪問MySQL等數據庫。
這個業務場景,主要是解決讀數據從Redis緩存,通常都是按照下圖的流程來進行業務操做。
讀取緩存步驟通常沒有什麼問題,可是一旦涉及到數據更新:數據庫和緩存更新,就容易出現緩存(Redis)和數據庫(MySQL)間的數據一致性問題。
無論是先寫MySQL數據庫,再刪除Redis緩存;仍是先刪除緩存,再寫庫,都有可能出現數據不一致的狀況。舉一個例子:
1.若是刪除了緩存Redis,尚未來得及寫庫MySQL,另外一個線程就來讀取,發現緩存爲空,則去數據庫中讀取數據寫入緩存,此時緩存中爲髒數據。
2.若是先寫了庫,在刪除緩存前,寫庫的線程宕機了,沒有刪除掉緩存,則也會出現數據不一致狀況。
由於寫和讀是併發的,無法保證順序,就會出現緩存和數據庫的數據不一致的問題。
如來解決?這裏給出兩個解決方案,先易後難,結合業務和技術代價選擇使用。
2、緩存和數據庫一致性解決方案
1.第一種方案:採用延時雙刪策略
在寫庫先後都進行redis.del(key)操做,而且設定合理的超時時間。
僞代碼以下:
public void write(String key,Object data){ redis.delKey(key);
db.updateData(data); Thread.sleep(500); redis.delKey(key); }
具體的步驟就是:
那麼,這個500毫秒怎麼肯定的,具體該休眠多久呢?
須要評估本身的項目的讀數據業務邏輯的耗時。這麼作的目的,就是確保讀請求結束,寫請求能夠刪除讀請求形成的緩存髒數據。
固然這種策略還要考慮redis和數據庫主從同步的耗時。最後的的寫數據的休眠時間:則在讀數據業務邏輯的耗時基礎上,加幾百ms便可。好比:休眠1秒。
設置緩存過時時間
從理論上來講,給緩存設置過時時間,是保證最終一致性的解決方案。全部的寫操做以數據庫爲準,只要到達緩存過時時間,則後面的讀請求天然會從數據庫中讀取新值而後回填緩存。
該方案的弊端
結合雙刪策略+緩存超時設置,這樣最差的狀況就是在超時時間內數據存在不一致,並且又增長了寫請求的耗時。
二、第二種方案:異步更新緩存(基於訂閱binlog的同步機制)
技術總體思路:
MySQL binlog增量訂閱消費+消息隊列+增量數據更新到redis
讀Redis:熱數據基本都在Redis
寫MySQL:增刪改都是操做MySQL
更新Redis數據:MySQ的數據操做binlog,來更新到Redis
Redis更新
1)數據操做主要分爲兩大塊:
一個是全量(將所有數據一次寫入到redis)
一個是增量(實時更新)
這裏說的是增量,指的是mysql的update、insert、delate變動數據。
2)讀取binlog後分析 ,利用消息隊列,推送更新各臺的redis緩存數據。
這樣一旦MySQL中產生了新的寫入、更新、刪除等操做,就能夠把binlog相關的消息推送至Redis,Redis再根據binlog中的記錄,對Redis進行更新。
其實這種機制,很相似MySQL的主從備份機制,由於MySQL的主備也是經過binlog來實現的數據一致性。
這裏能夠結合使用canal(阿里的一款開源框架),經過該框架能夠對MySQL的binlog進行訂閱,而canal正是模仿了mysql的slave數據庫的備份請求,使得Redis的數據更新達到了相同的效果。
固然,這裏的消息推送工具你也能夠採用別的第三方:kafka、rabbitMQ等來實現推送更新Redis。
以上就是Redis和MySQL數據一致性詳解。
5.==============================================================================================
1.redis是基於內存的,內存的讀寫速度很是快;
2.redis是單線程的,省去了不少上下文切換線程的時間;
3.redis使用多路複用技術,能夠處理併發的鏈接。非阻塞IO 內部實現採用epoll,採用了epoll+本身實現的簡單的事件框架。epoll中的讀、寫、關閉、鏈接都轉化成了事件,而後利用epoll的多路複用特性,毫不在io上浪費一點時間。
下面重點介紹單線程設計和IO多路複用核心設計快的緣由。
1.官方答案
由於Redis是基於內存的操做,CPU不是Redis的瓶頸,Redis的瓶頸最有多是機器內存的大小或者網絡帶寬。既然單線程容易實現,並且CPU不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了。
2.性能指標
關於redis的性能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求。
3.詳細緣由
1)不須要各類鎖的性能消耗
Redis的數據結構並不全是簡單的Key-Value,還有list,hash等複雜的結構,這些結構有可能會進行很細粒度的操做,好比在很長的列表後面添加一個元素,在hash當中添加或者刪除
一個對象。這些操做可能就須要加很是多的鎖,致使的結果是同步開銷大大增長。
總之,在單線程的狀況下,就不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗。
2)單線程多進程集羣方案
單線程的威力實際上很是強大,每核心效率也很是高,多線程天然是能夠比單線程有更高的性能上限,可是在今天的計算環境中,即便是單機多線程的上限也每每不能知足須要了,須要進一步摸索的是多服務器集羣化的方案,這些方案中多線程的技術照樣是用不上的。
因此單線程、多進程的集羣不失爲一個時髦的解決方案。
3)CPU消耗
採用單線程,避免了沒必要要的上下文切換和競爭條件,也不存在多進程或者多線程致使的切換而消耗 CPU。
可是若是CPU成爲Redis瓶頸,或者不想讓服務器其餘CUP核閒置,那怎麼辦?
能夠考慮多起幾個Redis進程,Redis是key-value數據庫,不是關係數據庫,數據之間沒有約束。只要客戶端分清哪些key放在哪一個Redis進程上就能夠了。
單進程單線程優點
代碼更清晰,處理邏輯更簡單
不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗
不存在多進程或者多線程致使的切換而消耗CPU
單進程單線程弊端
沒法發揮多核CPU性能,不過能夠經過在單機開多個Redis實例來完善;
IO多路複用技術
redis 採用網絡IO多路複用技術來保證在多鏈接的時候, 系統的高吞吐量。
多路-指的是多個socket鏈接,複用-指的是複用一個線程。多路複用主要有三種技術:select,poll,epoll。epoll是最新的也是目前最好的多路複用技術。
這裏「多路」指的是多個網絡鏈接,「複用」指的是複用同一個線程。採用多路 I/O 複用技術可讓單個線程高效的處理多個鏈接請求(儘可能減小網絡IO的時間消耗),且Redis在內存中操做數據的速度很是快(內存內的操做不會成爲這裏的性能瓶頸),主要以上兩點造就了Redis具備很高的吞吐量。
以上就是redis高併發快的詳解。
6.======================================================================================================
1、緩存雪崩
數據未加載到緩存中,或者緩存同一時間大面積的失效,從而致使全部請求都去查數據庫,致使數據庫CPU和內存負載太高,甚至宕機。
好比一個雪崩的簡單過程:
一、redis集羣大面積故障;
二、緩存失效,但依然大量請求訪問緩存服務redis;
三、redis大量失效後,大量請求轉向到mysql數據庫;
四、mysql的調用量暴增,很快就扛不住了,甚至直接宕機;
五、因爲大量的應用服務依賴mysql和redis的服務,這個時候很快會演變成各服務器集羣的雪崩,最後網站完全崩潰。
2、如何預防緩存雪崩
1.緩存的高可用性
緩存層設計成高可用,防止緩存大面積故障。即便個別節點、個別機器、甚至是機房宕掉,依然能夠提供服務,例如 Redis Sentinel 和 Redis Cluster 都實現了高可用。
2.緩存降級
能夠利用ehcache等本地緩存(暫時支持),但主要仍是對源服務訪問進行限流、資源隔離(熔斷)、降級等。
當訪問量劇增、服務出現問題仍然須要保證服務仍是可用的。系統能夠根據一些關鍵數據進行自動降級,也能夠配置開關實現人工降級,這裏會涉及到運維的配合。
降級的最終目的是保證核心服務可用,即便是有損的。好比推薦服務中,不少都是個性化的需求,假如個性化需求不能提供服務了,能夠降級補充熱點數據,不至於形成前端頁面是個大空白。在進行降級以前要對系統進行梳理,好比:哪些業務是核心(必須保證),哪些業務能夠允許暫時不提供服務(利用靜態頁面替換)等,以及配合服務器核心指標,來後設置總體預案,好比:
(1)通常:好比有些服務偶爾由於網絡抖動或者服務正在上線而超時,能夠自動降級;
(2)警告:有些服務在一段時間內成功率有波動(如在95~100%之間),能夠自動降級或人工降級,併發送告警;
(3)錯誤:好比可用率低於90%,或者數據庫鏈接池被打爆了,或者訪問量忽然猛增到系統能承受的最大閥值,此時能夠根據狀況自動降級或者人工降級;
(4)嚴重錯誤:好比由於特殊緣由數據錯誤了,此時須要緊急人工降級。
3.Redis備份和快速預熱
1)Redis數據備份和恢復;
2)快速緩存預熱;
4.提早演練
最後,建議仍是在項目上線前,演練緩存層宕掉後,應用以及後端的負載狀況以及可能出現的問題,對高可用提早預演,提早發現問題。
3、緩存穿透
緩存穿透是指查詢一個一不存在的數據。例如:從緩存redis沒有命中,須要從mysql數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,形成緩存穿透。
解決思路:
若是查詢數據庫也爲空,直接設置一個默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫。設置一個過時時間或者當有值的時候將緩存中的值替換掉便可。能夠給key設置一些格式規則,而後查詢以前先過濾掉不符合規則的Key。
4、緩存併發
這裏的併發指的是多個redis的client同時set key引發的併發問題。其實redis自身就是單線程操做,多個client併發操做,按照先到先執行的原則,先到的先執行,其他的阻塞。固然,另外的解決方案是把redis.set操做放在隊列中使其串行化,必須的一個一個執行。
5、緩存預熱
緩存預熱就是系統上線後,將相關的緩存數據直接加載到緩存系統。
這樣就能夠避免在用戶請求的時候,先查詢數據庫,而後再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數據!
解決思路:
一、直接寫個緩存刷新頁面,上線時手工操做下;
二、數據量不大,能夠在項目啓動的時候自動進行加載;
目的就是在系統上線前,將數據加載到緩存中。
以上就是緩存雪崩、預熱、降級等的介紹,更多總體從服務器雪崩的角度,參考文章:阿里P8架構師談:什麼是緩存雪崩?服務器雪崩的場景與解決方案。
7.===========================================================================================
Redis支持哪幾種數據類型?
支持多種類型的數據結構
1.string:最基本的數據類型,二進制安全的字符串,最大512M。
2.list:按照添加順序保持順序的字符串列表。
3.set:無序的字符串集合,不存在重複的元素。
4.sorted set:已排序的字符串集合。
5.hash:key-value對的一種集合。
Redis主要有哪些功能?
1.哨兵(Sentinel)和複製(Replication)
Redis服務器毫無徵兆的罷工是個麻煩事,如何保證備份的機器是原始服務器的完整備份呢?這時候就須要哨兵和複製。
Sentinel能夠管理多個Redis服務器,它提供了監控,提醒以及自動的故障轉移的功能,Replication則是負責讓一個Redis服務器能夠配備多個備份的服務器。
Redis也是利用這兩個功能來保證Redis的高可用的
2.事務
不少狀況下咱們須要一次執行不止一個命令,並且須要其同時成功或者失敗。redis對事務的支持也是源自於這部分需求,即支持一次性按順序執行多個命令的能力,並保證其原子性。
3.LUA腳本
在事務的基礎上,若是咱們須要在服務端一次性的執行更復雜的操做(包含一些邏輯判斷),則lua就能夠排上用場了
4.持久化
redis的持久化指的是redis會把內存的中的數據寫入到硬盤中,在redis從新啓動的時候加載這些數據,從而最大限度的下降緩存丟失帶來的影響。
5.集羣(Cluster)
單臺服務器資源的老是有上限的,CPU資源和IO資源咱們能夠經過主從複製,進行讀寫分離,把一部分CPU和IO的壓力轉移到從服務器上,這也有點相似mysql數據庫的主從同步。
在Redis官方的分佈式方案出來以前,有twemproxy和codis兩種方案,這兩個方案整體上來講都是依賴proxy來進行分佈式的,下面的內容有具體集羣方案詳解。
Redis是單進程單線程的?
Redis是單進程單線程的,Redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷。
Redis爲何是單線程的?
多線程處理會涉及到鎖,並且多線程處理會涉及到線程切換而消耗CPU。由於CPU不是Redis的瓶頸,Redis的瓶頸最有多是機器內存或者網絡帶寬。單線程沒法發揮多核CPU性能,不過能夠經過在單機開多個Redis實例來解決。
其它開源軟件採用的模型
Nginx:多進程單線程模型
Memcached:單進程多線程模型
使用Redis的優點?
1.速度快,由於數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1)
3.支持事務,操做都是原子性,所謂的原子性就是對數據的更改要麼所有執行,要麼所有不執行
Redis單點吞吐量
單點TPS達到8萬/秒,QPS達到10萬/秒,補充下TPS和QPS的概念
1.QPS: 應用系統每秒鐘最大能接受的用戶訪問量
每秒鐘處理完請求的次數,注意這裏是處理完,具體是指發出請求到服務器處理完成功返回結果。能夠理解在server中有個counter,每處理一個請求加1,1秒後counter=QPS。
2.TPS: 每秒鐘最大能處理的請求數
每秒鐘處理完的事務次數,一個應用系統1s能完成多少事務處理,一個事務在分佈式處理中,可能會對應多個請求,對於衡量單個接口服務的處理能力,用QPS比較合理。
Redis相比memcached有哪些優點?
1.memcached全部的值均是簡單的字符串,Redis做爲其替代者,支持更爲豐富的數據類型
2.Redis的速度比memcached快不少
3.Redis能夠持久化其數據
4.Redis支持數據的備份,即master-slave模式的數據備份。
Redis有哪幾種數據淘汰策略?
在Redis中,容許用戶設置最大使用內存大小server.maxmemory,當Redis 內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略。
1.volatile-lru:從已設置過時的數據集中挑選最近最少使用的淘汰
2.volatile-ttr:從已設置過時的數據集中挑選將要過時的數據淘汰
3.volatile-random:從已設置過時的數據集中任意挑選數據淘汰
4.allkeys-lru:從數據集中挑選最近最少使用的數據淘汰
5.allkeys-random:從數據集中任意挑選數據淘汰
6.noenviction:禁止淘汰數據
redis淘汰數據時還會同步到aof
Redis集羣方案應該怎麼作?都有哪些方案?
1.twemproxy
2.codis,目前用的最多的集羣方案,基本和twemproxy一致的效果,但它支持在 節點數量改變狀況下,舊節點數據可恢復到新hash節點。
3.Redis cluster3.0自帶的集,特色在於他的分佈式算法不是一致性hash,而是hash槽的概念,以及自身支持節點設置從節點。
具體請查看阿里架構師進階專題:Redis集羣的5種使用方式,各自優缺點分析
Redis讀寫分離模型
經過增長Slave DB的數量,讀的性能能夠線性增加。爲了不Master DB的單點故障,集羣通常都會採用兩臺Master DB作雙機熱備,因此整個集羣的讀和寫的可用性都很是高。
讀寫分離架構的缺陷在於,無論是Master仍是Slave,每一個節點都必須保存完整的數據,若是在數據量很大的狀況下,集羣的擴展能力仍是受限於單個節點的存儲能力,並且對於Write-intensive類型的應用,讀寫分離架構並不適合。
Redis數據分片模型
爲了解決讀寫分離模型的缺陷,能夠將數據分片模型應用進來。
能夠將每一個節點當作都是獨立的master,而後經過業務實現數據分片。
結合上面兩種模型,能夠將每一個master設計成由一個master和多個slave組成的模型。
Redis提供了哪幾種持久化方式?
2.RDB
默認開啓,會按照配置的指定時間將內存中的數據快照到磁盤中,建立一個dump.rdb文件,Redis啓動時再恢復到內存中。
Redis會單首創建fork()一個子進程,將當前父進程的數據庫數據複製到子進程的內存中,而後由子進程寫入到臨時文件中,持久化的過程結束了,再用這個臨時文件替換上次的快照文件,而後子進程退出,內存釋放。
須要注意的是,每次快照持久化都會將主進程的數據庫數據複製一遍,致使內存開銷加倍,若此時內存不足,則會阻塞服務器運行,直到複製結束釋放內存;都會將內存數據完整寫入磁盤一次,因此若是數據量大的話,並且寫操做頻繁,必然會引發大量的磁盤I/O操做,嚴重影響性能,而且最後一次持久化後的數據可能會丟失;
3.AOF
以日誌的形式記錄每一個寫操做(讀操做不記錄),只需追加文件但不能夠改寫文件,Redis啓動時會根據日誌從頭至尾所有執行一遍以完成數據的恢復工做。包括flushDB也會執行。
主要有兩種方式觸發:有寫操做就寫、每秒定時寫(也會丟數據)。
由於AOF採用追加的方式,因此文件會愈來愈大,針對這個問題,新增了重寫機制,就是當日志文件大到必定程度的時候,會fork出一條新進程來遍歷進程內存中的數據,每條記錄對應一條set語句,寫到臨時文件中,而後再替換到舊的日誌文件(相似rdb的操做方式)。默認觸發是當aof文件大小是上次重寫後大小的一倍且文件大於64M時觸發。
當兩種方式同時開啓時,數據恢復Redis會優先選擇AOF恢復。通常狀況下,只要使用默認開啓的RDB便可,由於相對於AOF,RDB便於進行數據庫備份,而且恢復數據集的速度也要快不少。
開啓持久化緩存機制,對性能會有必定的影響,特別是當設置的內存滿了的時候,更是降低到幾百reqs/s。因此若是隻是用來作緩存的話,能夠關掉持久化。
Redis常見性能問題和解決方案?
(1) Master最好不要作任何持久化工做,如RDB內存快照和AOF日誌文件
(2) 若是數據比較重要,某個Slave開啓AOF備份數據,策略設置爲每秒同步一次
(3) 爲了主從複製的速度和鏈接的穩定性,Master和Slave最好在同一個局域網內
(4) 儘可能避免在壓力很大的主庫上增長從庫
(5) 主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即:Master <- Slave1 <- Slave2 <- Slave3…
這樣的結構方便解決單點故障問題,實現Slave對Master的替換。若是Master掛了,能夠馬上啓用Slave1作Master,其餘不變。
Redis支持的Java客戶端都有哪些?官方推薦用哪一個?
Redisson、Jedis、lettuce等等,官方推薦使用Redisson。
Redis哈希槽的概念?
Redis集羣沒有使用一致性hash,而是引入了哈希槽的概念,當須要在 Redis 集羣中放置一個 key-value 時,根據 CRC16(key) mod 16384的值,決定將一個key放到哪一個桶中。
Redis集羣最大節點個數是多少?
Redis集羣預分好16384個桶(哈希槽)
Redis集羣的主從複製模型是怎樣的?
爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有N-1個複製品.
Redis集羣會有寫操做丟失嗎?爲何?
Redis並不能保證數據的強一致性,這意味這在實際中集羣在特定的條件下可能會丟失寫操做。
Redis集羣之間是如何複製的?
異步複製
Redis如何作內存優化?
儘量使用散列表(hashes),散列表(是說散列表裏面存儲的數少)使用的內存很是小,因此你應該儘量的將你的數據模型抽象到一個散列表裏面。好比你的web系統中有一個用戶對象,不要爲這個用戶的名稱,姓氏,郵箱,密碼設置單獨的key,而是應該把這個用戶的全部信息存儲到一張散列表裏面.
Redis回收進程如何工做的?
一個客戶端運行了新的命令,添加了新的數據。
Redi檢查內存使用狀況,若是大於maxmemory的限制, 則根據設定好的策略進行回收。
Redis回收使用的是什麼算法?
LRU算法
Redis有哪些適合的場景?
1)Session共享(單點登陸)
2)頁面緩存
3)隊列
4)排行榜/計數器
5)發佈/訂閱
以上就是最全Redis詳細答案總結,如下最新總結的最全2018阿里集團高級Java必考題範圍和答案,包含必考的:MySQL(最全60題)、Spring(最全71題)、多線程、JVM等的答案,用於參考~
我是mike,原BAT高級研發經理、架構師,每日分享bat架構+面試+技術乾貨!堅持原創不易,以爲不錯點贊支持,送你【BAT架構80期學習資料合集】,加我QQ 649449578領取資料、與我深度交流,驗證通關暗號【架構】。