1. 程式人生 > >學習Redis好一陣了,我對它有了一些新的看法

學習Redis好一陣了,我對它有了一些新的看法

> 前言 本篇文章不是一篇具體的教程,我打算記錄一下自己對Redis的一些思考。說來慚愧,我剛接觸Redis的時候只是簡單地使用了一下,背了一些面試題,就在簡歷上寫下了Redis這個技能點。 我們能在網路上輕易地找到關於Redis具體知識點的講解,但很少有文字說明為什麼會有這項技術,我希望通過本文總結一下個人目前對Redis的理解。 ### 1. 初識Redis 最開始的時候,我是通過網路上面的一些專案教程瞭解到Redis的,當時教程裡說把首頁資料放到Redis裡,能夠加快首頁資料的訪問速度,於是我就照做了。程式碼跑起來後,發現好像確實載入得蠻快的,就當完成了。 專案做完後,寫到了簡歷裡,順便在技能裡寫上熟練使用Redis,再背了幾道關於Redis的資料型別,持久化機制的面試題,便去找實習了。 當時面試的時候面試官問我:你為什麼使用Redis呀? 我按照專案教程裡說的複述了一遍:因為能讓首頁更快地載入資料,咱們的產品首頁是很重要,越快加載出資料,使用者越滿意...... 現在回想起來真是哭笑不得,你也不能說這個回答有問題,Redis用作快取的一大亮點就是能夠加快資料查詢效率,但是如果從技術面試的角度看,這個回答其實更應該從技術的角度去答,這也是促使我寫這篇文章的衝動之一。 ### 2. 為什麼要有Redis這項技術?(你為什麼用Redis) 如果現在再被問到為什麼要用Redis,我打算從計算機的儲存結構開始聊。 計算機界有一本名書《深入理解計算機系統》,裡面有一幅關於計算機儲存結構的圖,非常經典: ![](https://images.cnblogs.com/cnblogs_com/tanshaoshenghao/1486568/o_200608014645redis.png) 由圖可見計算機的儲存器是一個金字塔結構,越上層的儲存器儲存效率越高,越下層的儲存效率越低。而計算機中記憶體的層級位於磁碟之上,記憶體的儲存效率要比磁碟快得多。 正常情況下,我們會把應用的資料存放在資料庫中,資料庫把資料存放在磁碟;而Redis是一款基於記憶體的儲存系統,資料都存在記憶體裡,這就是從Redis讀取資料比從資料庫讀取資料要快的根本原因了。 > 看到這裡你可能會說,把資料存在記憶體有啥了不起的,我可以用谷歌的guava呀!再不濟,我可以直接new一個HashMap存資料呀,這不都是基於記憶體的嗎? 這個問題讓我聯想起了我在網上看面經的時候看到的一道題:如果讓你設計一個快取,你會怎麼設計? 大家可以想一下guava和Map集合使用時的缺點是什麼? 很明顯一點就是這兩者雖然基於記憶體,但他們使用的是jvm的記憶體,如果jvm掛掉或者重啟了,資料也就丟失了。這就能方便我們聯想到Redis的持久化機制,Redis的持久化機制使得記憶體中的資料能夠持久化到磁碟上,解決記憶體資料掉電易失的問題,而且Redis是一款中介軟體,無需依賴於jvm。 (當初我只是死背Redis的持久化機制,並沒有想過為什麼。我想搞清楚了這背後的關係後再去學習,能夠學得更紮實一些吧) > 再換一個角度:既然資料庫是因為磁碟才慢,那為啥不再記憶體裡實現資料庫呢? 還別說,SAP公司還真有基於記憶體的資料庫系統,但是使用記憶體有一個致命的缺點:那就是貴!能買得起那套軟體和巨大記憶體機器的公司畢竟是少數,所以說為什麼要使用Redis,就是因為他在低效的磁碟和昂貴的記憶體中取了一個折中。 > 補充:面試的時候還被問到一個問題:Redis的記憶體淘汰機制 當時直接懵圈了,後來想了一下其實這是一個再正常不過的考點了:Redis把資料存放在記憶體,記憶體的空間有限,總會有用完的一天。當記憶體使用完之後肯定需要有相應的記憶體淘汰策略來釋放記憶體。 不過說到記憶體淘汰,我還想起一個高階點的知識點,由於Redis的記憶體是有限的,我們使用記憶體的時候應該更加小心。Redis內部是有許多高效使用記憶體的招數的,比如說我們存放使用者資訊的時候,把使用者資訊存成一個hash,要比把使用者資訊逐條用key-value儲存佔的空間小得多,這些知識你可以在Redid的官網上找到。 ### 3. 關於Redis的主從複製,哨兵,叢集 在學習Redis之前,我對分散式的知識瞭解得非常少。當時為了面試背Redis的面試題,背到有關主從複製,哨兵,叢集等知識點的時候,我既興奮又茫然。感覺自己背完後掌握了許多分散式的知識,但是把這些知識點都揉在一起了,根本不知道這背後的邏輯是什麼。現在想通了一些,應該好好記下來: 在擴充套件到多機之前,我們先想一下單機的Redis有什麼缺點: 1. 有可能出現單點故障,這樣Redis服務就不可用了 2. 單一臺機器的記憶體有限,儲存不了太多的資料 3. 如果訪問量很大的話,單臺機器壓力會很大 通過第一個缺點,我們可以引出為什麼需要主從複製和哨兵。大家想一想,如果我們只有一個Redis服務,要是服務掛了就沒法用了,但如果我們安排多一臺Redis伺服器,它的資料時刻與第一臺Redis的資料保持一致,這樣當第一臺Redis掛掉後,我們就可以把請求遷移到第二臺Redis上,這樣Redis服務的可用性就提高了。為了讓第二臺Redis的資料與第一臺Redis保持一致,我們就需要用到主從複製。 有時候,可能一主一從的配置還是不夠保險,這個時候我們就要為主節點配置兩個或以上的從節點,那麼問題來了,要是主節點掛了,該通過什麼方案在從節點中選出新的主節點呢?這就用到了哨兵機制。 而且在一主多從的情況下,我們使用主從複製讓多臺Redis的資料保持一致,這個時候我們就可以把讀請求分攤到從節點上,這樣能有效緩解主節點的讀壓力。 但如果Redis的寫請求壓力也很大,而且資料量很大,這個時候為Redis增加備份機的橫向擴充套件已經幫不上什麼忙了,這個時候我們就要考慮縱向擴充套件,增加多臺Redis分攤寫請求,讓不同的key落到不同的機器上。這個時候我們就要考慮使用一致性雜湊等演算法把不同的key分給不同的機器。 Redis自身也提供了叢集機制,但內部使用的不是一致性雜湊,而是雜湊槽。簡單來說就是在雜湊槽中劃分不同的區間,不同的區間對應不同的機制;當擴容或縮減的時候有相應的雜湊槽調整策略。 我最初學習Redis的多機策略的時候就是搞不清楚叢集,主從複製,哨兵機制之間的關係。其實叢集就是一套完整的Redis多機解決方案,他有效解決了單機Redis的所有問題。當你在叢集中為某個節點配置從機的時候,主從節點間同步用的就是主從複製。主節點掛掉之後,從節點的選取,內部的邏輯就和哨兵機制相似。當我們使用叢集機制的時候,就可以省去自己寫類似一致性雜湊這樣的分攤邏輯,叢集機制會給節點加上相應的資料結構來完成這些功能。 如果想深入瞭解叢集背後的實現原理,我推薦這樣一個學習路線: 1. 首先登入官網,按照官網的步驟學習配置主從複製,配置哨兵,搭建叢集 2. 然後看《Redis的設計與實現》這本書,閱讀主從複製,哨兵和叢集這三個章節 ### 4. 後話 個人覺得,如果把文章中提到的Redis的點都深入瞭解一下,Redis基本能算入門了。 寫下這篇感想主要也是想提醒自己,學一項技術的時候多問為什麼,這樣知識學到手後不容易忘掉。 至於為什麼說只能說是入門Redis,因為Redis的用法實在太多了,你可以把它當作快取,也可以把它當成資料庫,甚至能把它當作訊息佇列。快取可能大家都很熟悉了,在當資料庫的方面Redis簡直是潛力無限,大家一定要善用它的bitmap點陣圖功能,簡直能在面對複雜需求的時候玩出花來。比如說老闆要統計所有使用者一年中的登入天數,一個使用者只需要365bit(46B)的空間,相比於用傳統的mysql不知道也節省多少倍的空間。 而且在學習Redis的過程中,我越來越感受到計算機基礎的重要性。就拿一個經典問題來說吧: > Redis為什麼這麼快? 雖然說答出基於記憶體能拿個合格的分數。但是作為一個執行在作業系統之上的軟體,你有沒有考慮過它是通過什麼方式從作業系統的網絡卡讀回網路請求資料的呢?作業系統不斷更新迭代的IO系統呼叫,為Redis的快提供了基本的保障,再加上它內建的簡潔精巧的資料結構,讓它成為了一款優秀的基於記憶體的資料結構儲存系統。 說不定再過半年,伴隨著知識和經驗的累積,我會對Redis有更進一步的看法。努力學習,