【搞定面試官】系列:Redis基礎

引言

在互聯網電商如火如荼發展的大背景下,傳統的關係型數據庫(MySQL、Oracle)已然沒法知足高併發、限時秒殺等複雜的場景。此時NoSQL(非關係型數據庫)應運而生,而Redis就是NoSQL大軍裏的一顆璀璨新星,在大廠面試中也是絕對繞不開的話題。面試

面試開始

> 同窗你好,先簡單作個自動介紹吧?

面試官您好,我叫少俠露飛,……,熟練運用Redis、RocketMQ等中間件。很期待加入貴部門。redis

> 好的,我看你自我介紹時提到了Redis,大家項目裏爲什麼採用Redis,或者說大家是基於什麼場景應用Redis的呢?

什麼?內心忍不住暗罵,這叫啥問題,你們都在用,我就是爲了用而用。可是咱們確定不能把真實想法說出來,作人固然要有點內涵嘛。算法

因而認真答道:「閃閃發光」的面試官您好,由於傳統的MySQL數據庫已經不能適用全部的場景了,好比限時秒殺,大流量削峯等,這些場景瞬時流量可達到數萬甚至數十萬級,這些服務所有打到MySQL,數據庫必然扛不住,很容易被打崩形成服務宕機,因此引入了緩存中間件。在緩存中間件領域有 Redis 和 Memcached 兩個領頭羊,可是Redis支持更多的數據類型,因此在綜合考慮以後選擇了Redis。數據庫

> 嗯,答得不錯,你剛剛提到了數據類型,那介紹一下Redis有哪些數據類型及相應的使用場景吧?

string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)後端

數據類型 特色 使用場景
string key-value 1.緩存功能:Redis做爲緩存層,MySQL做爲存儲層,加速讀寫並下降後端壓力;2.計數器功能,如視頻點擊量、文章瀏覽量等
hash key-field-value 假設要存儲的對象有不少屬性,那麼爲了表示該對象,必然有不少Key來描述該對象,可是接下來假如我修改某個值,還要把這個對象取出來再修改,比較麻煩,因此就有了Hash
list key-value,在一個list首端或末端添加元素 在朋友圈、微博等交友平臺的發帖、回覆、點贊、查看某一帖子點贊數等
set 數據無序且不能重複 set能夠作並集、交集運算,因此在共同好友、二度好友推薦場景下運用較多
zset 數據有序,給每一個member一個分數值,可支持按分數排序 微博等網站的排行榜

說明了這五種基本數據類型並詳細分析了各自的應用場景,千萬不要洋洋自得甚至都要被本身折服了,由於這僅僅是合格。
你想從數千個競爭者中脫穎而出,確定要有些東西,你還須要補充說到這三種數據結構:<font color="#E96900">HyperLogLog、Geo、Pub/Sub</font>緩存

這裏我用一個實際的場景說明一下HyperLogLog。在電商領域,常常要統計某一頁面的PV/UV(分別是瀏覽次數、瀏覽人數)。統計UV時確定要考慮到去重,即同一個用戶一天內不管點擊多少次,都只算做一次。這個時候HyperLogLog就能夠一展能爲了。HyperLogLog是基於基數統計,經過hash碰撞實現,用戶Id經過給定的hash算法每次都會獲得一樣的值,在哈希桶的同一索引位置。固然統計UV不用HyperLogLog也是能夠的,就用set或者string(須要用到setnx)類型同樣可行,這個不急,待會面試官就會問到。
須要注意的是,統計天天的UV,相關的鍵須要設置當天過時,否則你會發現以後天天的UV數據都是異常的。服務器

> 嗯,小夥子對Redis的數據結構掌握的還不錯(心裏已經給你比起了大拇指),剛剛你有提到setnx,能夠簡單說說這個原理及用處麼?

<font color="#E96900">面試絕對不要讓本身處於徹底被動的地位。不知聰明的大家發現了沒有,面試官問的Redis、setnx等問題都是我先在回答中提到的,也就是說面試官能夠自由發問,我也能夠主動的在回答中提到一些知識點,引導面試官詢問相關,化被動爲主動。這樣就儘量的把面試控制在咱們的節奏中。</font>數據結構

回答面試官的問題:setnx經常用做分佈式鎖,setnx核心思想在於爭搶鎖,搶到以後執行相關邏輯,注意執行完以後不要忘記用expire給鎖設置一個過時時間。併發

> 接着面試官開始下一輪的攻勢,問到若是在setnx後再執行expire期間進程意外crash或者服務重啓維護了,那怎麼辦?

這個時候你要當即作出迴應:當這種狀況setnx的鎖就永遠不會被釋放了,這是個危險的操做。
而後稍加思考並給出解決方案:Redis的set包含了豐富的指令參數,這兩個命令能夠合併成一條命令變爲原子操做來執行。異步

> 面試官已經知道面前的小夥不簡單,因而決定加大難度:若是Redis裏面有十億個key,其中有10w是以固定已知前綴開頭的,如何將它們找出來?

使用keys指令能夠掃出指定模式的key列表。
到這裏你還能夠更秀一點。
在這裏插入圖片描述
你接着補充到,可是因爲Redis是單線程模型,若是Redis正在給線上提供服務,keys指令會致使線程阻塞一段時間,線上服務會停頓。這個時候可使用scan指令,scan指令能夠無阻塞的提取出指定模式的key列表,可是會有必定的重複機率,將返回結果手動去重就好了。

> 這個時候面試官已經抑制不住激動的心情了,都學會搶答了,這個小夥子挺有料啊。既然剛剛提到了Redis的線程模型,能夠說下麼?

這個時候不要慌,穩穩的答道:Redis是單線程模型,底層是I/O多路複用(關於此知識點我將會在Nginx的事件驅動模塊作詳細介紹)。

> 此時面試官已經感到面前的小夥不通常了,因而繼續開懟:Redis是一種內存數據庫,數據如何持久化呢?

有兩種方式:RDB作鏡像全量持久化,AOF作增量持久化。由於RDB會耗費較長時間,難以作到實時持久化,在停機的時候會致使大量丟失數據,因此須要AOF來配合使用。在Redis實例重啓時,會使用RDB持久化文件從新構建內存,再使用AOF重放近期的操做指令來實現完整恢復重啓以前的狀態。
這裏很好理解,把RDB理解爲一整個表全量的數據,AOF理解爲每次操做的日誌就行了,服務器重啓的時候先把表的數據所有塞進內存,可是他可能不完整,你再回訪一下日誌,數據不就完整了嘛。不過Redis自己的機制是 AOF持久化開啓且存在AOF文件時,優先加載AOF文件;AOF關閉或者AOF文件不存在時,加載RDB文件;加載AOF/RDB文件以後,Redis啓動成功; AOF/RDB文件存在錯誤時,Redis啓動失敗並打印錯誤信息。

> 持久化的時候忽然斷電了會怎樣?

會丟失數據,但這取決於AOF日誌sync屬性的配置,若是不要求性能,在每條寫指令時都sync一下磁盤,就不會丟失數據。可是在高性能的要求下每次都sync是不現實的,通常都使用定時sync,好比5s1次,這個時候最多就會丟失5s的數據。

> 面試官此時決定跟你卯上了,接着追問:RDB的原理呢?

這裏有兩個關鍵的步驟:fork和COW。fork是指Redis經過建立子進程來進行RDB操做,COW指的是copy on write,子進程建立後,父子進程共享數據段,父進程繼續提供讀寫服務,寫髒的頁面數據會逐漸和子進程分離開來。
注:回答這個問題的時候,若是你還能說出AOF和RDB的優缺點,我以爲面試官都會爲你點讚的,關於此點我會在以後的博客繼續補充。

> 既然在這類問題難不倒你,聰明的面試官決定換個方向問你:使用過Redis作異步隊列麼,怎麼用的?

面試官千方百計的想問倒咱們,咱們就憑藉滿腹經綸化解一次次的危機,所謂振長策而於宇內,奧利給…
認真答道:Redis中通常用list數據結構做爲異步隊列,用rpush生產消息,lpop消費消息。當消費者lpop發現沒有消息的時候要睡眠sleep一會再重試。
此時你再補充說道:除了使用sleep,list還有個指令叫blpop,在沒有消息的時候,它會阻塞直到有新的消息到來。

> 這個時候面試官會以爲你這小夥子對Redis的看法很獨到,在內心已經錄用你100次了。可是,表面上仍是要沉穩,畢竟是久經沙場的老技術人了。問答繼續:像剛剛那種模式,數據blpop以後別的消費者就消費不了了,如何實現生產一次消費屢次呢?

使用pub/sub主題訂閱者模式,能夠實現 1:N 的消息隊列。

> 那麼pub/sub主題訂閱者模式的缺點呢?

該模式有個問題在於消費者下線的時候,生產的消息會丟失,得使用專業的消息隊列RocketMQ或Kafka。

> 若是面試官還不罷休,Redis如何實現延時隊列?

在這裏插入圖片描述
這一系列的連環發問,估計有耐心如你,也想把面試官打一頓:還有完沒完了。疫情這麼嚴重都不敢在外面吃,我得回家本身作飯,人家明天還要上班呢!
在這裏插入圖片描述
可是,爲了大廠的offer,小夥子仍是剋制一下,而後神態自若的回答道:使用有序集合sortedset(zset),以消息內容做爲key,用時間戳做爲score來調用zadd命令生產消息,消費者用zrangebyscore指令獲取N秒以前的數據輪詢進行消費。

> 回答到這裏,面試官已經爲你豎起了大拇指,而且內心默默的給了你A+,可是他還不願中止,篩不篩選人才的無所謂,主要就想問倒你。因而吹響了下一輪進攻的號角:知道pipeline嗎?

能夠將屢次IO往返的時間縮減爲一次,不過有個前提是pipeline執行的指令之間沒有因果相關性。

注:實際上使用redis-benchmark進行壓測的時候能夠發現影響redis的QPS峯值的一個重要因素是pipeline批次指令的數目。

> 瞭解過Redis的同步機制麼?

Redis可使用主從同步,從從同步。第一次同步時,主節點作一次bgsave,並同時將後續修改操做記錄到內存buffer,待完成後將RDB文件全量同步到複製節點,複製節點接受完成後將RDB鏡像加載到內存。加載完成後,再通知主節點將期間修改的操做記錄同步到複製節點進行重放就完成了同步過程。後續的增量數據經過AOF日誌同步便可,有點相似數據庫的binlog。

> 使用過Redis的集羣麼?如何保證集羣的高可用?

Redis Sentinal (Redis哨兵,這個我以後會單獨寫一篇博客介紹)着眼於高可用,在master宕機時會自動將slave提高爲master,繼續提供服務。

Redis Cluster 着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。

面試結束

小夥子能夠啊,我很滿意,咱們部門就缺你這種人才,要不今天就把入職手續辦了吧?
這個時候,你千萬要穩住,按捺一下激動無比的心裏:這麼急啊,疫情這麼嚴重,房子很差找啊,要不下週一吧。
面試官一聽,哎呀,這小夥子估計在手的offer很多啊,這種人才怎麼能放過,不行,人事經理何在,加錢!!!
當這些問題你都一一回答上來了,你是否是都以爲本身很棒呢?

總結

在技術面試的時候,無論是Redis仍是什麼問題,若是你能舉出實際開發過程的問題和收穫會給面試官的印象分會加不少,回答邏輯性也要強一點,不要東一榔頭西一棒子的,容易把本身都繞暈了。
而且面試不該該簡單的一問一答,若能在問題以外擴散一些知識點,面試官會以爲你不僅是一個會寫代碼的人,你邏輯清晰,你對技術選型,對中間件、對項目都有本身的理解和思考,內心天然會給你點讚的。

點點關注,不會迷路

相關文章
相關標籤/搜索