Redis系列總結–這幾點你會了嗎?

  • 2019 年 10 月 11 日
  • 筆記

前面幾篇已經對Redis中幾個關鍵知識點做了介紹,本篇主要對Redis系列做一下總結以及對Redis中常見面試題簡單進行介紹一下。首先我們對前面幾篇談到的Redis知識點進行總結。

第1篇:Redis系列開篇文章可以一文了解Redis

第2篇:通過對比RedisMemcached的區別來解釋Redis為什麼高性能。

第3篇:Redis中使用最頻繁的有5種數據類型:String、List、Hash、Set、SortSet。本篇對Redis中常用的5種數據類型進行了細微的講解以及常用場景進行介紹。

第4篇:如果同一台機器有多個執行緒搶奪同一個共享資源,同一個執行緒多次執行會出現異常,這種情況下就會出現非執行緒安全。我們解決方法通常使用鎖來解決。但是如果有多台機器呢?這時候我們通常使用分散式鎖來解決分散式環境下共享資源的同步問題。本篇對於單機部署分散式鎖幾種常規方案進行分別的說明。

第5篇:對保持雙庫數據一致性方案進行了分析以及分析通用的保持數據一致性的方案。

第6篇:主要針對Redis的記憶體淘汰機制以及Redis容易引發的三大問題:快取擊穿、快取穿透以及快取雪崩進行了詳細的講解以及提供了業界常用的解決方案。因為涉及到快取淘汰機制,所以內容包含快取淘汰機制的知識點。

第7篇:Redis受開發者歡迎的一大原因就是因為可持久化的特性。我們如何保證Redis宕機之後重啟可以將數據進行恢復?所以一般情況下我們需要定時進行持久化將記憶體中的數據寫入到硬碟中。而Redis中支援兩種不同的持久化機制:RDB持久化以及AOF持久化。

第8篇:在80%左右企業使用的都是Redis單機服務,在生產環境下使用單機環境的Redis容易面臨風險,如果Redis持久化的硬碟出現故障,則有可能導致持久化的備份數據出現丟失,所以我們需要一個方案解決這個問題,所以我們需要將原來集中式的資料庫中的數據分別複製到不同Redis節點上進行存儲,這也就是Redis中的主從複製。

第9篇:Redis主從複製實際上就是將主Redis節點的數據,複製到其他從Redis節點去進行存儲,當主節點因為出現異常宕機後,如何將從節點切換成主節點繼續提供服務呢?Redis主從切換主要分為以下兩種方式:手動切換以及哨兵模式。

第10篇:如果沒有分片機制,Redis就被局限於單機所支援的記憶體容量。Redis的分片機制允許數據拆分存放在不同的Redis實例上,每個Redis實例只包含所有鍵的子集。可以減輕單台Redis的壓力,提升Redis擴展能力和計算能力。

對前面Reids系列文章簡單做了總結,接下來我們一起看看Reids幾道比較常見的面試題吧。

簡單介紹一下Redis

redis是一個key-value存儲系統。它支援存儲的value類型相對更多,包括string(字元串)、list(鏈表)、set(集合)、zset(sorted set)和hash(哈希類型)。這些數據類型都支援push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支援各種不同方式的排序。為了保證效率,數據都是快取在記憶體中。區別的是redis會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了主從同步。簡單來說 Redis 就是一個資料庫,不過與傳統資料庫不同的是 Redis 的數據是存在記憶體中的,所以存寫速度非常快,因此 Redis 被廣泛應用於快取方向。Redis 也經常用來做分散式鎖。Redis 提供了多種數據類型來支援不同的業務場景。除此之外,Redis 支援事務 、持久化、LUA 腳本、LRU 驅動事件、多種集群方案。

Redis與Memcached的區別

  • Redis支援常見數據類型:Redis 不僅僅支援簡單的 key/value 類型的數據,同時還提供string(字元串)、list(鏈表)、set(集合)、zset(有序集合)和hash(哈希類型)等數據結構的存儲。而Memcache 只支援簡單的數據類型 String
  • Redis 支援數據的持久化,可以將記憶體中的數據保持在磁碟中,重啟的時候可以再次載入進行使用,而 Memecache 把數據全部存在記憶體之中。
  • 集群模式:Memcached 沒有原生的集群模式,需要依靠客戶端來實現往集群中分片寫入數據;但是 Redis 目前是原生支援 Cluster 模式的。
  • Memcached 是多執行緒,非阻塞 IO 復用的網路模型;Redis 使用單執行緒的多路 IO 復用模型。

Redis常用五大數據類型

Redis支援存儲的value類型相對更多,包括string、list、set、sorted set和hash。這些數據類型都支援push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,Redis支援各種不同方式的排序。為了保證效率,數據都是快取在記憶體中。對於這五種數據類型的具體分析可以看:細談Redis五大數據類型

Redis的快取淘汰策略

Redis可以對存儲在快取中的數據設置過期時間。作為一個快取資料庫,這是非常實用的功能。之前寫過一篇前後端交互的文章講過,Token 或者一些登錄資訊,尤其是簡訊驗證碼都是有時間限制的,按照傳統的資料庫處理方式,一般都是自己判斷過期,這樣無疑會嚴重影響項目性能。而有一個好的方案其實就是將這些驗證資訊存入Redis設置過期時間,如果設置了存活時間30分鐘,那麼半小時之後這些數據就會從Redis中進行刪除。那說到刪除,Redis是如果做到對這些數據進行刪除的呢:

  • 定期刪除:Redis 默認是每隔 100ms 就隨機抽取一些設置了過期時間的 Key,檢查其是否過期,如果過期就刪除。為什麼是隨機抽取而不是檢查所有key?因為你如果設置的key成千上萬,每100毫秒都將所有存在的key檢查一遍,會給CPU帶來比較大的壓力。
  • 惰性刪除 :定期刪除可能會導致很多過期 Key 到了時間並沒有被刪除掉。用戶在獲取key的時候,redis會檢查一下,這個key如果設置過期時間那麼是否過期了,如果過期就刪除這個key

但是只是使用定期刪除 + 惰性刪除的刪除機制還是存在一個致命問題:如果定期刪除漏掉了很多過期 Key,而且用戶長時間也沒有使用到這些過期key,就會導致這些過期key堆積在記憶體里,導致Redis記憶體塊被消耗殆盡。所以有了Redis記憶體淘汰機制的誕生。

Redis 提供 6 種數據淘汰策略:

  • volatile-lru:從已設置過期時間的數據集中挑選最近最少使用的數據淘汰。
  • volatile-ttl:從已設置過期時間的數據集中挑選將要過期的數據淘汰。
  • volatile-random:從已設置過期時間的數據集中任意選擇數據淘汰。
  • allkeys-lru:當記憶體不足以容納新寫入數據時移除最近最少使用的key。
  • allkeys-random:從數據集中任意選擇數據淘汰。
  • no-enviction:當記憶體不足以容納新寫入數據時,新寫入操作會報錯。

Redis為何在記憶體中存放數據?

Redis為了保證效率,數據都是快取在記憶體中。Redis會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件。簡單來說 Redis 就是一個資料庫,不過與傳統資料庫不同的是 Redis 的數據是存在記憶體中的,所以存寫速度非常快,因此 Redis 被廣泛應用於快取方向。Redis 也經常用來做分散式鎖。

Redis中哈希槽的概念

Redis沒有使用一致性哈希這個概念,而是引入了哈希槽。在Redis集群中共有16384個哈希槽,然後每個key通過哈希函數crc16()key名轉化成一個長整型數字再對16384取余,最終決定這個key存儲的哈希槽。而每個Redis實例負責維護一部分哈希槽,所有實例共同維護所有的哈希槽。使用哈希槽最顯而易見的特點就是Redis實例的增加或者移除很方便,而不需要暫停所有Redis實例服務。

Redis分區方案

數據分片方式一般有三種:客戶端分片、代理分片和伺服器分片。具體可以查看文章:Redis分片機制

客戶端分片

定義:客戶端自己計算key需要映射到哪一個Redis實例。

優點:客戶端分片最明顯的好處在於降低了集群的複雜度,而伺服器之間沒有任何關聯性,數據分片由客戶端來負責實現。

缺點:客戶端實現分片則客戶端需要知道當前集群下不同Redis實例的資訊,當新增Redis實例時需要支援動態分片,多數Redis需要重啟才能實現該功能。

代理分片

定義:客戶端將請求發送到代理,代理通過計算得到需要映射的集群實例資訊,然後將客戶端的請求轉發到對應的集群實例上,然後返迴響應給客戶端。

優點:降低了客戶端的複雜度,客戶端不用關心後端Redis實例的狀態資訊。

缺點:多了一個中間分發環節,所以對性能有些取的損失。

伺服器分片

定義:客戶端可以和集群中任意Redis實例通訊,當客戶端訪問某個實例時,伺服器進行計算key應該映射到哪個具體的Redis實例中存儲,如果映射的實例不是當前實例,則該實例主動引導客戶端去對應實例對key進行操作。這其實是一個重定向的過程。這個過程不是從當前Redis實例轉發到對應的Redis實例,而是客戶端收到伺服器通知具體映射的Redis實例重定向到映射的實例中。當前還不能完全適用於生產環境。

優點:支援高可用,任意實例都有主從,主掛了從會自動接管。

缺點:需要客戶端語言實現伺服器集群協議,但是目前大多數語言都有其客戶端實現版本。

Redis的持久化機制

Redis持久化支援兩種不同的持久化操作。 RDB持久化是一次全量備份,備份的是記憶體數據的二進位序列化格式。而AOF持久化是增量備份,記錄的是記憶體數據修改的指令記錄文本。所以AOF持久化生成的日誌會隨著運行時間變長而變得越來越臃腫,每次重啟Redis都需要載入AOF日誌進行指令重放,所以需要定期重寫AOF日誌進行瘦身操作。對於Redis的兩種持久化機制的選擇,主要還是得針對特定的系統討論,看是可以犧牲一定的性能使用AOF持久化換取快取一致性,還是在增刪操作頻繁時關閉備份,等到Redis空閑手動saveRDB持久化備份。所以其實最佳方案應該是採用混合持久化方案,開啟混合持久化後,AOF重寫日誌時會將RDB持久化的內容寫到AOF文件開頭,於是在Redis重啟時,可以先載入RDB的內容,再對增量的AOF日誌進行重放,提升Redis重啟的效率。

Redis如何使用分散式鎖?

當某個機器佔有鎖並在Redis中設置key時,將value設置為隨機數,在請求處理完畢需要釋放鎖之前加上一步操作:判斷keyvalue值是否等於之前設置的隨機數,如果是代表這個鎖佔有者還是自己,就可以執行釋放鎖操作,否則代表鎖已經被別人佔有,不能執行釋放鎖操作。由於查詢和釋放鎖的操作非原子性的,所以就需要使用另一種方式:引入Jedis,使用Lua腳本將查詢鎖和釋放鎖的兩部分邏輯寫成腳本,於是Redis執行Lua腳本時,其他機器的所有命令都必須等到Lua腳本執行結束才能執行,所以不可能存在查詢鎖結束還未釋放就被其他機器佔領的情況。

如何使用Redis集群?

使用主從複製將主節點的數據同步到從節點去存儲,然後使用哨兵模式實現集群的高可用,在主節點宕機則會從從節點中選擇一個進行主從切換成主節點繼續處理請求。然後當Redis記憶體不足時,使用分片機制對Redis進行分片存儲,可以減輕單台Redis的壓力,提升Redis擴展能力和計算能力。

快取雪崩、快取擊穿、快取穿透的區別

  • 快取擊穿:高並發的情況下,某個熱門key突然過期,導致大量請求在Redis未找到快取數據,進而全部去訪問DB請求數據,引起DB壓力瞬間增大。這就是快取擊穿。
  • 快取穿透:快取穿透是指查詢快取和DB中都不存在的數據。比如通過id查詢商品資訊,id一般大於0,攻擊者會故意傳id-1去查詢,由於快取是不命中則從DB中獲取數據,這將會導致每次快取都不命中數據導致每個請求都訪問DB,造成快取穿透。
  • 快取雪崩:快取中如果大量快取在一段時間內集中過期了,這時候會發生大量的快取擊穿現象,所有的請求都落在了DB上,由於查詢數據量巨大,引起DB壓力過大甚至導致DB宕機。這就叫做快取雪崩。