你知道的越多,你不知道的越多node
點贊再看,養成習慣git
Redis在互聯網技術存儲方面使用如此普遍,幾乎全部的後端技術面試官都要在Redis的使用和原理方面對小夥伴們進行360°的刁難。面試
做爲一個在互聯網公司面一次拿一次Offer的麪霸,戰勝了無數競爭對手,每次都只能看到無數落寞的身影失望的離開,略感愧疚(請容許我使用一下誇張的修辭手法)。redis
因而在一個寂寞難耐的夜晚,我痛定思痛,決定開始寫《吊打面試官》系列,但願能幫助各位讀者之後面試勢如破竹,對面試官進行360°的反擊,吊打問你的面試官,讓一同面試的同僚瞠目結舌,瘋狂收割大廠Offer!算法
上一期由於是在雙十一一直在熬夜的大環境下完成的,因此我本身以爲質量明顯沒以前的好,我這不一睡好就加班加點準備補償你們,來點乾貨。(熬夜太容易感冒了,此次點個贊別白嫖了!)數據庫
順帶提一嘴,我把我準備寫啥畫了一個思惟導圖,之後總不能每篇都放個賊大的圖吧,就開源到了個人GitHub,你們有興趣能夠去完善和Star。後端
這篇我就先放出來你們看看,感受仍是差點意思,等你們完善了。緩存
上一期吊打系列咱們提到了Redis相關的一些知識,還沒看的小夥伴能夠回顧一下服務器
這期我就從緩存到一些常見的問題講一下,有一些我是以前提到過的,不過可能大部分仔是第一次看,我就重複發一下。
緩存是高併發場景下提升熱點數據訪問性能的一個有效手段,在開發項目時會常用到。
緩存的類型分爲:本地緩存、分佈式緩存和多級緩存。
本地緩存就是在進程的內存中進行緩存,好比咱們的 JVM 堆中,能夠用 LRUMap 來實現,也可使用 Ehcache 這樣的工具來實現。
本地緩存是內存訪問,沒有遠程交互開銷,性能最好,可是受限於單機容量,通常緩存較小且沒法擴展。
分佈式緩存能夠很好得解決這個問題。
分佈式緩存通常都具備良好的水平擴展能力,對較大數據量的場景也能應付自如。缺點就是須要進行遠程請求,性能不如本地緩存。
爲了平衡這種狀況,實際業務中通常採用多級緩存,本地緩存只保存訪問頻率最高的部分熱點數據,其餘的熱點數據放在分佈式緩存中。
在目前的一線大廠中,這也是最經常使用的緩存方案,單考單一的緩存方案每每難以撐住不少高併發的場景。
無論是本地緩存仍是分佈式緩存,爲了保證較高性能,都是使用內存來保存數據,因爲成本和內存限制,當存儲的數據超過緩存容量時,須要對緩存的數據進行剔除。
通常的剔除策略有 FIFO 淘汰最先數據、LRU 剔除最近最少使用、和 LFU 剔除最近使用頻率最低的數據幾種策略。
noeviction:返回錯誤當內存限制達到而且客戶端嘗試執行會讓更多內存被使用的命令(大部分的寫入指令,但DEL和幾個例外)
allkeys-lru: 嘗試回收最少使用的鍵(LRU),使得新添加的數據有空間存放。
volatile-lru: 嘗試回收最少使用的鍵(LRU),但僅限於在過時集合的鍵,使得新添加的數據有空間存放。
allkeys-random: 回收隨機的鍵使得新添加的數據有空間存放。
volatile-random: 回收隨機的鍵使得新添加的數據有空間存放,但僅限於在過時集合的鍵。
volatile-ttl: 回收在過時集合的鍵,而且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
若是沒有鍵知足回收的前提條件的話,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差很少了。
其實在你們熟悉的LinkedHashMap中也實現了Lru算法的,實現以下:
當容量超過100時,開始執行LRU策略:將最近最少未使用的 TimeoutInfoHolder 對象 evict 掉。
真實面試中會讓你寫LUR算法,你可別搞原始的那個,那真TM多,寫不完的,你要麼懟上面這個,要麼懟下面這個,找一個數據結構實現下Java版本的LRU仍是比較容易的,知道啥原理就行了。
注意後面會把 Memcache 簡稱爲 MC。
先來看看 MC 的特色:
另外,使用 MC 有一些限制,這些限制在如今的互聯網場景下很致命,成爲你們選擇Redis、MongoDB的重要緣由:
先簡單說一下 Redis 的特色,方便和 MC 比較。
Redis 的知識點結構以下圖所示。
來看 Redis 提供的功能有哪些吧!
String 類型是 Redis 中最常使用的類型,內部的實現是經過 SDS(Simple Dynamic String )來存儲的。SDS 相似於 Java 中的 ArrayList,能夠經過預分配冗餘空間的方式來減小內存的頻繁分配。
這是最簡單的類型,就是普通的 set 和 get,作簡單的 KV 緩存。
可是真實的開發環境中,不少仔可能會把不少比較複雜的結構也統一轉成String去存儲使用,好比有的仔他就喜歡把對象或者List轉換爲JSONString進行存儲,拿出來再反序列話啥的。
我在這裏就不討論這樣作的對錯了,可是我仍是但願你們能在最合適的場景使用最合適的數據結構,對象找不到最合適的可是類型能夠選最合適的嘛,以後別人接手你的代碼一看這麼規範,誒這小夥子有點東西呀,看到你啥都是用的String,垃圾!
好了這些都是題外話了,道理仍是但願你們記在內心,習慣成天然嘛,小習慣成就你。
String的實際應用場景比較普遍的有:
緩存功能:String字符串是最經常使用的數據類型,不只僅是Redis,各個語言都是最基本類型,所以,利用Redis做爲緩存,配合其它數據庫做爲存儲層,利用Redis支持高併發的特色,能夠大大加快系統的讀寫速度、以及下降後端數據庫的壓力。
計數器:許多系統都會使用Redis做爲系統的實時計數器,能夠快速實現計數和查詢的功能。並且最終的數據結果能夠按照特定的時間落地到數據庫或者其它存儲介質當中進行永久保存。
共享用戶Session:用戶從新刷新一次界面,可能須要訪問一下數據進行從新登陸,或者訪問頁面緩存Cookie,可是能夠利用Redis將用戶的Session集中管理,在這種模式只須要保證Redis的高可用,每次用戶Session的更新和獲取均可以快速完成。大大提升效率。
這個是相似 Map 的一種結構,這個通常就是能夠將結構化的數據,好比一個對象(前提是這個對象沒嵌套其餘的對象)給緩存在 Redis 裏,而後每次讀寫緩存的時候,能夠就操做 Hash 裏的某個字段。
可是這個的場景其實仍是多少單一了一些,由於如今不少對象都是比較複雜的,好比你的商品對象可能裏面就包含了不少屬性,其中也有對象。我本身使用的場景用得不是那麼多。
List 是有序列表,這個仍是能夠玩兒出不少花樣的。
好比能夠經過 List 存儲一些列表型的數據結構,相似粉絲列表、文章的評論列表之類的東西。
好比能夠經過 lrange 命令,讀取某個閉區間內的元素,能夠基於 List 實現分頁查詢,這個是很棒的一個功能,基於 Redis 實現簡單的高性能分頁,能夠作相似微博那種下拉不斷分頁的東西,性能高,就一頁一頁走。
好比能夠搞個簡單的消息隊列,從 List 頭懟進去,從 List 屁股那裏弄出來。
List自己就是咱們在開發過程當中比較經常使用的數據結構了,熱點數據更不用說了。
消息隊列:Redis的鏈表結構,能夠輕鬆實現阻塞隊列,可使用左進右出的命令組成來完成隊列的設計。好比:數據的生產者能夠經過Lpush命令從左邊插入數據,多個數據消費者,可使用BRpop命令阻塞的「搶」列表尾部的數據。
文章列表或者數據分頁展現的應用。
好比,咱們經常使用的博客網站的文章列表,當用戶量愈來愈多時,並且每個用戶都有本身的文章列表,並且當文章多時,都須要分頁展現,這時能夠考慮使用Redis的列表,列表不但有序同時還支持按照範圍內獲取元素,能夠完美解決分頁查詢功能。大大提升查詢效率。
Set 是無序集合,會自動去重的那種。
直接基於 Set 將系統裏須要去重的數據扔進去,自動就給去重了,若是你須要對一些數據進行快速的全局去重,你固然也能夠基於 JVM 內存裏的 HashSet 進行去重,可是若是你的某個系統部署在多臺機器上呢?得基於Redis進行全局的 Set 去重。
能夠基於 Set 玩兒交集、並集、差集的操做,好比交集吧,咱們能夠把兩我的的好友列表整一個交集,看看倆人的共同好友是誰?對吧。
反正這些場景比較多,由於對比很快,操做也簡單,兩個查詢一個Set搞定。
Sorted set 是排序的 Set,去重但能夠排序,寫進去的時候給一個分數,自動根據分數排序。
有序集合的使用場景與集合相似,可是set集合不是自動有序的,而Sorted set能夠利用分數進行成員間的排序,並且是插入時就排序好。因此當你須要一個有序且不重複的集合列表時,就能夠選擇Sorted set數據結構做爲選擇方案。
排行榜:有序集合經典使用場景。例如視頻網站須要對用戶上傳的視頻作排行榜,榜單維護多是多方面:按照時間、按照播放量、按照得到的贊數等。
用Sorted Sets來作帶權重的隊列,好比普通消息的score爲1,重要消息的score爲2,而後工做線程能夠選擇按score的倒序來獲取工做任務。讓重要的任務優先執行。
微博熱搜榜,就是有個後面的熱度值,前面就是名稱
位圖是支持按 bit 位來存儲信息,能夠用來實現 布隆過濾器(BloomFilter);
供不精確的去重計數功能,比較適合用來作大規模數據的去重統計,例如統計 UV;
能夠用來保存地理位置,並做位置距離計算或者根據半徑計算位置等。有沒有想過用Redis來實現附近的人?或者計算最優地圖路徑?
這三個其實也能夠算做一種數據結構,不知道還有多少朋友記得,我在夢開始的地方,Redis基礎中提到過,你若是隻知道五種基礎類型那隻能拿60分,若是你能講出高級用法,那就以爲你有點東西。
功能是訂閱發佈功能,能夠用做簡單的消息隊列。
能夠批量執行一組指令,一次性返回所有結果,能夠減小頻繁的請求應答。
Redis 支持提交 Lua 腳原本執行一系列的功能。
我在前電商老東家的時候,秒殺場景常用這個東西,講道理有點香,利用他的原子性。
話說大家想看秒殺的設計麼?我記得我面試好像每次都問啊,想看的直接點贊後評論秒殺吧。
最後一個功能是事務,但 Redis 提供的不是嚴格的事務,Redis 只保證串行執行命令,而且能保證所有執行,可是執行命令失敗時並不會回滾,而是會繼續執行下去。
Redis 提供了 RDB 和 AOF 兩種持久化方式,RDB 是把內存中的數據集以快照形式寫入磁盤,實際操做是經過 fork 子進程執行,採用二進制壓縮存儲;AOF 是以文本日誌的形式記錄 Redis 處理的每個寫入或刪除操做。
RDB 把整個 Redis 的數據保存在單一文件中,比較適合用來作災備,但缺點是快照保存完成以前若是宕機,這段時間的數據將會丟失,另外保存快照時可能致使服務短期不可用。
AOF 對日誌文件的寫入操做使用的追加模式,有靈活的同步策略,支持每秒同步、每次修改同步和不一樣步,缺點就是相同規模的數據集,AOF 要大於 RDB,AOF 在運行效率上每每會慢於 RDB。
細節的點你們去高可用這章看,特別是二者的優缺點,以及怎麼抉擇。
《吊打面試官》系列-Redis哨兵、持久化、主從、手撕LRU
來看 Redis 的高可用。Redis 支持主從同步,提供 Cluster 集羣部署模式,經過 Sentine l哨兵來監控 Redis 主服務器的狀態。當主掛掉時,在從節點中根據必定策略選出新主,並調整其餘從 slaveof 到新主。
選主的策略簡單來講有三個:
在 Redis 集羣中,sentinel 也會進行多實例部署,sentinel 之間經過 Raft 協議來保證自身的高可用。
Redis Cluster 使用分片機制,在內部分爲 16384 個 slot 插槽,分佈在全部 master 節點上,每一個 master 節點負責一部分 slot。數據操做時按 key 作 CRC16 來計算在哪一個 slot,由哪一個 master 進行處理。數據的冗餘是經過 slave 節點來保障。
哨兵必須用三個實例去保證本身的健壯性的,哨兵+主從並不能保證數據不丟失,可是能夠保證集羣的高可用。
爲啥必需要三個實例呢?咱們先看看兩個哨兵會咋樣。
master宕機了 s1和s2兩個哨兵只要有一個認爲你宕機了就切換了,而且會選舉出一個哨兵去執行故障,可是這個時候也須要大多數哨兵都是運行的。
那這樣有啥問題呢?M1宕機了,S1沒掛那實際上是OK的,可是整個機器都掛了呢?哨兵就只剩下S2個裸屌了,沒有哨兵去容許故障轉移了,雖然另一個機器上還有R1,可是故障轉移就是不執行。
經典的哨兵集羣是這樣的:
M1所在的機器掛了,哨兵還有兩個,兩我的一看他不是掛了嘛,那咱們就選舉一個出來執行故障轉移不就行了。
暖男我,小的總結下哨兵組件的主要功能:
提到這個,就跟我前面提到的數據持久化的RDB和AOF有着比密切的關係了。
我先說下爲啥要用主從這樣的架構模式,前面提到了單機QPS是有上限的,並且Redis的特性就是必須支撐讀高併發的,那你一臺機器又讀又寫,這誰頂得住啊,不當人啊!可是你讓這個master機器去寫,數據同步給別的slave機器,他們都拿去讀,分發掉大量的請求那是否是好不少,並且擴容的時候還能夠輕鬆實現水平擴容。
你啓動一臺slave 的時候,他會發送一個psync命令給master ,若是是這個slave第一次鏈接到master,他會觸發一個全量複製。master就會啓動一個線程,生成RDB快照,還會把新的寫請求都緩存在內存中,RDB文件生成後,master會將這個RDB發送給slave的,slave拿到以後作的第一件事情就是寫進本地的磁盤,而後加載進內存,而後master會把內存裏面緩存的那些新命名都發給slave。
我發出來以後來自CSDN的網友:Jian_Shen_Zer 問了個問題:
主從同步的時候,新的slaver進來的時候用RDB,那以後的數據呢?有新的數據進入master怎麼同步到slaver啊
敖丙答:笨,AOF嘛,增量的就像MySQL的Binlog同樣,把日誌增量同步給從服務就行了
Redis 的 key 能夠設置過時時間,過時後 Redis 採用主動和被動結合的失效機制,一個是和 MC 同樣在訪問時觸發被動刪除,另外一種是按期的主動刪除。
按期+惰性+內存淘汰
這是決定在使用緩存時就該考慮的問題。
緩存的數據在數據源發生變動時須要對緩存進行更新,數據源多是 DB,也多是遠程服務。更新的方式能夠是主動更新。數據源是 DB 時,能夠在更新完 DB 後就直接更新緩存。
當數據源不是 DB 而是其餘遠程服務,可能沒法及時主動感知數據變動,這種狀況下通常會選擇對緩存數據設置失效期,也就是數據不一致的最大容忍時間。
這種場景下,能夠選擇失效更新,key 不存在或失效時先請求數據源獲取最新數據,而後再次緩存,並更新失效期。
但這樣作有個問題,若是依賴的遠程服務在更新時出現異常,則會致使數據不可用。改進的辦法是異步更新,就是當失效時先不清除數據,繼續使用舊的數據,而後由異步線程去執行更新任務。這樣就避免了失效瞬間的空窗期。另外還有一種純異步更新方式,定時對數據進行分批更新。實際使用時能夠根據業務場景選擇更新方式。
第二個問題是數據不一致的問題,能夠說只要使用緩存,就要考慮如何面對這個問題。緩存不一致產生的緣由通常是主動更新失敗,例如更新 DB 後,更新 Redis 由於網絡緣由請求超時;或者是異步更新失敗致使。
解決的辦法是,若是服務對耗時不是特別敏感能夠增長重試;若是服務對耗時敏感能夠經過異步補償任務來處理失敗的更新,或者短時間的數據不一致不會影響業務,那麼只要下次更新時能夠成功,能保證最終一致性就能夠。
緩存穿透。產生這個問題的緣由多是外部的惡意攻擊,例如,對用戶信息進行了緩存,但惡意攻擊者使用不存在的用戶id頻繁請求接口,致使查詢緩存不命中,而後穿透 DB 查詢依然不命中。這時會有大量請求穿透緩存訪問到 DB。
解決的辦法以下。
緩存擊穿,就是某個熱點數據失效時,大量針對這個數據的請求會穿透到數據源。
解決這個問題有以下辦法。
緩存雪崩,產生的緣由是緩存掛掉,這時全部的請求都會穿透到 DB。
解決方法:
實際場景中,這兩種方法會結合使用。
老朋友都知道爲啥我沒有大篇幅介紹這個幾個點了吧,我在以前的文章實在是寫得太詳細了,忍不住點贊那種,我這裏就不作重複拷貝了。
拿筆記一下!
面試的時候問你緩存,主要是考察緩存特性的理解,對 MC、Redis 的特色和使用方式的掌握。
要了解 MC 和 Redis 的經常使用命令,例如原子增減、對不一樣數據結構進行操做的命令等。
瞭解 MC 和 Redis 在內存中的存儲結構,這對評估使用容量會頗有幫助。
瞭解 MC 和 Redis 的數據失效方式和剔除策略,好比主動觸發的按期剔除和被動觸發延期剔除
要理解 Redis 的持久化、主從同步與 Cluster 部署的原理,好比 RDB 和 AOF 的實現方式與區別。
要知道緩存穿透、擊穿、雪崩分別的異同點以及解決方案。
無論你有沒有電商經驗我以爲你都應該知道秒殺的具體實現,以及細節點。
........
歡迎去GitHub補充
若是想要在面試中得到更好的表現,還應瞭解下面這些加分項。
是要結合實際應用場景來介紹緩存的使用。例如調用後端服務接口獲取信息時,可使用本地+遠程的多級緩存;對於動態排行榜類的場景能夠考慮經過 Redis 的 Sorted set 來實現等等。
最好你有過度布式緩存設計和使用經驗,例如項目中在什麼場景使用過 Redis,使用了什麼數據結構,解決哪類的問題;使用 MC 時根據預估值大小調整 McSlab 分配參數等等。
最好能夠了解緩存使用中可能產生的問題。好比 Redis 是單線程處理請求,應儘可能避免耗時較高的單個請求任務,防止相互影響;Redis 服務應避免和其餘 CPU 密集型的進程部署在同一機器;或者禁用 Swap 內存交換,防止 Redis 的緩存數據交換到硬盤上,影響性能。再好比前面提到的 MC 鈣化問題等等。
要了解 Redis 的典型應用場景,例如,使用 Redis 來實現分佈式鎖;使用 Bitmap 來實現 BloomFilter,使用 HyperLogLog 來進行 UV 統計等等。
........
仍是那句話歡迎去GitHub補充。
此次是對我Redis系列的總結,這應該是Redis相關的最後一篇文章了,其實四篇看下來的小夥伴不少都從只知其一;不知其二到了一臉懵逼,哈哈開個玩笑。
我以爲個人方式應該還好,大部分小夥伴仍是比較能理解的,這篇以後我就不會寫Redis相關的文章了(秒殺看你們想看的熱度吧),有啥問題能夠微信找我,下個系列寫啥?
你們不用急,下個系列前我會發個有意思的文章,是我在公司代碼創意大賽拿獎的文章,我以爲仍是有點東西,我忍不住分享一下,順便就在那期發起投票吧哈哈。
我看到不少小夥伴都有評論說想看別的,大概蒐集了一下,還沒留言的這期趕忙喲:
愚辛 :想看計算機基礎,網絡和操做系統那些(FPX牛脾)
cherish君:講講dubbo常常遇到的面試題目,太多人喜歡問dubbo😃
Java架構養成記:真的很香啊,下一期講Dubbbo(重點SPI)而後講MQ好嗎
小殿下:看完了全部的redis篇 但願能夠出ssm
程然:Dubbo Dubbo
linshi2019:這期明顯是趕工之做啊
敖丙:這條我回一下,鞭策我,我很喜歡,不過說實話仍是但願你們理解下,我雙十一熬夜三天了,如今給大家寫的時候也是值班回家2點左右了,我一天吃飯工做時間確定是固定的,想寫點東西就只有擠出睡覺時間了,這種產出確定沒週末全情投入寫的來的質量高。
其實第一期看過來的小夥伴應該也知道,我在排版,還有不少文案,配圖其實我一直都有在改進的,光是名詞高亮我都要弄好久,由於怕你們看單一的黑白色調枯燥。
我是真的用心在搞,仍是但願你們支持下理解下。
知乎、簡書、思否、慕課手記沒人看不知道爲啥,懂行的老鐵能夠跟我說一下。
我只想說大家想看的確定都在我開頭和GITHub那個圖裏吧,問題不大,後面都會寫的。
如今雙十一過去了,我服務器的廣告也無法打來賺錢了,惟一寫做的來源可能就是我微信公衆號文章下面的廣告位,你們能夠點了退出來,微信按點擊給我廣告費,錢很少也算對個人一點支持吧哈哈!不過白嫖也沒事。
喏我寫文章到如今才3塊錢,不過關注我公衆號的人也很少,總之拜託了。
就是點文章下面的這個廣告,點他等於給我投幣了👇
最後感謝下,新浪微博的技術專家張雷。
他於2013年加入新浪微博,做爲核心技術人員參與了微博服務化、混合雲等多個重點項目,是微博開源的RPC框架Motan的技術負責人,同時也負責微博的Service Mesh方案的研發與推廣,專一於高可用架構及服務中間件開發方向。
他負責的Motan框架天天承載着萬億級別的請求調用,是微博平臺服務化的基石,每次的突發熱點事件、每次的春晚流量高峯,都離不開Motan框架的支撐與保障。此外,他也屢次應邀在ArchSummit、WOT、GIAC技術峯會作技術分享。
感謝他對文章部分文案提供的支持和思路。
好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才。
我後面會每週都更新幾篇《吊打面試官》系列和互聯網經常使用技術棧相關的文章。若是你有什麼想知道的,也能夠留言給我,我一有時間就會寫出來,咱們共同進步。
很是感謝人才們能看到這裏,若是這個文章寫得還不錯,以爲「敖丙」我有點東西的話 求點贊👍 求關注❤️ 求分享👥 求留言💬 對暖男我來講 很是有用!!!
各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!
敖丙 | 文 【原創】【轉載請聯繫本人】
《吊打面試官》系列每週持續更新,能夠關注個人公衆號JavaFamily第一時間閱讀和催更(公衆號比博客早一到兩天喲),裏面也有我我的微信有什麼問題也能夠直接滴滴我,咱們一塊兒進步。