Redis追命連環(huán)問,你能回答到第幾問火架?(上)

Redis常見面試題連環(huán)問鉴象,你能回答到第幾問忙菠?(上)

Redis常見面試題連環(huán)問,你能回答到第幾問纺弊?(中)

Redis常見面試題連環(huán)問牛欢,你能回答到第幾問?(下)

Redis是后端工程師必備的一項技能淆游,下面分享一位求職者在面試過程中遇到的問題傍睹。

面試官說:“我們開始吧∮塘猓看了你的簡歷拾稳,覺得你對redis應(yīng)該掌握的不錯,我們今天就來討論下redis…”腊脱。我想:“來就來访得,兵來將擋水來土掩”。

一虑椎、Redis是什么

面試官:你先來說下redis是什么吧

我:(這不就是總結(jié)下redis的定義和特點嘛)Redis是C語言開發(fā)的一個開源的(遵從BSD協(xié)議)高性能鍵值對(key-value)的內(nèi)存數(shù)據(jù)庫,可以用作數(shù)據(jù)庫俱笛、緩存捆姜、消息中間件等。它是一種NoSQL(not-only sql迎膜,泛指非關(guān)系型數(shù)據(jù)庫)的數(shù)據(jù)庫泥技。

我頓了一下,接著說:Redis作為一個內(nèi)存數(shù)據(jù)庫磕仅。

  1. 性能優(yōu)秀珊豹,數(shù)據(jù)在內(nèi)存中,讀寫速度非抽哦快店茶,支持并發(fā)10W QPS;

  2. 單進(jìn)程單線程劫恒,是線程安全的贩幻,采用IO多路復(fù)用機制;

  3. 豐富的數(shù)據(jù)類型两嘴,支持字符串(strings)丛楚、散列(hashes)、列表(lists)憔辫、集合(sets)趣些、有序集合(sorted sets)等;

  4. 支持?jǐn)?shù)據(jù)持久化贰您』灯剑可以將內(nèi)存中數(shù)據(jù)保存在磁盤中拢操,重啟時加載;

  5. 主從復(fù)制功茴,哨兵庐冯,高可用;

  6. 可以用作分布式鎖坎穿;

  7. 可以作為消息中間件使用展父,支持發(fā)布訂閱

注:答主回答的還是不錯的,我們看一下官方簡介

Redis是一個基于BSD開源的項目玲昧,是一個把結(jié)構(gòu)化的數(shù)據(jù)放在內(nèi)存中的一個存儲系統(tǒng)栖茉,你可以把它作為數(shù)據(jù)庫,緩存和消息中間件來使用孵延。同時支持strings吕漂,lists,hashes尘应,sets惶凝,sorted sets,bitmaps犬钢,hyperloglogs和geospatial indexes等數(shù)據(jù)類型苍鲜。

它還內(nèi)建了復(fù)制,lua腳本玷犹,LRU(Least Recently Used混滔,最近最少使用),事務(wù)等功能歹颓,通過redis sentinel(即哨兵)實現(xiàn)高可用坯屿,通過redis cluster實現(xiàn)了自動分片。以及事務(wù)巍扛,發(fā)布/訂閱领跛,自動故障轉(zhuǎn)移等等。

面試官:總結(jié)的不錯撤奸,看來是早有準(zhǔn)備啊隔节。剛來聽你提到redis支持五種數(shù)據(jù)類型,那你能簡單說下這五種數(shù)據(jù)類型嗎寂呛?

二怎诫、五種數(shù)據(jù)類型

我:當(dāng)然可以,但是在說之前贷痪,我覺得有必要先來了解下Redis內(nèi)部內(nèi)存管理是如何描述這5種數(shù)據(jù)類型的幻妓。說著,我拿著筆給面試官畫了一張圖:

image
image.gif

?

我:首先redis內(nèi)部使用一個redisObject對象來表示所有的key和value,redisObject最主要的信息如上圖所示:
type表示一個value對象具體是何種數(shù)據(jù)類型肉津,
encoding是不同數(shù)據(jù)類型在redis內(nèi)部的存儲方式强胰。比如:type=string表示value存儲的是一個普通字符串,那么encoding可以是raw或者int妹沙。

我頓了一下偶洋,接著說:下面我簡單說下5種數(shù)據(jù)類型:

  1. string是redis最基本的類型,可以理解成與memcached一模一樣的類型距糖,一個key對應(yīng)一個value玄窝。value不僅是string,也可以是數(shù)字悍引。string類型是二進(jìn)制安全的恩脂,意思是redis的string類型可以包含任何數(shù)據(jù),比如jpg圖片或者序列化的對象趣斤。string類型的值最大能存儲512M俩块。

  2. Hash是一個鍵值(key-value)的集合。redis的hash是一個string的key和value的映射表浓领,Hash特別適合存儲對象玉凯。常用命令:hget,hset,hgetall等。

  3. list列表是簡單的字符串列表联贩,按照插入順序排序漫仆。可以添加一個元素到列表的頭部(左邊)或者尾部(右邊) 常用命令:lpush撑蒜、rpush歹啼、lpop玄渗、rpop座菠、lrange(獲取列表片段)等。
    應(yīng)用場景:list應(yīng)用場景非常多藤树,也是Redis最重要的數(shù)據(jù)結(jié)構(gòu)之一浴滴,比如twitter的關(guān)注列表,粉絲列表都可以用list結(jié)構(gòu)來實現(xiàn)岁钓。
    數(shù)據(jù)結(jié)構(gòu):list就是鏈表升略,可以用來當(dāng)消息隊列。redis提供了List的push和pop操作屡限,還提供了操作某一段的api品嚣,可以直接查詢或者刪除某一段的元素。
    實現(xiàn)方式:redis list的是實現(xiàn)是一個雙向鏈表钧大,支持反向查找和遍歷翰撑,更方便操作,不過帶來了額外的內(nèi)存開銷啊央。

  4. set是string類型的無序集合眶诈。集合是通過hashtable實現(xiàn)的涨醋。set中的元素是沒有順序的,而且是沒有重復(fù)的逝撬。
    常用命令:sdd浴骂、spop、smembers宪潮、sunion等溯警。
    應(yīng)用場景:redis set對外提供的功能和list一樣是一個列表,特殊之處在于set是自動去重的坎炼,而且set提供了判斷某個成員是否在一個set集合中愧膀。

  5. zset和set一樣是string類型元素的集合,且不允許重復(fù)的元素谣光。常用命令:zadd檩淋、zrange、zrem萄金、zcard等蟀悦。
    使用場景:sorted set可以通過用戶額外提供一個優(yōu)先級(score)的參數(shù)來為成員排序,并且是插入有序的氧敢,即自動排序日戈。當(dāng)你需要一個有序的并且不重復(fù)的集合列表,那么可以選擇sorted set結(jié)構(gòu)孙乖。和set相比浙炼,sorted set關(guān)聯(lián)了一個double類型權(quán)重的參數(shù)score,使得集合中的元素能夠按照score進(jìn)行有序排列唯袄,redis正是通過分?jǐn)?shù)來為集合中的成員進(jìn)行從小到大的排序弯屈。
    實現(xiàn)方式:Redis sorted set的內(nèi)部使用HashMap和跳躍表(skipList)來保證數(shù)據(jù)的存儲和有序,HashMap里放的是成員到score的映射恋拷,而跳躍表里存放的是所有的成員资厉,排序依據(jù)是HashMap里存的score,使用跳躍表的結(jié)構(gòu)可以獲得比較高的查找效率蔬顾,并且在實現(xiàn)上比較簡單宴偿。

數(shù)據(jù)類型應(yīng)用場景總結(jié)

類型 簡介 特性 場景
string(字符串) 二進(jìn)制安全 可以包含任何數(shù)據(jù),比如jpg圖片或者序列化對象
Hash(字典) 鍵值對集合诀豁,即編程語言中的map類型 適合存儲對象窄刘,并且可以像數(shù)據(jù)庫中的update一個屬性一樣只修改某一項屬性值 存儲、讀取舷胜、修改用戶屬性
List(列表) 鏈表(雙向鏈表) 增刪快娩践,提供了操作某一元素的api 最新消息排行;消息隊列
set(集合) hash表實現(xiàn),元素不重復(fù) 添加欺矫、刪除纱新、查找的復(fù)雜度都是O(1),提供了求交集穆趴、并集脸爱、差集的操作 共同好友;利用唯一性未妹,統(tǒng)計訪問網(wǎng)站的所有Ip
sorted set(有序集合) 將set中的元素增加一個權(quán)重參數(shù)score簿废,元素按score有序排列 數(shù)據(jù)插入集合時,已經(jīng)進(jìn)行了天然排序 排行榜络它;帶權(quán)重的消息隊列

面試官:那Redis緩存你一定用過的吧族檬,用的過程中遇到過什么問題嗎?雪崩了解嗎化戳?

我:緩存和數(shù)據(jù)庫數(shù)據(jù)一致性問題:分布式環(huán)境下非常容易出現(xiàn)緩存和數(shù)據(jù)庫間數(shù)據(jù)一致性問題单料,針對這一點,如果項目對緩存的要求是強一致性的点楼,那么就不要使用緩存扫尖。我們只能采取合適的策略來降低緩存和數(shù)據(jù)庫間數(shù)據(jù)不一致的概率,而無法保證兩者間的強一致性掠廓。合適的策略包括合適的緩存更新策略换怖,更新數(shù)據(jù)庫后及時更新緩存、緩存失敗時增加重試機制蟀瞧。

緩存雪崩

緩存雪崩是指在我們設(shè)置緩存時采用了相同的過期時間沉颂,導(dǎo)致緩存在某一時刻同時失效,請求全部轉(zhuǎn)發(fā)到DB悦污,DB瞬時壓力過重雪崩铸屉。

舉個栗子:
如果某電商網(wǎng)站首頁所有Key的失效時間都是12小時,中午12點刷新的塞关,我零點有個大促活動大量用戶涌入抬探,假設(shè)每秒6000個請求子巾,本來緩存可以抗住每秒5000個請求帆赢,但是緩存中所有Key都失效了。此時6000個/秒的請求全部落在了數(shù)據(jù)庫上线梗,數(shù)據(jù)庫必然扛不住椰于,真實情況可能DBA都沒反應(yīng)過來直接掛了,此時仪搔,如果沒什么特別的方案來處理瘾婿,DBA很著急,重啟數(shù)據(jù)庫,但是數(shù)據(jù)庫立馬又被新流量給打死了偏陪。這就是我理解的緩存雪崩抢呆。

我心想:同一時間大面積失效,瞬間Redis跟沒有一樣笛谦,那這個數(shù)量級別的請求直接打到數(shù)據(jù)庫幾乎是災(zāi)難性的抱虐,你想想如果掛的是一個用戶服務(wù)的庫,那其他依賴他的庫所有接口幾乎都會報錯饥脑,如果沒做熔斷等策略基本上就是瞬間掛一片的節(jié)奏恳邀,你怎么重啟用戶都會把你打掛,等你重啟好的時候灶轰,用戶早睡覺去了谣沸。

解決方案

緩存失效時的雪崩效應(yīng)對底層系統(tǒng)的沖擊非常可怕笋颤。有一個簡單方案就是將緩存失效時間分散開乳附,比如我們可以在原有的失效時間基礎(chǔ)上增加一個隨機值,比如1-5分鐘隨機伴澄,這樣每一個緩存的過期時間的重復(fù)率就會降低许溅,就很難引發(fā)集體失效的事件。

如果Redis是集群部署秉版,將熱點數(shù)據(jù)均勻分布在不同的Redis庫中也能避免全部失效贤重。
或者設(shè)置熱點數(shù)據(jù)永不過期,有更新操作就更新緩存就好了(比如更新了首頁商品清焕,那你刷下緩存就好了并蝗,不要設(shè)置過期時間),電商首頁的數(shù)據(jù)也可以用這個操作秸妥,保險滚停。

面試官:那你了解緩存穿透和擊穿么,可以說說他們跟雪崩的區(qū)別嗎粥惧?

緩存穿透 與 緩存擊穿

我:緩存穿透是指查詢一個一定不存在的數(shù)據(jù)键畴,由于緩存是不命中時被動寫的,并且出于容錯考慮突雪,如果從存儲層查不到數(shù)據(jù)則不寫入緩存起惕,這將導(dǎo)致這個不存在的數(shù)據(jù)每次請求都要到存儲層去查詢,失去了緩存的意義咏删。而用戶(黑客)不斷發(fā)起請求惹想,這就是漏洞。

舉個栗子:我們數(shù)據(jù)庫的id都是從1自增的督函,如果發(fā)起id=-1的數(shù)據(jù)或者id特別大不存在的數(shù)據(jù)嘀粱,這樣的不斷攻擊導(dǎo)致數(shù)據(jù)庫壓力很大激挪,嚴(yán)重會擊垮數(shù)據(jù)庫。

我又接著說:至于緩存擊穿嘛锋叨,這個跟緩存雪崩有點像垄分,但是又有一點不一樣,緩存雪崩是因為大面積的緩存失效娃磺,打崩了DB锋喜,而緩存擊穿不同的是緩存擊穿是指一個Key非常熱點,在不停地扛著大量的請求豌鸡,大并發(fā)集中對這一個點進(jìn)行訪問嘿般,當(dāng)這個Key在失效的瞬間,持續(xù)的大并發(fā)直接落到了數(shù)據(jù)庫上涯冠,就在這個Key的點上擊穿了緩存炉奴。并發(fā)的請求可能會瞬間把后端DB壓垮。

面試官露出欣慰的眼光:那他們分別怎么解決蛇更?

緩存穿透我會在接口層增加校驗瞻赶,比如用戶鑒權(quán),參數(shù)做校驗派任,不合法的校驗直接return砸逊,比如id做基礎(chǔ)校驗,id<=0直接攔截掌逛。
從緩存取不到的數(shù)據(jù)师逸,在數(shù)據(jù)庫中也沒有取到,這時也可以將key-value對寫為key-null豆混,緩存有效時間可以設(shè)置短點篓像,如30秒(設(shè)置太長會導(dǎo)致正常情況也沒法使用)。這樣可以防止攻擊用戶反復(fù)用同一個id暴力攻擊皿伺。

Redis里還有一個高級用法布隆過濾器(Bloom Filter)這個也能很好的預(yù)防緩存穿透的發(fā)生员辩,他的原理也很簡單,就是利用高效的數(shù)據(jù)結(jié)構(gòu)和算法快速判斷出你這個Key是否在數(shù)據(jù)庫中存在鸵鸥,不存在你return就好了奠滑,存在你就去查DB刷新KV再return。但布隆過濾器有一定的誤判性妒穴。

緩存擊穿的話宋税,主要有三種解決方法:

  1. 使用互斥鎖(mutex key):這種解決方案思路比較簡單,就是只讓一個線程構(gòu)建緩存宰翅,其他線程等待構(gòu)建緩存的線程執(zhí)行完弃甥,重新從緩存獲取數(shù)據(jù)就可以了爽室。

  2. "提前"使用互斥鎖(mutex key):在value內(nèi)部設(shè)置1個超時值(timeout1), timeout1比實際的緩存失效時間timeout(timeout2)小汁讼。當(dāng)從cache讀取到timeout1發(fā)現(xiàn)它已經(jīng)過期時候淆攻,馬上獲取新的數(shù)據(jù)到cache并延長timeout1并重新設(shè)置到cache。

  3. “永遠(yuǎn)不過期”:然后通過定時job去刷新緩存嘿架。

加鎖偽代碼如下:

public function getData($key)
{
    $data = redis->get($key);
    if (!is_null($data)) {
        //緩存未過期
        if ($data['expire'] > time()){
            return $data['data'];
        }
        //加鎖失敗說明已經(jīng)有請求執(zhí)行加鎖瓶珊,返回之前的緩存數(shù)據(jù)
        if (!Redis::setnx($lockKey,1)) {
            return $data['data'];
        }
    }
    usleep(100);
    $data_new = $this->searchDB($key);
    $data = [
        'data' => $data_new,
        'expire' => time() + $expire
    ];
    $r = redis->set($key, $data, $expire);
    //解鎖
    redis->del($lockKey);
    return $data['data'];
}

今天就分享到這里,預(yù)知后事如何且聽下回分解耸彪。

更多精彩歡迎關(guān)注公眾號伞芹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蝉娜,隨后出現(xiàn)的幾起案子唱较,更是在濱河造成了極大的恐慌,老刑警劉巖召川,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件南缓,死亡現(xiàn)場離奇詭異,居然都是意外死亡荧呐,警方通過查閱死者的電腦和手機汉形,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倍阐,“玉大人概疆,你說我怎么就攤上這事》逄拢” “怎么了岔冀?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長概耻。 經(jīng)常有香客問我楣颠,道長,這世上最難降的妖魔是什么咐蚯? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任童漩,我火速辦了婚禮,結(jié)果婚禮上春锋,老公的妹妹穿的比我還像新娘矫膨。我一直安慰自己,他們只是感情好期奔,可當(dāng)我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布侧馅。 她就那樣靜靜地躺著,像睡著了一般呐萌。 火紅的嫁衣襯著肌膚如雪馁痴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天肺孤,我揣著相機與錄音罗晕,去河邊找鬼济欢。 笑死,一個胖子當(dāng)著我的面吹牛小渊,可吹牛的內(nèi)容都是我干的法褥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼酬屉,長吁一口氣:“原來是場噩夢啊……” “哼半等!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呐萨,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤杀饵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谬擦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凹髓,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年怯屉,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔚舀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡锨络,死狀恐怖赌躺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情羡儿,我是刑警寧澤礼患,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站掠归,受9級特大地震影響缅叠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虏冻,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一肤粱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧厨相,春花似錦领曼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至践磅,卻和暖如春单刁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背府适。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工羔飞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肺樟,地道東北人。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓褥傍,卻偏偏與公主長得像儡嘶,于是被迫代替她去往敵國和親喇聊。 傳聞我的和親對象是個殘疾皇子恍风,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 一.Redis簡介 Redis 是完全開源免費的,是一個高性能的key-value類型的內(nèi)存數(shù)據(jù)庫誓篱。整個數(shù)據(jù)庫統(tǒng)統(tǒng)...
    小星的java學(xué)習(xí)筆記閱讀 23,454評論 0 13
  • NOSQL類型簡介鍵值對:會使用到一個哈希表朋贬,表中有一個特定的鍵和一個指針指向特定的數(shù)據(jù),如redis窜骄,volde...
    MicoCube閱讀 4,000評論 2 27
  • 一锦募、Redis 1、概述 Redis是速度非沉诙簦快的非關(guān)系型內(nèi)存鍵值數(shù)據(jù)庫糠亩,可以存儲鍵和物種不同類型的值之間的映射。...
    落地生涯閱讀 784評論 0 3
  • 數(shù)據(jù)存儲和消息隊列 Redis 1. Redis 有哪些數(shù)據(jù)類型 Redis是一個開源的內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲系統(tǒng)准验。...
    熊先森_5094閱讀 532評論 0 0
  • 貼吧有多牛赎线,流量有多大,這個已經(jīng)毋庸置疑的了糊饱。 而且貼吧的權(quán)重之高垂寥。能讓帖子在百度輕易的被搜索到。 有意通過高權(quán)重...
    徐媛live閱讀 249評論 0 0