《Redis深度歷險》讀後總結

最近疫情好多了,好多城市都開始清零。大家還是不要大意,在家再堅持一段時間。疫情期間,有很多安靜的時間,可以用來看平時沒時間看的書。趁着這段時間,來個漂亮的彎道超車(^^)
好了,迴歸正題。今天讀完了掌閱科技技術專家老錢的《Redis深度歷險》。書不錯,學到了很多東西。好記性不如爛筆頭,在此記錄一下,方便記憶。
全書共分爲五章
基礎和應用篇;原理篇;集羣篇;拓展篇;源碼篇

基礎和應用篇,主要介紹了一下redis五種常見數據結構的使用方式
沒有什麼可說的,這個大家應該都很熟悉了。值得注意的是zset的數據結構是跳躍表。跳躍表的設計,在我上一篇博客中已經簡要介紹了一下,跳躍表的設計非常的優雅,感興趣的同學可以研究一下。
應用篇裏提到了HyperLogLog數據結構,這個數據結構我們可以想象爲是一個set結構的增強版。set如果存儲上百萬的數據,耗費的空間是驚人的。HyperLogLog可以用來對上百萬的數據做一個去重功能,而且需要的空間很小。但是有一個缺點,它得出來的數據量不準確,標準誤差是0.81%。100萬數據的話,HyperLogLog統計的數量大概在991900個,對於一些要求不是很高的場景來說,已經夠用了。
緊接着,書中介紹了布隆過濾器。布隆過濾器在高併發的場景中非常的有用。布隆過濾器就是一個大的位數組和幾個無偏hash函數。同一個key到來時,通過這幾個hash函數分別對key求hash,得到一個整數的索引值,然後使用該索引值對位數組求模運算得到一個維數組的下標值,然後將該值置爲1。同樣的,其他幾個hash函數對key求hash,最後也將位數組的某個位置置爲1。下一個key來請求的時候,使用同樣的hash函數對其求hash值,如果對應的位數組位置都是1 ,說明這個布隆過濾器見過這個key。bf.exists就會返回1。布隆過濾器也是有誤差的。布隆過濾器說某個值存在時,它可能不存在。但是如果布隆過濾器說某個值沒見過時,那它一定是沒見過。這個特性可以很好的用來防止緩存穿透攻擊。不過,布隆過濾器的使用,redis要升級到4.0版本,通過模塊使用纔可以。github上有人在維護,可以下載下來,將布隆過濾器配置在redis的配置文件裏就可以使用了。
基礎篇裏講到了一個非常有意思的模塊,GeoHash。它可以計算出附進的人。我們輸入自己的座標,然後輸入別人的座標。它可以計算出你們兩個的距離,同時你輸入自己的座標,然後指定一個距離,它可以計算出你附近的元素。我們可以將Geo模塊想象成zset結構,通過score排序就可以得到座標附近的其他元素。Geo的數據存儲是通過zset結構。單個key的大小不宜超過1MB,否則會導致集羣遷移出現卡頓現象。所以,建議Geo模塊使用單獨的redis實例部署,不使用集羣環境。如果數據量過億個,甚至更大,就要對Geo數據按照一定的規律拆分,降低單個zset結構的大小
基礎篇的最後,講了scan命令。和它意思差不多的命令是keys命令。但是keys命令在大數量的場景下,非常的危險。因爲它會一次性吐出滿足條件的所有key,如果key的數量超過千萬級,這條命令會直接導致redis卡頓,影響redis正常的讀寫請求。所有的redis讀寫指令都要等這個keys命令執行完才能正常執行。
scan命令完美的解決了以上問題,它提供了limit參數,可以控制每次遍歷的hash槽的數量。某次遍歷可能沒有返回任何數據,但是不代表遍歷已經完成。只有當返回的遊標值爲0時,纔是真正的遍歷完成。不同的數據結構有不同的scan命令,hsan可以遍歷hash結構,zscan可以遍歷zset,sscan可以遍歷set。
scan命令還可以掃描大key,大key對於集羣的遷移非常有影響。不過,如果使用scan命令掃描大key,需要寫腳本。redis官方在redis-cli命令中提供了這樣的功能,一條命令就可以得到當前redis環境中的大key信息,很直觀。
以上就是基礎篇重點內容

下一篇是原理篇
原理篇,先講的是redis的IO模型
redis的IO模型是IO多路複用。關於redis的多路複用,我前面也有一篇文章,感興趣的可以看一下。IO多路複用,我理解就一句話。之前的socket是順序執行,現在的多個socket被linux內核監控起來,可讀可寫時就返回可讀可寫的狀態。這樣就可以順序執行已經就緒的socket,省了很多無用的操作。
之後,非常重要的一個環節介紹是redis的持久化機制。我們知道redis是完全基於內存操作的。那麼一旦redis宕機,所有的數據都會丟失。這對於生產環境來說是災難性的。所以,這就引出了redis的持久化機制,redis的持久化機制一共有兩種。RDB和AOF。前者是快照模式,後者是連續的增量備份模式。
快照模式就是,redis會調用glibc函數fork一個子進程。由子進程執行持久化操作。父進程繼續處理客戶端的請求。一次性就redis中的所有數據全部持久化,這裏面涉及到了COW機制。
redis默認是RDB模式,默認策略是:
900 1
300 10
60 10000
900秒內有1個key變更
300秒內有10個key變更
60秒內有10000個key變更
以上情況都會觸發快照模式持久化,生成一個rdb文件。redis重啓時,會加載持久化文件中的數據
第二種持久化機制是AOF模式,redis會將redis實例啓動以來所有修改性的指令全部持久化到AOF文件中,當redis服務端收到客戶端的修改性指令時,先校驗然後執行,最後寫入AOF文件。當redis啓動時,讀取AOF文件中的內容。注意,redis是先執行指令然後再生成AOF文件,這不同於很多的存儲引擎。redis爲什麼要這樣做?
因爲redis認爲,除非程序員自己輸錯,否則redis指令不會出現錯誤。如果先記日誌,就會導致AOF中有大量的錯誤指令。程序員先把命令輸入正確,redis再記日誌。
AOF增量備份模式是以文件的形式存在的,調用Linux提供的fsync(int fd)函數強制將指定文件的內容從內核緩存刷到磁盤。只要redis進程實時調用fsync函數就可以保證redis數據不丟失。默認情況下,redis每秒鐘調用一次fsync函數,這個時間可以調,我們要在性能和安全性之間做一個權衡。除此之外,redis還提供了兩種策略,一種是永不調用fsync函數,由linux系統決定何時將數據刷到磁盤中。一種是每執行一次指令調用一次fsync函數。這兩種在生產上用的都不多.
以上這兩種模式,都有缺點:
1 .RDB方式大塊寫磁盤,會加重系統負擔
2 .AOF方式每秒調用一次fsync,這是一個耗時的操作。會降低redis的性能。同時也會加重IO負擔
基於以上2點原因,redis的主節點不會進行持久化操作,持久化操作一般都會在從節點上進行。但是這樣做,一定要注意主節點和從節點的同步工作,一旦出現網絡分區,主節點沒有及時將數據同步到從節點,就會導致數據丟失,所以生產上要注意多增加幾個從節點。並做好對redis的監控工作
重啓redis時,一般不會採用rdb恢復內存數據,因爲會丟失大量數據。但是重放AOF日誌,redis啓動時間又太長
redis4.0採用了一種混合持久化的方式。也就是將rdb文件和增量的aof文件放在一起,這裏的aof文件不再是全量的aof文件,而是rdb持久化開始到持久化結束的增量數據,通常這部分數據很少。所以,當redis4.0啓動時,可以先加載rdb的內容,然後再重放aof的文件內容,大大提高了重啓的效率
接着,本書介紹了redis的管道操作,以及redis的事務。redis的管道操作對於操作同一個key來說的話,效率非常高,它的原理是將相同的操作放在一起,比如讀讀,寫寫。redis的事務不具備原子性。
用的不多。之後講了redis的發佈訂閱,redis原生的發佈訂閱是不具備持久化能力的,這就意味着一旦redis的訂閱端宕機,宕機這段期間的消息就會全部丟失。所以,基於這個原因redis作者在5.0版本搞了一個stream數據結構,用來做持久化的消息隊列。

接着進入拓展篇
首先介紹redis的過期策略。redis的過期策略是redis會將設置了過期時間的key全部放入一個獨立的字典中。每隔100毫秒掃描一次字典。但是redis沒有說全部掃描,而是隨機從字典中選取20個key,然後刪除這20個key中已經過期的key,如果過期key的比例超過所有key比例的1/4,此時就會繼續掃描20個key。如果這個操作過於頻繁,redis會將掃描時間縮短到25毫秒一次,加快過期key的回收。除了這種過期策略,redis還提供了懶惰刪除,也就是當訪問這個key的時候檢查檢查該key是否失效。
所以,redis會持續掃描這個過期key集合。直到其中的key變的稀疏(可能會持續多次),所以在此期間,一個正常的客戶端請求到了,該請求至少會等待25毫秒。這樣在生產中就會帶來一個問題,如果我們將請求redis的超時時間設置的太短,比如:10毫秒,此時就會出現大量的請求超時。而且該種超時,不屬於慢查詢。無法查詢出來。另外,我們要注意給key的過期時間都加上一個隨機值,防止大量的key在同一時間過期,造成緩存擊穿。
redis的LRU策略,當redis的內存不足時,redis提供了多個LRU策略maxmemory-policy。redis的內存參數配置爲:maxmemory
默認是:不能寫,只能讀。
redis採取的LRU淘汰策略是一種近似的LRU淘汰算法,使用隨機採樣法。隨機挑出5個key,刪除最舊的key,如果內存還是超出maxmemory。繼續以上操作。
接着,我們講一下懶惰刪除,這個操作在生產上來說,非常的重要。對於一個很大的key來說,如果我們直接del的話,很可能會導致單線程卡頓。此時,我們就會用到懶惰刪除。懶惰刪除的根本原理就是服務端發出一個刪除命令,然後交給異步線程後臺操作。比如刪除:
unlink key。
比如flushall,對應的就是flushall async
很好的解決了卡頓的問題。
下面說了一些redis的安全操作,比如:我們限制redis的訪問ip
bind,再比如:keys命令很危險,我們可以直接在生產上把keys命令禁用掉,可以直接在配置文件的securiry模塊中增加
rename-command flushall " "
這樣flushall命令就不能用了
然後關於安全,老錢講解了spiped,用來在客戶端和服務端之間構建ssl通道,防止redis跨機房訪問時被竊聽數據。
最後一章,講到了redis5種數據類型的底層實現。
總體來說,redis就是一個大的hashmap,key對redis可見,value對redis不可見。value可以是任何值,比如list,zset等等。zset的數據結構,面試常問,感興趣的,可以去看我的上一篇博客。
好了,這本書的總結就到這裏了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章