天天看點

Redis内幕揭秘:探索基礎知識及應用場景,挖掘出高效的緩存技術

作者:玄明Hanko

#挑戰30天在頭條寫日記#

Redis 是一個開源的記憶體資料結構存儲系統,它可以用作資料庫、緩存和消息中間件。以下是 Redis 的發展史:

  • 2009 年:Salvatore Sanfilippo 開始編寫 Redis。
  • 2010 年:Redis 釋出了 1.0 版本。這個版本包含了許多常用的資料結構,例如字元串、哈希表、清單、集合和有序集合。
  • 2012 年:Redis 釋出了 2.6 版本,引入了持久化機制和 Lua 腳本支援。
  • 2014 年:Redis 釋出了 3.0 版本,添加了 Cluster 功能,允許将多個 Redis 執行個體組成分布式叢集。
  • 2015 年:Redis 釋出了 3.2 版本,引入了子產品化擴充功能,允許開發者編寫自定義的 Redis 子產品。
  • 2018 年:Redis 釋出了 5.0 版本,引入了 Streams 資料類型和更好的叢集管理工具。
  • 2021 年:Redis 釋出了 6.2 版本,添加了 RedisRaft 子產品,使得 Redis 可以支援強一緻性分布式系統。

随着時間的推移,Redis 已經成為了一個非常流行的開源項目,并被廣泛應用于網際網路和企業級應用程式中。

1、Redis基礎

1.1、資料類型

Redis内幕揭秘:探索基礎知識及應用場景,挖掘出高效的緩存技術

1)String(字元串):最基本的資料結構,可以存儲任何類型的字元串、數字或二進制資料。

2)Hash(哈希表):類似于關聯數組或字典,可以存儲多個字段和對應的值,常用于存儲對象屬性或配置資訊。

3)List(清單):一個有序的字元串清單,支援在清單兩端進行插入和删除操作,還提供了多種操作,如查找、裁剪、排序等。

4)Set(集合):一個無序的字元串集合,支援添加、删除、查找和求交、并、差等操作,還提供了多種操作,如求随機元素、判斷元素是否存在等。

5)ZSet(有序集合):和 Set 類型相似,但是每個元素都有一個分數(score),根據分數進行排序,可以支援按照分數範圍進行查找、插入和删除操作。

1.2、持久化機制

Redis 的持久化機制有兩種:RDB(Redis Database)和AOF(Append Only File)。

1)RDB 持久化:将 Redis 記憶體中的資料以快照的形式儲存到硬碟中,即生成一個 RDB 檔案。可以手動或自動設定定時儲存 RDB 檔案。當 Redis 重新開機時,會從 RDB 檔案中讀取資料并恢複資料庫狀态。RDB 持久化适用于大規模的資料集和較長時間的備份。

2)AOF 持久化:将 Redis 執行的寫指令追加到 AOF 檔案中,記錄了 Redis 修改資料的所有操作。由于 AOF 檔案是一個完整的 Redo 日志,是以當 Redis 重新開機時可以通過重新執行 AOF 檔案中的所有寫指令來還原資料。AOF 持久化适用于需要高耐久性的場景,比如金融、電商等行業。

在使用 Redis 的持久化機制時,還需要注意以下幾點:

  • 如果同時開啟了 RDB 和 AOF,Redis 支援首先使用 AOF 進行資料恢複,然後再使用 RDB 檔案進行備份。
  • RDB 檔案和 AOF 檔案都可能比記憶體中的資料要舊,是以如果資料非常關鍵,最好同時開啟 RDB 和 AOF,保證不丢失資料。
  • 定期儲存 RDB 檔案和 AOF 檔案的頻率應該根據實際需求進行調整,以平衡資料備份和性能損耗之間的關系。
  • Redis 還提供了 BGSAVE 和 BGREWRITEAOF 指令來異步執行 RDB 和 AOF 持久化操作,避免阻塞 Redis 主線程。

當然生産上大多數是這兩種機制同時使用,以保證資料的安全性和可靠性。

1.3、部署方式

1)Sentinel 執行個體進行監控和故障轉移,實作 Redis 的自動故障恢複和主備切換。

2)Redis Cluster:Redis Cluster 是 Redis 官方提供的分布式叢集方案,支援資料分片和節點擴充,可以在不丢失資料的前提下動态增加或減少節點數量,提高了叢集的可擴充性和容錯性。

3)Codis:Codis 是一個開源的 Redis 資料庫中間件,基于 Redis 的主從複制和分片機制,提供了多種功能,如資料分片、節點管理、讀寫分離、高可用性等,并且可以與 ZooKeeper 等 Apache 開源軟體進行整合。

4)Twemproxy:Twemproxy(也稱為 Nutcracker)是一個類似于代理伺服器的 Redis 中間件,支援多個 Redis 執行個體的負載均衡和故障轉移,可以提高 Redis 叢集的性能和可靠性。

2、Redis應用場景

2.1、緩存

Redis 最常見的應用場景就是作為緩存來提高讀寫性能。由于 Redis 基于記憶體讀寫,響應速度非常快,是以可以用來緩存熱點資料,如網站首頁、商品資訊等。通過使用 TTL(time to live)機制來設定緩存過期時間,可以避免緩存資料過期而導緻的問題。

2.2、分布式鎖

Redis 可以用作分布式鎖,通過設定一個唯一的鍵值對來控制通路某個資源的并發數。當一個用戶端需要通路該資源時,先去擷取分布式鎖,執行完後再釋放鎖,以保證同時隻有一個用戶端在通路該資源。這種方式可以有效避免因為并發通路而導緻的資料沖突和競争問題。

Redis實作分布式鎖的技術方案有很多,其中比較常用的包括:

1)基于SETNX指令+Lua腳本:使用SETNX指令建立一個鍵值對,如果該鍵不存在,表示加鎖成功;否則表示加鎖失敗。釋放鎖時,使用DEL指令删除該鍵。配合Lua腳本可以讓加鎖和釋放鎖過程封裝成原子性操作,避免出現誤删等問題。

2)Redisson:是一個Java實作的Redis用戶端,提供了完整的分布式鎖解決方案,支援多種鎖模式(例如可重入鎖、公平鎖等),并提供了逾時自動釋放鎖、異步執行等功能。

3)Spring Boot + LockRegistry(推薦):LockRegistry是Spring Boot提供的接口,可以輕松地将分布式鎖嵌入到應用程式中。LockRegistry接口可以與不同的分布式鎖提供者(如Redis)內建,并提供了簡單易用的API,使開發人員無需關注底層實作細節。

需要注意的是,在選擇分布式鎖方案時,需要根據實際情況進行考慮。不同的方案具有不同的特點和适用場景,需要根據業務需求和系統負載情況進行選擇和優化。同時,分布式鎖的實作過程需要特别注意死鎖和誤删等問題,必要時可以借助第三方庫進行實作。

2.3、實時排行榜

Redis 可以用來實作實時排行榜,通過将使用者行為資料記錄下來,如點贊數、評論數等,然後通過 ZSET(有序集合)資料類型來實作實時排名和排序。這種方式可以很好地滿足諸如遊戲排名、電商銷量排行等實時統計的需求。

2.4、計數器/自增ID

Redis 還可以用作計數器,通過使用 INCR 指令來實作。當需要對某個計數器進行增加操作時,隻需要執行一次 INCR 指令即可。由于 Redis 的原子性操作,可以保證在高并發場景下的資料一緻性。

2.5、消息隊列

Redis 也可以用作消息隊列,在分布式系統中起到重要的作用。生産者将消息存入隊列中,消費者從隊列中取出消息進行處理。通過使用 Redis 的 PUB/SUB(釋出/訂閱)功能或者 Stream來實作消息的釋出和訂閱,保證了消息傳遞的可靠性和高效性。

2.6、地理位置應用

Redis 還具有地理位置服務的特性,可以記錄每個使用者的位置資訊,并将其儲存在 Redis 中。然後通過 GeoHash 和 Geospatial 資料類型來實作位置資訊的查找和計算,以實作類似于附近的人、打車等服務。

3、Redis進階

3.1、資料類型

除了常見的 String、Hash、List、Set、ZSet 等資料類型,Redis 還支援以上提到的其他資料類型,如 Bitmaps、HyperLogLog、Geo 和 Streams 等。

1)JSON

雖然Redis在自身的核心中并不原生支援JSON資料類型,但是通過Redis子產品系統,可以使用第三方擴充子產品來支援JSON資料類型。Redis 4.0及以上版本引入了Modules(子產品)系統,允許開發者編寫自己的擴充子產品來擴充Redis的功能。目前有一些第三方子產品已經實作了對JSON資料類型的支援,例如RedisJSON和ReJSON等。

2)釋出訂閱/Redis Streams:

Redis 釋出訂閱 (pub/sub) 是一種消息通信模式:發送者 (pub) 發送消息,訂閱者 (sub) 接收消息。Redis中的訂閱釋出模式, 當沒有訂閱者時, 消息會被直接丢棄(Redis不會持久化儲存消息)。

Redis Stream 是 Redis 5.0 版本新增加的資料結構。Redis Stream 主要用于消息隊列(MQ,Message Queue),Redis 本身是有一個 Redis 釋出訂閱 (pub/sub) 來實作消息隊列的功能,但它有個缺點就是消息無法持久化,如果出現網絡斷開、Redis 當機等,消息就會被丢棄。簡單來說釋出訂閱 (pub/sub) 可以分發消息,但無法記錄曆史消息。而 Redis Stream 提供了消息的持久化和主備複制功能,可以讓任何用戶端通路任何時刻的資料,并且能記住每一個用戶端的通路位置,還能保證消息不丢失。

3)Geo

Redis GEO 主要用于存儲地理位置資訊,并對存儲的資訊進行操作,該功能在 Redis 3.2 版本新增。

3.2、Redis管道技術

Redis管道技術是一種優化Redis用戶端與伺服器之間互動的方式,它可以将多個指令打包在一起發送到Redis伺服器,進而減少了網絡傳輸和用戶端/伺服器之間的通信次數,提高了Redis的性能。具體來說,Redis管道技術的工作流程如下:

1)用戶端向Redis伺服器發送多個指令。

2)Redis伺服器将這些指令緩存到隊列中,并等待用戶端的響應。

3)用戶端接收到伺服器響應後,再一次性地發送所有指令的響應結果。

4)Redis伺服器處理這些響應結果,并将它們傳回給用戶端。

通過使用Redis管道技術,可以顯著降低Redis用戶端與伺服器之間的延遲,并提高資料讀寫效率。此外,Redis管道技術還具有批量操作、事務處理等功能,可以簡化程式設計和管理複雜性。

需要注意的是,雖然Redis管道技術可以提高Redis的性能,但也會增加系統複雜性和記憶體負擔。是以,在實際使用中,需要根據業務需求和系統負載情況進行合理調整和配置。

4、相關問題

1)Redis為什麼那麼快?

(1)記憶體存儲:Redis将資料存儲在記憶體中,使得讀寫速度非常快。同時,Redis也提供持久化機制,可以将記憶體資料異步地寫入磁盤中,保證資料的安全性和可靠性。

(2)非阻塞I/O多路複用機制:Redis使用非阻塞I/O模型,避免了線程上下文切換和系統調用帶來的開銷,進而大幅提高了并發吞吐量。

(3)單線程架構:Redis采用單線程架構,避免了多線程間的同步和鎖競争等問題,簡化了代碼實作和維護。

(4)資料結構優化:Redis内置了多種資料結構(如哈希表、有序集合等),并對其進行了優化,使得操作複雜度低,并能在很短的時間内完成大量的資料處理。

(5)預配置設定記憶體:Redis在初始化時會預先配置設定一定量的記憶體空間,避免了頻繁的記憶體配置設定和釋放過程,提高了性能。

2)Redis為什麼使用單線程?

Redis官方的回複:

“Redis的性能瓶頸通常不在CPU上,而是其他因素(如磁盤I/O和網絡請求等)限制了系統的性能。”

3)Redis支援多線程嗎?

Redis采用單線程模型,不支援多線程操作。這是因為Redis是一個基于記憶體的資料存儲系統,大部分操作都需要通路記憶體,而記憶體通路通常是CPU密集型任務,多線程情況下會存線上程之間的上下文切換和鎖競争等問題,反而會降低效率。

雖然Redis 6.0+ 引入多線程IO,但隻是用來處理網絡資料的讀寫、協定的解析及日志操作等,而執行指令依舊是單線程,是以不需要去考慮set/get、事務、lua等的并發問題。

4)Redis有哪些資料結構?

Redis支援字元串、哈希表、清單、集合和有序集合等五種資料結構。

5)Redis的持久化機制有哪些?它們之間有什麼差別?

Redis支援RDB(快照)和AOF(追加式檔案)兩種持久化機制。RDB會定期将記憶體資料快照寫入磁盤檔案,而AOF則将所有操作指令追加到一個日志檔案中。相比而言,AOF更為可靠,但同時也需要更多的磁盤空間和IO資源。

6)Redis如何實作分布式鎖?

Redis可以通過SETNX指令建立一個鍵值對作為鎖,并使用Lua腳本實作原子性的加鎖和釋放鎖操作。此外,還可以使用第三方庫如Redisson提供的分布式鎖解決方案。

7)Redis支援哪些類型的指令?

Redis支援基本的讀寫指令,如GET/SET/HGETALL等,以及一些進階指令,如事務、釋出訂閱等。

8)Redis的線程模型是什麼?

Redis采用單線程架構,但通過使用事件驅動和非阻塞I/O技術,可以處理大量并發請求。

9)Redis如何保證資料的一緻性?

Redis采用原子性操作和持久化機制來保證資料的一緻性。例如,可以使用Redis事務(MULTI/EXEC)、管道技術、Lua腳本等方式實作原子性操作;通過開啟持久化功能,可以将記憶體資料寫入磁盤檔案并在伺服器重新開機後恢複資料。

10)Redis如何處理大量的并發請求?

Redis采用非阻塞I/O多路複用和事件驅動模型,可以高效地處理大量并發請求,并提供了線程池和緩沖區等機制來進一步優化性能。

11)Redis有哪些常見的應用場景?

Redis常見的應用場景包括緩存、計數器、消息隊列、分布式鎖等。

12)Redis的叢集模式有哪些?

Redis支援主從複制、Sentinel哨兵模式和Cluster叢集模式三種叢集模式。其中,主從複制和Sentinel模式适用于較小的系統或需要高可用的場景,而Cluster模式則适用于更大規模的系統。

13)Redis如何實作釋出訂閱功能?

Redis 本身是有一個 Redis 釋出訂閱 (pub/sub) 來實作消息隊列的功能,但它有個缺點就是消息無法持久化,如果出現網絡斷開、Redis 當機等,消息就會被丢棄。簡單來說釋出訂閱 (pub/sub) 可以分發消息,但無法記錄曆史消息。而 Redis Stream 提供了消息的持久化和主備複制功能,可以讓任何用戶端通路任何時刻的資料,并且能記住每一個用戶端的通路位置,還能保證消息不丢失。

=================================

如果文章對你有幫助,請不要忘記加個關注、點個贊!!!