《吊打面試官》系列-Redis終章_凜冬將至、FPX_新王登基

你知道的越多,你不知道的越多git

點贊再看,養成習慣github

GitHub上已經開源github.com/JavaFamily,有一線大廠面試點腦圖,歡迎Star和完善面試

前言

Redis在互聯網技術存儲方面使用如此普遍,幾乎全部的後端技術面試官都要在Redis的使用和原理方面對小夥伴們進行360°的刁難。做爲一個在互聯網公司面一次拿一次offer的麪霸(請容許我使用一下誇張的修辭手法),戰勝了無數競爭對手,每次都只能看到無數落寞的身影失望的離開,略感愧疚,在一個寂寞難耐的夜晚,我痛定思痛,決定開始寫《吊打面試官》系列,但願能幫助各位讀者之後面試勢如破竹,對面試官進行360°的反擊,吊打問你的面試官,讓一同面試的同僚瞠目結舌,瘋狂收割大廠offer!redis

絮叨

男兒何不帶吳鉤,收取關山五十州 FPX 🐂B,LPL兩年連冠🏆 🐂B!算法

看着金色的雨落下,我到窗邊,發現天有點藍,風有點綿,個人眼角又溼了!數據庫

最近雙十一講道理有點忙的說,直接肝爆,就是這樣做爲暖男的我,仍是給大家擠出時間搞出終章,忍不住給本身點贊👍後端

放個雙十一照片證實真的忙,但願別取關!!!緩存

如今大家在看的時候,我應該還在睡覺哈哈。困🛌服務器

以前跟大家說的,限流降級,是否是在雙十一又應驗了,下單接口其實沒掛,犧牲部分用戶體驗,保住服務器,你多點幾下是能夠成功的,等流量高峯過去了,全部的用戶所有都恢復正常訪問,服務器也沒啥事。微信

去年退款接口被打崩了,今年阿里明顯也聰明瞭不少。

正文

上幾期吊打系列咱們提到了Redis的不少知識,還沒看的小夥伴能夠回顧一下

那提到Redis我相信各位在面試,或者實際開發過程當中對基本類型的使用場景,併發競爭帶來的問題,以及緩存數據庫雙寫入一致性的問題等,咱們有請下一位受害者。

面試開始

一個大腹便便,穿着格子襯衣的中年男子,拿着一個盡是劃痕的mac向你走來,看着快禿頂的頭髮,心想着確定是尼瑪頂級架構師吧!可是咱們腹有詩書氣自華,虛都不虛。(這不是第一篇文章的面試官麼?)

小夥子,你還記得我在第一章裏面問過你,Redis有幾種基礎數據類型麼?

嗯嗯,帥氣的面試官,我確定記得,沒齒難忘!!!

我特麼謝謝你,都四面了還不給Offer!

那你能說一下他們的特性,還有分別的使用場景麼?

行吧,那我先從String提及。

String:

這是最簡單的類型,就是普通的 set 和 get,作簡單的 KV 緩存。

可是真實的開發環境中,不少仔可能會把不少比較複雜的結構也統一轉成String去存儲使用,好比有的仔他就喜歡把對象或者List轉換爲JSONString進行存儲,拿出來再反序列話啥的。

我在這裏就不討論這樣作的對錯了,可是我仍是但願你們能在最合適的場景使用最合適的數據結構,對象找不到最合適的可是類型能夠選最合適的嘛,以後別人接手你的代碼一看這麼規範,誒這小夥子有點東西呀,看到你啥都是用的String垃圾!

好了這些都是題外話了,道理仍是但願你們記在內心,習慣成天然嘛,小習慣成就你。

String的實際應用場景比較普遍的有:

  • 緩存功能:String字符串是最經常使用的數據類型,不只僅是Redis,各個語言都是最基本類型,所以,利用Redis做爲緩存,配合其它數據庫做爲存儲層,利用Redis支持高併發的特色,能夠大大加快系統的讀寫速度、以及下降後端數據庫的壓力。

  • 計數器:許多系統都會使用Redis做爲系統的實時計數器,能夠快速實現計數和查詢的功能。並且最終的數據結果能夠按照特定的時間落地到數據庫或者其它存儲介質當中進行永久保存。

  • 共享用戶Session:用戶從新刷新一次界面,可能須要訪問一下數據進行從新登陸,或者訪問頁面緩存Cookie,可是能夠利用Redis將用戶的Session集中管理,在這種模式只須要保證Redis的高可用,每次用戶Session的更新和獲取均可以快速完成。大大提升效率。

Hash:

這個是相似 Map 的一種結構,這個通常就是能夠將結構化的數據,好比一個對象(前提是這個對象沒嵌套其餘的對象)給緩存在 Redis 裏,而後每次讀寫緩存的時候,能夠就操做 Hash 裏的某個字段

可是這個的場景其實仍是多少單一了一些,由於如今不少對象都是比較複雜的,好比你的商品對象可能裏面就包含了不少屬性,其中也有對象。我本身使用的場景用得不是那麼多。

List:

List 是有序列表,這個仍是能夠玩兒出不少花樣的。

好比能夠經過 List 存儲一些列表型的數據結構,相似粉絲列表、文章的評論列表之類的東西。

好比能夠經過 lrange 命令,讀取某個閉區間內的元素,能夠基於 List 實現分頁查詢,這個是很棒的一個功能,基於 Redis 實現簡單的高性能分頁,能夠作相似微博那種下拉不斷分頁的東西,性能高,就一頁一頁走。

好比能夠搞個簡單的消息隊列,從 List 頭懟進去,從 List 屁股那裏弄出來。

List自己就是咱們在開發過程當中比較經常使用的數據結構了,熱點數據更不用說了。

  • 消息隊列:Redis的鏈表結構,能夠輕鬆實現阻塞隊列,可使用左進右出的命令組成來完成隊列的設計。好比:數據的生產者能夠經過Lpush命令從左邊插入數據,多個數據消費者,可使用BRpop命令阻塞的「搶」列表尾部的數據。

  • 文章列表或者數據分頁展現的應用。

    好比,咱們經常使用的博客網站的文章列表,當用戶量愈來愈多時,並且每個用戶都有本身的文章列表,並且當文章多時,都須要分頁展現,這時能夠考慮使用Redis的列表,列表不但有序同時還支持按照範圍內獲取元素,能夠完美解決分頁查詢功能。大大提升查詢效率。

Set:

Set 是無序集合,會自動去重的那種。

直接基於 Set 將系統裏須要去重的數據扔進去,自動就給去重了,若是你須要對一些數據進行快速的全局去重,你固然也能夠基於 JVM 內存裏的 HashSet 進行去重,可是若是你的某個系統部署在多臺機器上呢?得基於Redis進行全局的 Set 去重。

能夠基於 Set 玩兒交集、並集、差集的操做,好比交集吧,咱們能夠把兩我的的好友列表整一個交集,看看倆人的共同好友是誰?對吧。

反正這些場景比較多,由於對比很快,操做也簡單,兩個查詢一個Set搞定。

Sorted Set:

Sorted set 是排序的 Set,去重但能夠排序,寫進去的時候給一個分數,自動根據分數排序。

有序集合的使用場景與集合相似,可是set集合不是自動有序的,而Sorted set能夠利用分數進行成員間的排序,並且是插入時就排序好。因此當你須要一個有序且不重複的集合列表時,就能夠選擇Sorted set數據結構做爲選擇方案。

  • 排行榜:有序集合經典使用場景。例如視頻網站須要對用戶上傳的視頻作排行榜,榜單維護多是多方面:按照時間、按照播放量、按照得到的贊數等。

  • Sorted Sets來作帶權重的隊列,好比普通消息的score爲1,重要消息的score爲2,而後工做線程能夠選擇按score的倒序來獲取工做任務。讓重要的任務優先執行。

    微博熱搜榜,就是有個後面的熱度值,前面就是名稱

小結

Redis基礎類型有五種,這個我在基礎裏面也有提到了,這個問題其實通常都是對P6如下,也就是1-3年左右的小夥伴多是會問得比較多的問題。

能回答出來五種我想你們均可以,可是不知道你們是否知道,五種類型具體的使用場景,以及何時用什麼類型最合適呢?

要是你回答的很差,沒說出幾種數據類型,也沒說什麼場景,你完了,面試官對你印象確定很差,以爲你平時就是作個簡單的 set 和 get。因此看似很簡單的面試題實則最容易看出你的深淺了,你們都要注意打好基礎

你有沒有考慮過,若是你多個系統同時操做(併發)Redis帶來的數據問題?

嗯嗯這個問題我之前開發的時候遇到過,其實併發過程當中確實會有這樣的問題,好比下面這樣的狀況

系統A、B、C三個系統,分別去操做Redis的同一個Key,原本順序是1,2,3是正常的,可是由於系統A網絡忽然抖動了一下,B,C在他前面操做了Redis,這樣數據不就錯了麼。

就比如下單,支付,退款三個順序你變了,你先退款,再下單,再支付,那流程就會失敗,那數據不就亂了?你訂單還沒生成你卻支付,退款了?明顯走不通了,這在線上是很恐怖的事情。

那這種狀況怎麼解決呢?

咱們能夠找個管家幫咱們管理好數據的嘛!

某個時刻,多個系統實例都去更新某個 key。能夠基於 Zookeeper 實現分佈式鎖。每一個系統經過 Zookeeper 獲取分佈式鎖,確保同一時間,只能有一個系統實例在操做某個 Key,別人都不容許讀和寫。

你要寫入緩存的數據,都是從 MySQL 裏查出來的,都得寫入 MySQL 中,寫入 MySQL 中的時候必須保存一個時間戳,從 MySQL 查出來的時候,時間戳也查出來。

每次要寫以前,先判斷一下當前這個 Value 的時間戳是否比緩存裏的 Value 的時間戳要新。若是是的話,那麼能夠寫,不然,就不能用舊的數據覆蓋新的數據。

你只要用緩存,就可能會涉及到緩存與數據庫雙存儲雙寫,你只要是雙寫,就必定會有數據一致性的問題,那麼你如何解決一致性問題?

通常來講,若是容許緩存能夠稍微的跟數據庫偶爾有不一致的狀況,也就是說若是你的系統不是嚴格要求 「緩存+數據庫」 必須保持一致性的話,最好不要作這個方案,即:讀請求和寫請求串行化,串到一個內存隊列裏去。

串行化能夠保證必定不會出現不一致的狀況,可是它也會致使系統的吞吐量大幅度下降,用比正常狀況下多幾倍的機器去支撐線上的一個請求。

把一些列的操做都放到隊列裏面,順序確定不會亂,可是併發高了,這隊列很容易阻塞,反而會成爲整個系統的弱點,瓶頸

你瞭解最經典的KV、DB讀寫模式麼?

最經典的緩存+數據庫讀寫的模式,就是 Cache Aside Pattern

  • 讀的時候,先讀緩存,緩存沒有的話,就讀數據庫,而後取出數據後放入緩存,同時返回響應。
  • 更新的時候,先更新數據庫,而後再刪除緩存

爲何是刪除緩存,而不是更新緩存?

緣由很簡單,不少時候,在複雜點的緩存場景,緩存不僅僅是數據庫中直接取出來的值。

好比可能更新了某個表的一個字段,而後其對應的緩存,是須要查詢另外兩個表的數據並進行運算,才能計算出緩存最新的值的。

另外更新緩存的代價有時候是很高的。是否是說,每次修改數據庫的時候,都必定要將其對應的緩存更新一份?也許有的場景是這樣,可是對於比較複雜的緩存數據計算的場景,就不是這樣了。若是你頻繁修改一個緩存涉及的多個表,緩存也頻繁更新。可是問題在於,這個緩存到底會不會被頻繁訪問到?

舉個栗子:一個緩存涉及的表的字段,在 1 分鐘內就修改了 20 次,或者是 100 次,那麼緩存更新 20 次、100 次;可是這個緩存在 1 分鐘內只被讀取了 1 次,有大量的冷數據

實際上,若是你只是刪除緩存的話,那麼在 1 分鐘內,這個緩存不過就從新計算一次而已,開銷大幅度下降。用到緩存纔去算緩存。

其實刪除緩存,而不是更新緩存,就是一個 Lazy 計算的思想,不要每次都從新作複雜的計算,無論它會不會用到,而是讓它到須要被使用的時候再從新計算。

MybatisHibernate,都有懶加載思想。查詢一個部門,部門帶了一個員工的 List,沒有必要說每次查詢部門,都裏面的 1000 個員工的數據也同時查出來啊。80% 的狀況,查這個部門,就只是要訪問這個部門的信息就能夠了。先查部門,同時要訪問裏面的員工,那麼這個時候只有在你要訪問裏面的員工的時候,纔會去數據庫裏面查詢 1000 個員工。

Redis 和 Memcached 有啥區別,爲啥選擇用Redis做爲大家的緩存中間件?

Redis 支持複雜的數據結構:

Redis 相比 Memcached 來講,擁有更多的數據結構,能支持更豐富的數據操做。若是須要緩存可以支持更復雜的結構和操做, Redis 會是不錯的選擇。

Redis 原生支持集羣模式:

在 redis3.x 版本中,便能支持 Cluster 模式,而 Memcached 沒有原生的集羣模式,須要依靠客戶端來實現往集羣中分片寫入數據。

性能對比:

因爲 Redis 只使用單核,而 Memcached 可使用多核,因此平均每個核上 Redis 在存儲小數據時比 Memcached 性能更高。而在 100k 以上的數據中,Memcached 性能要高於 Redis,雖然 Redis 最近也在存儲大數據的性能上進行優化,可是比起 Remcached,仍是稍有遜色。

Tip:其實面試官這麼問,是想看你知道爲啥用這個技術棧麼?你爲啥選這個技術棧,你是否作過技術選型的對比,優缺點你是否瞭解,你啥都不知道,只是爲了用而用,那你可能就差點意思了。

Redis 的線程模型瞭解麼?

Redis 內部使用文件事件處理器 file event handler,這個文件事件處理器是單線程的,因此 Redis 才叫作單線程的模型。它採用 IO 多路複用機制同時監聽多個 Socket,根據 Socket 上的事件來選擇對應的事件處理器進行處理。

文件事件處理器的結構包含 4 個部分:

  • 多個 Socket
  • IO 多路複用程序
  • 文件事件分派器
  • 事件處理器(鏈接應答處理器、命令請求處理器、命令回覆處理器)

多個 Socket 可能會併發產生不一樣的操做,每一個操做對應不一樣的文件事件,可是 IO 多路複用程序會監聽多個 Socket,會將 Socket 產生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應的事件處理器進行處理。

面試結束

小夥子對你面試了四輪,你說話有理有據,邏輯清晰,來公司後確定是一把好手,我想要不你來當個人Leader吧,哈哈?

面試官別跟我開玩笑了,我跟您這樣日積月累的技術專家仍是有不少差距的,您的經驗和技術上的深度,沒有很長時間的磨練是沒法達到的,我還得多跟您學習。

好的,小夥子有點東西,你年少有爲不自卑,知道什麼是珍貴,就是你了來上班吧。

好的面試官,不過我想我在Java基礎,MQ,Dubbo等等領域還有好多知識點您沒問我,要不下次繼續面我?

強行,爲吊打下一期埋伏筆哈哈,下期寫啥大家定!!!

能撐到最後,你本身都忍不住本身給本身點個讚了!

暗示點贊,每次都看了不點贊,大家想白嫖我麼?大家好壞喲,不過我喜歡)。


《吊打面試官》Redis系列 ---- 全劇終


總結

既然都說了是Redis的終章我最後也作個Redis方面常見面試題,題目的總結,答案你們要去思考我前面的文章基本上都提到了,結果能夠去我公衆號回覆【答案】獲取,不過我仍是但願你們能看到題目就能想到答案,而且記在心中,教你們怎麼回答只是幫你們組織下語言,真正的場景解決方案仍是要你們理解的。

(週三之後出答案,我先睡會)

  • 0、在集羣模式下,Redis 的 Key 是如何尋址的?分佈式尋址都有哪些算法?瞭解一致性 Hash 算法嗎?
  • 一、使用Redis有哪些好處?
  • 二、Redis相比Memcached有哪些優點?
  • 三、Redis常見性能問題和解決方案
  • 四、MySQL裏有2000w數據,Redis中只存20w的數據,如何保證Redis中的數據都是熱點數據?
  • 五、Memcache與Redis的區別都有哪些?
  • 六、Redis 常見的性能問題都有哪些?如何解決?
  • 七、在什麼樣的場景下能夠充分的利用Redis的特性,大大提升Redis的效率?
  • 八、Redis的緩存雪崩、穿透、擊穿瞭解麼?有什麼異同點?分別怎麼解決?
  • 九、Redis的基本類型有哪些?他們的使用場景瞭解麼?比較高級的用法你使用過麼?
  • 十、Redis主從怎麼同步數據的?集羣的高可用怎麼保證?持久化機制瞭解麼?
  • 十一、爲何 redis 單線程卻能支撐高併發?
  • 十二、如何保證緩存和數據庫數據的一致性?
  • 1三、項目中是怎麼用緩存的,用了緩存以後會帶來什麼問題?

絮叨+

最後我想說的就是,我這四章只是介紹到了一些Redis面試比較常見的問題,其實還有不少點我都沒回答到,你們若是爲了對付面試可能是夠用了,可是咱們技術人員仍是要保持對技術的敬畏心,你不能淺嘗即止,仍是要深究的。

你永遠只會用,不去考慮用了會帶來的問題,以及出現問題以後的解決方案,我以爲你大機率會停滯不前,既然入都入了這行了,爲啥不武裝一下本身。

其實學習技術是個反哺的過程,學習的時候可能你只是感受知識廣度、深度上去了,一個知識點你這樣,兩個、三個知識點你都這樣,最後你發現你的技術已經跟身邊同樣P6的仔不同了,這樣你可能在團隊重大項目的貢獻都上去了,那P7的晉升概率是否是大了,錢是否是上去了,女友是否是好看了,房子是否是大了。

End

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才,我後面會每週都更新幾篇《吊打面試官》系列和Java技術棧相關的文章。若是你有什麼想知道的,也能夠留言給我,或者去公衆號加我微信,我一有時間就會寫出來,咱們共同進步。

很是感謝人才們能看到這裏,若是這個文章寫得還不錯,以爲「敖丙」有點東西的話 求點贊👍 求關注❤️ 求分享👥 求留言💬 對暖男我來講很是有用

各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!

敖丙 | 文 【原創】【轉載請聯繫本人】


《吊打面試官》系列每週持續更新,能夠關注個人公衆號「 JavaFamily 」第時間閱讀和催更(公衆號比博客早一到兩天喲),裏面也有我我的微信有什麼問題也能夠直接滴滴我,我也是個新人,不過不影響咱們一塊兒進步,做爲渣男,我給不了你幸福,還給不了你溫暖嘛?

相關文章
相關標籤/搜索