<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Redis 面試題全面總結(jié),建議收藏。

          共 9465字,需瀏覽 19分鐘

           ·

          2021-01-13 20:10


          點(diǎn)擊上方 泥瓦匠 關(guān)注我!

          • Redis 持久化機(jī)制
          • 緩存雪崩、緩存穿透、緩存預(yù)熱、緩存更新、緩存降級(jí)等問(wèn)題
          • 熱點(diǎn)數(shù)據(jù)和冷數(shù)據(jù)是什么
          • Memcache與Redis的區(qū)別都有哪些?
          • 單線(xiàn)程的redis為什么這么快
          • redis的數(shù)據(jù)類(lèi)型,以及每種數(shù)據(jù)類(lèi)型的使用場(chǎng)景
          • Redis 內(nèi)部結(jié)構(gòu)
          • redis的過(guò)期策略以及內(nèi)存淘汰機(jī)制
          • Redis 為什么是單線(xiàn)程的
          • Redis 集群方案應(yīng)該怎么做?都有哪些方案?
          • 有沒(méi)有嘗試進(jìn)行多機(jī)redis 的部署?如何保證數(shù)據(jù)一致的?
          • 對(duì)于大量的請(qǐng)求怎么樣處理
          • Redis 常見(jiàn)性能問(wèn)題和解決方案?
          • 講解下Redis線(xiàn)程模型
          • 為什么Redis的操作是原子性的,怎么保證原子性的?
          • Redis事務(wù)
          • Redis實(shí)現(xiàn)分布式鎖


          Redis 持久化機(jī)制

          Redis是一個(gè)支持持久化的內(nèi)存數(shù)據(jù)庫(kù),通過(guò)持久化機(jī)制把內(nèi)存中的數(shù)據(jù)同步到硬盤(pán)文件來(lái)保證數(shù)據(jù)持久化。當(dāng)Redis重啟后通過(guò)把硬盤(pán)文件重新加載到內(nèi)存,就能達(dá)到恢復(fù)數(shù)據(jù)的目的。

          實(shí)現(xiàn):?jiǎn)为?dú)創(chuàng)建fork()一個(gè)子進(jìn)程,將當(dāng)前父進(jìn)程的數(shù)據(jù)庫(kù)數(shù)據(jù)復(fù)制到子進(jìn)程的內(nèi)存中,然后由子進(jìn)程寫(xiě)入到臨時(shí)文件中,持久化的過(guò)程結(jié)束了,再用這個(gè)臨時(shí)文件替換上次的快照文件,然后子進(jìn)程退出,內(nèi)存釋放。

          RDB是Redis默認(rèn)的持久化方式。按照一定的時(shí)間周期策略把內(nèi)存的數(shù)據(jù)以快照的形式保存到硬盤(pán)的二進(jìn)制文件。即Snapshot快照存儲(chǔ),對(duì)應(yīng)產(chǎn)生的數(shù)據(jù)文件為dump.rdb,通過(guò)配置文件中的save參數(shù)來(lái)定義快照的周期。( 快照可以是其所表示的數(shù)據(jù)的一個(gè)副本,也可以是數(shù)據(jù)的一個(gè)復(fù)制品。) AOF:Redis會(huì)將每一個(gè)收到的寫(xiě)命令都通過(guò)Write函數(shù)追加到文件最后,類(lèi)似于MySQL的binlog。當(dāng)Redis重啟是會(huì)通過(guò)重新執(zhí)行文件中保存的寫(xiě)命令來(lái)在內(nèi)存中重建整個(gè)數(shù)據(jù)庫(kù)的內(nèi)容。

          當(dāng)兩種方式同時(shí)開(kāi)啟時(shí),數(shù)據(jù)恢復(fù)Redis會(huì)優(yōu)先選擇AOF恢復(fù)。

          緩存雪崩、緩存穿透、緩存預(yù)熱、緩存更新、緩存降級(jí)等問(wèn)題

          緩存雪崩

          緩存雪崩我們可以簡(jiǎn)單的理解為:由于原有緩存失效,新緩存未到期間

          (例如:我們?cè)O(shè)置緩存時(shí)采用了相同的過(guò)期時(shí)間,在同一時(shí)刻出現(xiàn)大面積的緩存過(guò)期),所有原本應(yīng)該訪問(wèn)緩存的請(qǐng)求都去查詢(xún)數(shù)據(jù)庫(kù)了,而對(duì)數(shù)據(jù)庫(kù)CPU和內(nèi)存造成巨大壓力,嚴(yán)重的會(huì)造成數(shù)據(jù)庫(kù)宕機(jī)。從而形成一系列連鎖反應(yīng),造成整個(gè)系統(tǒng)崩潰。

          解決辦法:

          大多數(shù)系統(tǒng)設(shè)計(jì)者考慮用加鎖( 最多的解決方案)或者隊(duì)列的方式保證來(lái)保證不會(huì)有大量的線(xiàn)程對(duì)數(shù)據(jù)庫(kù)一次性進(jìn)行讀寫(xiě),從而避免失效時(shí)大量的并發(fā)請(qǐng)求落到底層存儲(chǔ)系統(tǒng)上。還有一個(gè)簡(jiǎn)單方案就時(shí)講緩存失效時(shí)間分散開(kāi)。

          緩存穿透

          緩存穿透是指用戶(hù)查詢(xún)數(shù)據(jù),在數(shù)據(jù)庫(kù)沒(méi)有,自然在緩存中也不會(huì)有。這樣就導(dǎo)致用戶(hù)查詢(xún)的時(shí)候,在緩存中找不到,每次都要去數(shù)據(jù)庫(kù)再查詢(xún)一遍,然后返回空(相當(dāng)于進(jìn)行了兩次無(wú)用的查詢(xún))。這樣請(qǐng)求就繞過(guò)緩存直接查數(shù)據(jù)庫(kù),這也是經(jīng)常提的緩存命中率問(wèn)題。

          解決辦法:

          最常見(jiàn)的則是采用布隆過(guò)濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被這個(gè)bitmap攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢(xún)壓力。

          另外也有一個(gè)更為簡(jiǎn)單粗暴的方法,如果一個(gè)查詢(xún)返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存,但它的過(guò)期時(shí)間會(huì)很短,最長(zhǎng)不超過(guò)五分鐘。通過(guò)這個(gè)直接設(shè)置的默認(rèn)值存放到緩存,這樣第二次到緩沖中獲取就有值了,而不會(huì)繼續(xù)訪問(wèn)數(shù)據(jù)庫(kù),這種辦法最簡(jiǎn)單粗暴。

          5TB的硬盤(pán)上放滿(mǎn)了數(shù)據(jù),請(qǐng)寫(xiě)一個(gè)算法將這些數(shù)據(jù)進(jìn)行排重。如果這些數(shù)據(jù)是一些32bit大小的數(shù)據(jù)該如何解決?如果是64bit的呢?

          對(duì)于空間的利用到達(dá)了一種極致,那就是Bitmap和布隆過(guò)濾器(Bloom Filter)。

          Bitmap:典型的就是哈希表

          缺點(diǎn)是,Bitmap對(duì)于每個(gè)元素只能記錄1bit信息,如果還想完成額外的功能,恐怕只能靠犧牲更多的空間、時(shí)間來(lái)完成了。

          布隆過(guò)濾器(推薦)

          就是引入了k(k>1)k(k>1)個(gè)相互獨(dú)立的哈希函數(shù),保證在給定的空間、誤判率下,完成元素判重的過(guò)程。

          它的優(yōu)點(diǎn)是空間效率和查詢(xún)時(shí)間都遠(yuǎn)遠(yuǎn)超過(guò)一般的算法,缺點(diǎn)是有一定的誤識(shí)別率和刪除困難。

          Bloom-Filter算法的核心思想就是利用多個(gè)不同的Hash函數(shù)來(lái)解決“沖突”。

          Hash存在一個(gè)沖突(碰撞)的問(wèn)題,用同一個(gè)Hash得到的兩個(gè)URL的值有可能相同。為了減少?zèng)_突,我們可以多引入幾個(gè)Hash,如果通過(guò)其中的一個(gè)Hash值我們得出某元素不在集合中,那么該元素肯定不在集合中。只有在所有的Hash函數(shù)告訴我們?cè)撛卦诩现袝r(shí),才能確定該元素存在于集合中。這便是Bloom-Filter的基本思想。

          Bloom-Filter一般用于在大數(shù)據(jù)量的集合中判定某元素是否存在。

          緩存穿透與緩存擊穿的區(qū)別

          緩存擊穿:是指一個(gè)key非常熱點(diǎn),在不停的扛著大并發(fā),大并發(fā)集中對(duì)這一個(gè)點(diǎn)進(jìn)行訪問(wèn),當(dāng)這個(gè)key在失效的瞬間,持續(xù)的大并發(fā)就穿破緩存,直接請(qǐng)求數(shù)據(jù)。

          解決方案:在訪問(wèn)key之前,采用SETNX(set if not exists)來(lái)設(shè)置另一個(gè)短期key來(lái)鎖住當(dāng)前key的訪問(wèn),訪問(wèn)結(jié)束再刪除該短期key。

          給一個(gè)我公司處理的案例:背景雙機(jī)拿token,token在存一份到redis,保證系統(tǒng)在token過(guò)期時(shí)都只有一個(gè)線(xiàn)程去獲取token;線(xiàn)上環(huán)境有兩臺(tái)機(jī)器,故使用分布式鎖實(shí)現(xiàn)。

          三、緩存預(yù)熱

          緩存預(yù)熱這個(gè)應(yīng)該是一個(gè)比較常見(jiàn)的概念,相信很多小伙伴都應(yīng)該可以很容易的理解,緩存預(yù)熱就是系統(tǒng)上線(xiàn)后,將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。這樣就可以避免在用戶(hù)請(qǐng)求的時(shí)候,先查詢(xún)數(shù)據(jù)庫(kù),然后再將數(shù)據(jù)緩存的問(wèn)題!用戶(hù)直接查詢(xún)事先被預(yù)熱的緩存數(shù)據(jù)!

          解決思路:

          • 直接寫(xiě)個(gè)緩存刷新頁(yè)面,上線(xiàn)時(shí)手工操作下;
          • 數(shù)據(jù)量不大,可以在項(xiàng)目啟動(dòng)的時(shí)候自動(dòng)進(jìn)行加載;
          • 定時(shí)刷新緩存;

          四、緩存更新

          除了緩存服務(wù)器自帶的緩存失效策略之外(Redis默認(rèn)的有6中策略可供選擇),我們還可以根據(jù)具體的業(yè)務(wù)需求進(jìn)行自定義的緩存淘汰,常見(jiàn)的策略有兩種:

          • 定時(shí)去清理過(guò)期的緩存;
          • 當(dāng)有用戶(hù)請(qǐng)求過(guò)來(lái)時(shí),再判斷這個(gè)請(qǐng)求所用到的緩存是否過(guò)期,過(guò)期的話(huà)就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存。

          兩者各有優(yōu)劣,第一種的缺點(diǎn)是維護(hù)大量緩存的key是比較麻煩的,第二種的缺點(diǎn)就是每次用戶(hù)請(qǐng)求過(guò)來(lái)都要判斷緩存失效,邏輯相對(duì)比較復(fù)雜!具體用哪種方案,大家可以根據(jù)自己的應(yīng)用場(chǎng)景來(lái)權(quán)衡。

          五、緩存降級(jí)

          當(dāng)訪問(wèn)量劇增、服務(wù)出現(xiàn)問(wèn)題(如響應(yīng)時(shí)間慢或不響應(yīng))或非核心服務(wù)影響到核心流程的性能時(shí),仍然需要保證服務(wù)還是可用的,即使是有損服務(wù)。系統(tǒng)可以根據(jù)一些關(guān)鍵數(shù)據(jù)進(jìn)行自動(dòng)降級(jí),也可以配置開(kāi)關(guān)實(shí)現(xiàn)人工降級(jí)。

          降級(jí)的最終目的是保證核心服務(wù)可用,即使是有損的。而且有些服務(wù)是無(wú)法降級(jí)的(如加入購(gòu)物車(chē)、結(jié)算)。

          以參考日志級(jí)別設(shè)置預(yù)案:

          • 一般:比如有些服務(wù)偶爾因?yàn)榫W(wǎng)絡(luò)抖動(dòng)或者服務(wù)正在上線(xiàn)而超時(shí),可以自動(dòng)降級(jí);
          • 警告:有些服務(wù)在一段時(shí)間內(nèi)成功率有波動(dòng)(如在95~100%之間),可以自動(dòng)降級(jí)或人工降級(jí),并發(fā)送告警;
          • 錯(cuò)誤:比如可用率低于90%,或者數(shù)據(jù)庫(kù)連接池被打爆了,或者訪問(wèn)量突然猛增到系統(tǒng)能承受的最大閥值,此時(shí)可以根據(jù)情況自動(dòng)降級(jí)或者人工降級(jí);
          • 嚴(yán)重錯(cuò)誤:比如因?yàn)樘厥庠驍?shù)據(jù)錯(cuò)誤了,此時(shí)需要緊急人工降級(jí)。

          服務(wù)降級(jí)的目的,是為了防止Redis服務(wù)故障,導(dǎo)致數(shù)據(jù)庫(kù)跟著一起發(fā)生雪崩問(wèn)題。因此,對(duì)于不重要的緩存數(shù)據(jù),可以采取服務(wù)降級(jí)策略,例如一個(gè)比較常見(jiàn)的做法就是,Redis出現(xiàn)問(wèn)題,不去數(shù)據(jù)庫(kù)查詢(xún),而是直接返回默認(rèn)值給用戶(hù)。

          熱點(diǎn)數(shù)據(jù)和冷數(shù)據(jù)是什么

          熱點(diǎn)數(shù)據(jù),緩存才有價(jià)值

          對(duì)于冷數(shù)據(jù)而言,大部分?jǐn)?shù)據(jù)可能還沒(méi)有再次訪問(wèn)到就已經(jīng)被擠出內(nèi)存,不僅占用內(nèi)存,而且價(jià)值不大。頻繁修改的數(shù)據(jù),看情況考慮使用緩存

          對(duì)于上面兩個(gè)例子,壽星列表、導(dǎo)航信息都存在一個(gè)特點(diǎn),就是信息修改頻率不高,讀取通常非常高的場(chǎng)景。

          對(duì)于熱點(diǎn)數(shù)據(jù),比如我們的某IM產(chǎn)品,生日祝福模塊,當(dāng)天的壽星列表,緩存以后可能讀取數(shù)十萬(wàn)次。再舉個(gè)例子,某導(dǎo)航產(chǎn)品,我們將導(dǎo)航信息,緩存以后可能讀取數(shù)百萬(wàn)次。

          數(shù)據(jù)更新前至少讀取兩次, 緩存才有意義。這個(gè)是最基本的策略,如果緩存還沒(méi)有起作用就失效了,那就沒(méi)有太大價(jià)值了。

          那存不存在,修改頻率很高,但是又不得不考慮緩存的場(chǎng)景呢?有!比如,這個(gè)讀取接口對(duì)數(shù)據(jù)庫(kù)的壓力很大,但是又是熱點(diǎn)數(shù)據(jù),這個(gè)時(shí)候就需要考慮通過(guò)緩存手段,減少數(shù)據(jù)庫(kù)的壓力,比如我們的某助手產(chǎn)品的,點(diǎn)贊數(shù),收藏?cái)?shù),分享數(shù)等是非常典型的熱點(diǎn)數(shù)據(jù),但是又不斷變化,此時(shí)就需要將數(shù)據(jù)同步保存到Redis緩存,減少數(shù)據(jù)庫(kù)壓力。

          Memcache與Redis的區(qū)別都有哪些?

          1)、存儲(chǔ)方式 Memecache把數(shù)據(jù)全部存在內(nèi)存之中,斷電后會(huì)掛掉,數(shù)據(jù)不能超過(guò)內(nèi)存大小。Redis有部份存在硬盤(pán)上,redis可以持久化其數(shù)據(jù)

          2)、數(shù)據(jù)支持類(lèi)型 memcached所有的值均是簡(jiǎn)單的字符串,redis作為其替代者,支持更為豐富的數(shù)據(jù)類(lèi)型 ,提供list,set,zset,hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)

          3)、使用底層模型不同 它們之間底層實(shí)現(xiàn)方式 以及與客戶(hù)端之間通信的應(yīng)用協(xié)議不一樣。Redis直接自己構(gòu)建了VM 機(jī)制 ,因?yàn)橐话愕南到y(tǒng)調(diào)用系統(tǒng)函數(shù)的話(huà),會(huì)浪費(fèi)一定的時(shí)間去移動(dòng)和請(qǐng)求。

          4). value 值大小不同:Redis 最大可以達(dá)到 512M;memcache 只有 1mb。

          5)redis的速度比memcached快很多

          6)Redis支持?jǐn)?shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。

          單線(xiàn)程的redis為什么這么快

          (一)純內(nèi)存操作

          (二)單線(xiàn)程操作,避免了頻繁的上下文切換

          (三)采用了非阻塞I/O多路復(fù)用機(jī)制

          redis的數(shù)據(jù)類(lèi)型,以及每種數(shù)據(jù)類(lèi)型的使用場(chǎng)景

          回答:一共五種

          (一)String

          這個(gè)其實(shí)沒(méi)啥好說(shuō)的,最常規(guī)的set/get操作,value可以是String也可以是數(shù)字。一般做一些復(fù)雜的計(jì)數(shù)功能的緩存。

          (二)hash

          這里value存放的是結(jié)構(gòu)化的對(duì)象,比較方便的就是操作其中的某個(gè)字段。博主在做單點(diǎn)登錄的時(shí)候,就是用這種數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)用戶(hù)信息,以cookieId作為key,設(shè)置30分鐘為緩存過(guò)期時(shí)間,能很好的模擬出類(lèi)似session的效果。

          (三)list

          使用List的數(shù)據(jù)結(jié)構(gòu),可以做簡(jiǎn)單的消息隊(duì)列的功能。另外還有一個(gè)就是,可以利用lrange命令,做基于redis的分頁(yè)功能,性能極佳,用戶(hù)體驗(yàn)好。本人還用一個(gè)場(chǎng)景,很合適—取行情信息。就也是個(gè)生產(chǎn)者和消費(fèi)者的場(chǎng)景。LIST可以很好的完成排隊(duì),先進(jìn)先出的原則。

          (四)set

          因?yàn)閟et堆放的是一堆不重復(fù)值的集合。所以可以做全局去重的功能。為什么不用JVM自帶的Set進(jìn)行去重?因?yàn)槲覀兊南到y(tǒng)一般都是集群部署,使用JVM自帶的Set,比較麻煩,難道為了一個(gè)做一個(gè)全局去重,再起一個(gè)公共服務(wù),太麻煩了。

          另外,就是利用交集、并集、差集等操作,可以計(jì)算共同喜好,全部的喜好,自己獨(dú)有的喜好等功能。

          (五)sorted set

          sorted set多了一個(gè)權(quán)重參數(shù)score,集合中的元素能夠按score進(jìn)行排列。可以做排行榜應(yīng)用,取TOP N操作。

          Redis 內(nèi)部結(jié)構(gòu)

          • dict 本質(zhì)上是為了解決算法中的查找問(wèn)題(Searching)是一個(gè)用于維護(hù)key和value映射關(guān)系的數(shù)據(jù)結(jié)構(gòu),與很多語(yǔ)言中的Map或dictionary類(lèi)似。本質(zhì)上是為了解決算法中的查找問(wèn)題(Searching)
          • sds sds就等同于char * 它可以存儲(chǔ)任意二進(jìn)制數(shù)據(jù),不能像C語(yǔ)言字符串那樣以字符’\0’來(lái)標(biāo)識(shí)字符串的結(jié) 束,因此它必然有個(gè)長(zhǎng)度字段。
          • skiplist (跳躍表) 跳表是一種實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,單層多指針的鏈表,它查找效率很高,堪比優(yōu)化過(guò)的二叉平衡樹(shù),且比平衡樹(shù)的實(shí)現(xiàn),
          • quicklist
          • ziplist 壓縮表 ziplist是一個(gè)編碼后的列表,是由一系列特殊編碼的連續(xù)內(nèi)存塊組成的順序型數(shù)據(jù)結(jié)構(gòu),

          redis的過(guò)期策略以及內(nèi)存淘汰機(jī)制

          redis采用的是定期刪除+惰性刪除策略。

          為什么不用定時(shí)刪除策略?

          定時(shí)刪除,用一個(gè)定時(shí)器來(lái)負(fù)責(zé)監(jiān)視key,過(guò)期則自動(dòng)刪除。雖然內(nèi)存及時(shí)釋放,但是十分消耗CPU資源。在大并發(fā)請(qǐng)求下,CPU要將時(shí)間應(yīng)用在處理請(qǐng)求,而不是刪除key,因此沒(méi)有采用這一策略.

          定期刪除+惰性刪除是如何工作的呢?

          定期刪除,redis默認(rèn)每個(gè)100ms檢查,是否有過(guò)期的key,有過(guò)期key則刪除。需要說(shuō)明的是,redis不是每個(gè)100ms將所有的key檢查一次,而是隨機(jī)抽取進(jìn)行檢查(如果每隔100ms,全部key進(jìn)行檢查,redis豈不是卡死)。因此,如果只采用定期刪除策略,會(huì)導(dǎo)致很多key到時(shí)間沒(méi)有刪除。

          于是,惰性刪除派上用場(chǎng)。也就是說(shuō)在你獲取某個(gè)key的時(shí)候,redis會(huì)檢查一下,這個(gè)key如果設(shè)置了過(guò)期時(shí)間那么是否過(guò)期了?如果過(guò)期了此時(shí)就會(huì)刪除。

          采用定期刪除+惰性刪除就沒(méi)其他問(wèn)題了么?

          不是的,如果定期刪除沒(méi)刪除key。然后你也沒(méi)即時(shí)去請(qǐng)求key,也就是說(shuō)惰性刪除也沒(méi)生效。這樣,redis的內(nèi)存會(huì)越來(lái)越高。那么就應(yīng)該采用內(nèi)存淘汰機(jī)制。

          在redis.conf中有一行配置

          maxmemory-policy volatile-lru1

          該配置就是配內(nèi)存淘汰策略的(什么,你沒(méi)配過(guò)?好好反省一下自己)

          • volatile-lru:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
          • volatile-ttl:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過(guò)期的數(shù)據(jù)淘汰
          • volatile-random:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
          • allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
          • allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
          • no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù),新寫(xiě)入操作會(huì)報(bào)錯(cuò)

          ps:如果沒(méi)有設(shè)置 expire 的key, 不滿(mǎn)足先決條件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行為, 和 noeviction(不刪除) 基本上一致。

          Redis 為什么是單線(xiàn)程的

          官方FAQ表示,因?yàn)镽edis是基于內(nèi)存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機(jī)器內(nèi)存的大小或者網(wǎng)絡(luò)帶寬。

          既然單線(xiàn)程容易實(shí)現(xiàn),而且CPU不會(huì)成為瓶頸,那就順理成章地采用單線(xiàn)程的方案了(畢竟采用多線(xiàn)程會(huì)有很多麻煩!)Redis利用隊(duì)列技術(shù)將并發(fā)訪問(wèn)變?yōu)榇性L問(wèn)

          1)絕大部分請(qǐng)求是純粹的內(nèi)存操作(非常快速)

          2)采用單線(xiàn)程,避免了不必要的上下文切換和競(jìng)爭(zhēng)條件

          3)非阻塞IO優(yōu)點(diǎn):

          • 速度快,因?yàn)閿?shù)據(jù)存在內(nèi)存中,類(lèi)似于HashMap,HashMap的優(yōu)勢(shì)就是查找和操作的時(shí)間復(fù)雜度都是O(1)
          • 支持豐富數(shù)據(jù)類(lèi)型,支持string,list,set,sorted set,hash
          • 支持事務(wù),操作都是原子性,所謂的原子性就是對(duì)數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行
          • 豐富的特性:可用于緩存,消息,按key設(shè)置過(guò)期時(shí)間,過(guò)期后將會(huì)自動(dòng)刪除如何解決redis的并發(fā)競(jìng)爭(zhēng)key問(wèn)題

          同時(shí)有多個(gè)子系統(tǒng)去set一個(gè)key。這個(gè)時(shí)候要注意什么呢?

          不推薦使用redis的事務(wù)機(jī)制。因?yàn)槲覀兊纳a(chǎn)環(huán)境,基本都是redis集群環(huán)境,做了數(shù)據(jù)分片操作。你一個(gè)事務(wù)中有涉及到多個(gè)key操作的時(shí)候,這多個(gè)key不一定都存儲(chǔ)在同一個(gè)redis-server上。因此,redis的事務(wù)機(jī)制,十分雞肋。

          • 如果對(duì)這個(gè)key操作,不要求順序:準(zhǔn)備一個(gè)分布式鎖,大家去搶鎖,搶到鎖就做set操作即可
          • 如果對(duì)這個(gè)key操作,要求順序:分布式鎖+時(shí)間戳。假設(shè)這會(huì)系統(tǒng)B先搶到鎖,將key1設(shè)置為{valueB 3:05}。接下來(lái)系統(tǒng)A搶到鎖,發(fā)現(xiàn)自己的valueA的時(shí)間戳早于緩存中的時(shí)間戳,那就不做set操作了。以此類(lèi)推。
          • 利用隊(duì)列,將set方法變成串行訪問(wèn)也可以redis遇到高并發(fā),如果保證讀寫(xiě)key的一致性

          對(duì)redis的操作都是具有原子性的,是線(xiàn)程安全的操作,你不用考慮并發(fā)問(wèn)題,redis內(nèi)部已經(jīng)幫你處理好并發(fā)的問(wèn)題了。

          Redis 集群方案應(yīng)該怎么做?都有哪些方案?

          1.twemproxy,大概概念是,它類(lèi)似于一個(gè)代理方式, 使用時(shí)在本需要連接 redis 的地方改為連接 twemproxy, 它會(huì)以一個(gè)代理的身份接收請(qǐng)求并使用一致性 hash 算法,將請(qǐng)求轉(zhuǎn)接到具體 redis,將結(jié)果再返回 twemproxy。

          缺點(diǎn):twemproxy 自身單端口實(shí)例的壓力,使用一致性 hash 后,對(duì) redis 節(jié)點(diǎn)數(shù)量改變時(shí)候的計(jì)算值的改變,數(shù)據(jù)無(wú)法自動(dòng)移動(dòng)到新的節(jié)點(diǎn)。

          2.codis,目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支持在 節(jié)點(diǎn)數(shù)量改變情況下,舊節(jié)點(diǎn)數(shù)據(jù)可恢復(fù)到新 hash 節(jié)點(diǎn)

          3.redis cluster3.0 自帶的集群,特點(diǎn)在于他的分布式算法不是一致性 hash,而是 hash 槽的概念,以及自身支持節(jié)點(diǎn)設(shè)置從節(jié)點(diǎn)。具體看官方文檔介紹。

          有沒(méi)有嘗試進(jìn)行多機(jī)redis 的部署?如何保證數(shù)據(jù)一致的?

          主從復(fù)制,讀寫(xiě)分離

          一類(lèi)是主數(shù)據(jù)庫(kù)(master)一類(lèi)是從數(shù)據(jù)庫(kù)(slave),主數(shù)據(jù)庫(kù)可以進(jìn)行讀寫(xiě)操作,當(dāng)發(fā)生寫(xiě)操作的時(shí)候自動(dòng)將數(shù)據(jù)同步到從數(shù)據(jù)庫(kù),而從數(shù)據(jù)庫(kù)一般是只讀的,并接收主數(shù)據(jù)庫(kù)同步過(guò)來(lái)的數(shù)據(jù),一個(gè)主數(shù)據(jù)庫(kù)可以有多個(gè)從數(shù)據(jù)庫(kù),而一個(gè)從數(shù)據(jù)庫(kù)只能有一個(gè)主數(shù)據(jù)庫(kù)。

          對(duì)于大量的請(qǐng)求怎么樣處理

          redis是一個(gè)單線(xiàn)程程序,也就說(shuō)同一時(shí)刻它只能處理一個(gè)客戶(hù)端請(qǐng)求;

          redis是通過(guò)IO多路復(fù)用(select,epoll, kqueue,依據(jù)不同的平臺(tái),采取不同的實(shí)現(xiàn))來(lái)處理多個(gè)客戶(hù)端請(qǐng)求的

          Redis 常見(jiàn)性能問(wèn)題和解決方案?

          (1) Master 最好不要做任何持久化工作,如 RDB 內(nèi)存快照和 AOF 日志文件

          (2) 如果數(shù)據(jù)比較重要,某個(gè) Slave 開(kāi)啟 AOF 備份數(shù)據(jù),策略設(shè)置為每秒同步一次

          (3) 為了主從復(fù)制的速度和連接的穩(wěn)定性, Master 和 Slave 最好在同一個(gè)局域網(wǎng)內(nèi)

          (4) 盡量避免在壓力很大的主庫(kù)上增加從庫(kù)

          (5) 主從復(fù)制不要用圖狀結(jié)構(gòu),用單向鏈表結(jié)構(gòu)更為穩(wěn)定,即:Master <- Slave1 <- Slave2 <- Slave3…

          講解下Redis線(xiàn)程模型

          文件事件處理器包括分別是套接字、 I/O 多路復(fù)用程序、 文件事件分派器(dispatcher)、 以及事件處理器。使用 I/O 多路復(fù)用程序來(lái)同時(shí)監(jiān)聽(tīng)多個(gè)套接字, 并根據(jù)套接字目前執(zhí)行的任務(wù)來(lái)為套接字關(guān)聯(lián)不同的事件處理器。

          當(dāng)被監(jiān)聽(tīng)的套接字準(zhǔn)備好執(zhí)行連接應(yīng)答(accept)、讀取(read)、寫(xiě)入(write)、關(guān)閉(close)等操作時(shí), 與操作相對(duì)應(yīng)的文件事件就會(huì)產(chǎn)生, 這時(shí)文件事件處理器就會(huì)調(diào)用套接字之前關(guān)聯(lián)好的事件處理器來(lái)處理這些事件。

          I/O 多路復(fù)用程序負(fù)責(zé)監(jiān)聽(tīng)多個(gè)套接字, 并向文件事件分派器傳送那些產(chǎn)生了事件的套接字。

          工作原理:

          I/O 多路復(fù)用程序負(fù)責(zé)監(jiān)聽(tīng)多個(gè)套接字, 并向文件事件分派器傳送那些產(chǎn)生了事件的套接字。

          盡管多個(gè)文件事件可能會(huì)并發(fā)地出現(xiàn), 但 I/O 多路復(fù)用程序總是會(huì)將所有產(chǎn)生事件的套接字都入隊(duì)到一個(gè)隊(duì)列里面, 然后通過(guò)這個(gè)隊(duì)列, 以有序(sequentially)、同步(synchronously)、每次一個(gè)套接字的方式向文件事件分派器傳送套接字:

          當(dāng)上一個(gè)套接字產(chǎn)生的事件被處理完畢之后(該套接字為事件所關(guān)聯(lián)的事件處理器執(zhí)行完畢), I/O 多路復(fù)用程序才會(huì)繼續(xù)向文件事件分派器傳送下一個(gè)套接字。如果一個(gè)套接字又可讀又可寫(xiě)的話(huà), 那么服務(wù)器將先讀套接字, 后寫(xiě)套接字.

          圖片

          為什么Redis的操作是原子性的,怎么保證原子性的?

          對(duì)于Redis而言,命令的原子性指的是:一個(gè)操作的不可以再分,操作要么執(zhí)行,要么不執(zhí)行。

          Redis的操作之所以是原子性的,是因?yàn)镽edis是單線(xiàn)程的。(Redis新版本已經(jīng)引入多線(xiàn)程,這里基于舊版本的Redis)

          Redis本身提供的所有API都是原子操作,Redis中的事務(wù)其實(shí)是要保證批量操作的原子性。

          多個(gè)命令在并發(fā)中也是原子性的嗎?

          不一定, 將get和set改成單命令操作,incr 。使用Redis的事務(wù),或者使用Redis+Lua==的方式實(shí)現(xiàn).

          Redis事務(wù)

          Redis事務(wù)功能是通過(guò)MULTI、EXEC、DISCARD和WATCH 四個(gè)原語(yǔ)實(shí)現(xiàn)的

          Redis會(huì)將一個(gè)事務(wù)中的所有命令序列化,然后按順序執(zhí)行。

          1. redis 不支持回滾“Redis 在事務(wù)失敗時(shí)不進(jìn)行回滾,而是繼續(xù)執(zhí)行余下的命令”, 所以 Redis 的內(nèi)部可以保持簡(jiǎn)單且快速。
          2. 如果在一個(gè)事務(wù)中的命令出現(xiàn)錯(cuò)誤,那么所有的命令都不會(huì)執(zhí)行;
          3. 如果在一個(gè)事務(wù)中出現(xiàn)運(yùn)行錯(cuò)誤,那么正確的命令會(huì)被執(zhí)行。

          注:redis的discard只是結(jié)束本次事務(wù),正確命令造成的影響仍然存在.

          1)MULTI命令用于開(kāi)啟一個(gè)事務(wù),它總是返回OK。MULTI執(zhí)行之后,客戶(hù)端可以繼續(xù)向服務(wù)器發(fā)送任意多條命令,這些命令不會(huì)立即被執(zhí)行,而是被放到一個(gè)隊(duì)列中,當(dāng)EXEC命令被調(diào)用時(shí),所有隊(duì)列中的命令才會(huì)被執(zhí)行。

          2)EXEC:執(zhí)行所有事務(wù)塊內(nèi)的命令。返回事務(wù)塊內(nèi)所有命令的返回值,按命令執(zhí)行的先后順序排列。當(dāng)操作被打斷時(shí),返回空值 nil 。

          3)通過(guò)調(diào)用DISCARD,客戶(hù)端可以清空事務(wù)隊(duì)列,并放棄執(zhí)行事務(wù), 并且客戶(hù)端會(huì)從事務(wù)狀態(tài)中退出。

          4)WATCH 命令可以為 Redis 事務(wù)提供 check-and-set (CAS)行為。可以監(jiān)控一個(gè)或多個(gè)鍵,一旦其中有一個(gè)鍵被修改(或刪除),之后的事務(wù)就不會(huì)執(zhí)行,監(jiān)控一直持續(xù)到EXEC命令。

          Redis實(shí)現(xiàn)分布式鎖

          Redis為單進(jìn)程單線(xiàn)程模式,采用隊(duì)列模式將并發(fā)訪問(wèn)變成串行訪問(wèn),且多客戶(hù)端對(duì)Redis的連接并不存在競(jìng)爭(zhēng)關(guān)系Redis中可以使用SETNX命令實(shí)現(xiàn)分布式鎖。

          將 key 的值設(shè)為 value ,當(dāng)且僅當(dāng) key 不存在。若給定的 key 已經(jīng)存在,則 SETNX 不做任何動(dòng)作

          圖片

          解鎖:使用 del key 命令就能釋放鎖

          解決死鎖:

          • 通過(guò)Redis中expire()給鎖設(shè)定最大持有時(shí)間,如果超過(guò),則Redis來(lái)幫我們釋放鎖。
          • 使用 setnx key “當(dāng)前系統(tǒng)時(shí)間+鎖持有的時(shí)間”和getset key “當(dāng)前系統(tǒng)時(shí)間+鎖持有的時(shí)間”組合的命令就可以實(shí)現(xiàn)。




          往期推薦

          SpringBoot 中用 AOP 實(shí)現(xiàn)一個(gè)權(quán)限校驗(yàn)的思路總結(jié)

          通過(guò) Excel 來(lái)認(rèn)識(shí)神器 Apache POI

          畫(huà)好架構(gòu)圖,是進(jìn)階的必經(jīng)之路

          大公司還是小公司到底如何選擇?


          下方二維碼關(guān)注我

          技術(shù)草根堅(jiān)持分享 編程,算法,架構(gòu)

          朋友助力下!點(diǎn)個(gè)在看
          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  99国产在线观看免费 | 色天堂网| 啪啪啪网站免费观看 | 婷婷基地五月 | 又粗又大又黄 |