天天看點

Redis實戰之入門進階到精通

本章主要内容

 Redis 與其他軟體的相同之處和不同之處

 Redis 的用法

 使用 Python 示例代碼與 Redis 進行簡單的互動

 使用 Redis 解決實際問題

以下知識點解析來自于《Redis實戰》文檔其中的一部分!由于不影響觀看,隻選取了其中的一部分來展示。

需要完整版的可以點選這裡!!暗号CSDN,擷取!

Redis 是一個遠端記憶體資料庫,它不僅性能強勁,而且還具有複制特性以及為解決問題而生

的獨一無二的資料模型。Redis 提供了 5 種不同類型的資料結構,各式各樣的問題都可以很自然

地映射到這些資料結構上:Redis 的資料結構緻力于幫助使用者解決問題,而不會像其他資料庫那

樣,要求使用者扭曲問題來适應資料庫。除此之外,通過複制、持久化(persistence)和用戶端分

片(client-side sharding)等特性,使用者可以很友善地将 Redis 擴充成一個能夠包含數百 GB 資料、

每秒處理上百萬次請求的系統。

筆者第一次使用 Redis 是在一家公司裡面,這家公司需要對一個儲存了 6 萬個客戶聯系

方式的關系資料庫進行搜尋,搜尋可以根據名字、郵件位址、所在地和電話号碼來進行,每

次搜尋需要花費 10~15 秒的時間。在花了一周時間學習 Redis 的基礎知識之後,我使用 Redis

重寫了一個新的搜尋引擎,然後又花費了數周時間來仔細測試這個新系統,使它達到生産級

别,最終這個新的搜尋系統不僅可以根據名字、郵件位址、所在地和電話号碼等資訊來過濾

和排序客戶聯系方式,并且每次操作都可以在 50 毫秒之内完成,這比原來的搜尋系統足足快

了 200 倍。閱讀本書可以讓你學到很多小技巧、小竅門以及使用 Redis 解決某些常見問題的

方法。

本章将介紹 Redis 的适用範圍,以及在不同環境中使用 Redis 的方法(比如怎樣跟不同的組

件和程式設計語言進行通信等);而之後的章節則會展示各式各樣的問題,以及使用 Redis 來解決這

些問題的方法。

第 1 章 初識 Redis

1.1 Redis 簡介

安裝 Redis 和 Python 附錄 A 介紹了快速安裝 Redis 和 Python 的方法。

在其他程式設計語言裡面使用 Redis 本書隻展示了使用 Python 語言編寫的示例代碼,使用 Ruby、Java 和 JavaScript(Node.js)編寫的示例代碼可以在這裡找到:https://github.com/josiahcarlson/redis-in-action。使用 Spring 架構的讀者可以通過檢視 http://www.springsource.org/spring-data/redis來學習如何在 Spring 架構中使用 Redis。

前面對于Redis資料庫的描述隻說出了一部分真相。Redis是一個速度非常快的非關系數

據庫(non-relational database),它可以存儲鍵(key)與 5 種不同類型的值(value)之間的

映射(mapping),可以将存儲在記憶體的鍵值對資料持久化到硬碟,可以使用複制特性來擴

展讀性能,還可以使用用戶端分片

1.1.1 Redis 與其他資料庫和軟體的對比

來擴充寫性能,接下來的幾節将分别介紹Redis的這幾個特性。

如果你熟悉關系資料庫,那麼你肯定寫過用來關聯兩個表的資料的 SQL 查詢 。而 Redis 則屬于人們常說的 NoSQL 資料庫或者非關系資料庫:Redis 不使用表,它的資料庫也不會預定義或者強制去要求使用者對 Redis 存儲的不同資料進行關聯。

高性能鍵值緩存伺服器 memcached 也經常被拿來與 Redis 進行比較:這兩者都可用于存儲鍵值映射,彼此的性能也相差無幾,但是 Redis 能夠自動以兩種不同的方式将資料寫入硬碟,并且 Redis 除了能存儲普通的字元串鍵之外,還可以存儲其他 4 種資料結構,而 memcached 隻能存儲普通的字元串鍵。這些不同之處使得 Redis 可以用于解決更為廣泛的問題,并且既可以用作主資料庫(primary database)使用,又可以作為其他存儲系統的輔助資料庫(auxiliary database)使用。

本書的後續章節會分别介紹将 Redis 用作主存儲(primary storage)和二級存儲(secondary storage)時的用法和查詢模式。一般來說,許多使用者隻會在 Redis 的性能或者功能是必要的情況下,才會将資料存儲到 Redis 裡面:如果程式對性能的要求不高,又或者因為費用原因而沒辦法将大量資料存儲到記憶體裡面,那麼使用者可能會選擇使用關系資料庫,或者其他非關系資料庫。在實際中,讀者應該根據自己的需求來決定是否使用 Redis,并考慮是将 Redis 用作主存儲還是輔

① 分片是一種将資料劃分為多個部分的方法,對資料的劃分可以基于鍵包含的 ID、基于鍵的散列值,或者

基于以上兩者的某種組合。通過對資料進行分片,使用者可以将資料存儲到多台機器裡面,也可以從多台

機器裡面擷取資料,這種方法在解決某些問題時可以獲得線性級别的性能提升。

助存儲,以及如何通過複制、持久化和事務等手段保證資料的完整性。

表 1-1 展示了一部分在功能上與 Redis 有重疊的資料庫伺服器和緩存伺服器,從這個表可以

看出 Redis 與這些資料庫及軟體之間的差別。

Redis實戰之入門進階到精通

1.1.2 附加特性

在使用類似 Redis 這樣的記憶體資料庫時,一個首先要考慮的問題就是“當伺服器被關閉時,伺服器存儲的資料将何去何從呢?”Redis 擁有兩種不同形式的持久化方法,它們都可以用小而緊湊的格式将存儲在記憶體中的資料寫入硬碟:第一種持久化方法為時間點轉儲(point-in-time dump),轉儲操作既可以在“指定時間段内有指定數量的寫操作執行”這一條件被滿足時執行,又可以通過調用兩條轉儲到硬碟(dump-to-disk)指令中的任何一條來執行;第二種持久化方法将所有修改了資料庫的指令都寫入一個隻追加(append-only)檔案裡面,使用者可以根據資料的重要程度,将隻追加寫入設定為從不同步(sync)、每秒同步一次或者每寫入一個指令就同步一次。

我們将在第 4 章中更加深入地讨論這些持久化選項。另外,盡管 Redis 的性能很好,但受限于 Redis 的記憶體存儲設計,有時候隻使用一台 Redis伺服器可能沒有辦法處理所有請求。是以,為了擴充 Redis 的讀性能,并為 Redis 提供故障轉移

5 (failover)支援 ,Redis 實作了主從複制特性:執行複制的從伺服器會連接配接上主伺服器,接收主伺服器發送的整個資料庫的初始副本(copy);之後主伺服器執行的寫指令,都會被發送給所有連接配接着的從伺服器去執行,進而實時地更新從伺服器的資料集。因為從伺服器包含的資料會不斷地進行更新,是以用戶端可以向任意一個從伺服器發送讀請求,以此來避免對主伺服器進行集中式的通路。我們将在第 4 章中更加深入地讨論 Redis 從伺服器。

1.1.3 使用 Redis 的理由

有 memcached 使用經驗的讀者可能知道,使用者隻能用 APPEND 指令将資料添加到已有字元串的末尾。memcached 的文檔中聲明,可以用 APPEND 指令來管理元素清單。這很好!使用者可以将元素追加到一個字元串的末尾,并将那個字元串當作清單來使用。但随後如何删除這些元素呢?memcached 采用的辦法是通過黑名單(blacklist)來隐藏清單裡面的元素,進而避免對元素執行讀取、更新、寫入(包括在一次資料庫查詢之後執行的 memcached 寫入)等操作。相反地,Redis 的 LIST 和 SET 允許使用者直接添加或者删除元素。使用 Redis 而不是 memcached 來解決問題,不僅可以讓代碼變得更簡短、更易懂、更易維護,而且還可以使代碼的運作速度更快(因為使用者不需要通過讀取資料庫來更新資料)。除此之外,在其他許多情況下,Redis 的效率和易用性也比關系資料庫要好得多。

資料庫的一個常見用法是存儲長期的報告資料,并将這些報告資料用作固定時間範圍内的聚合資料(aggregates)。收集聚合資料的常見做法是:先将各個行插入一個報告表裡面,之後再通過掃描這些行來收集聚合資料,并根據收集到的聚合資料來更新聚合表中已有的那些行。之是以使用插入行的方式來存儲,是因為對于大部分資料庫來說,插入行操作的執行速度非常快(插入行隻會在硬碟檔案末尾進行寫入)。不過,對表裡面的行進行更新卻是一個速度相當慢的操作,因為這種更新除了會引起一次随機讀(random read)之外,還可能會引起一次随機寫(random write)。而在Redis裡面,使用者可以直接使用原子的(atomic)INCR指令及其變種來計算聚合資料,并且因為Redis将資料存儲在記憶體裡面 ①

① 客觀來講,memcached 也能用在這個簡單的場景裡,但使用 Redis 存儲聚合資料有以下 3 個好處:

1、首先,使用 Redis 可以将彼此相關的聚合資料放在同一個結構裡面,這樣通路聚合資料就會變得更為容易;

2、其次,使用 Redis 可以将聚合資料放到有序集合裡面,建構出一個實時的排行榜;

3、最後,Redis 的聚合資料可以是整數或者浮點數,而 memcached 的聚合資料隻能是整數。而且發送給Redis的指令請求并不需要經過典型的查詢分析器(parser)或者查詢優化器(optimizer)進行處理,是以對Redis存儲的資料執行随機寫的速度總是非常迅速的。

使用 Redis 而不是關系資料庫或者其他硬碟存儲資料庫,可以避免寫入不必要的臨時資料,也免去了對臨時資料進行掃描或者删除的麻煩,并最終改善程式的性能。雖然上面列舉的都是一些簡單的例子,但它們很好地證明了“工具會極大地改變人們解決問題的方式”這一點。

1.2 Redis 資料結構簡介

正如之前的表 1-1 所示,Redis 可以存儲鍵與 5 種不同資料結構類型之間的映射,這 5 種數

據結構類型分别為 STRING(字元串)、LIST(清單)、SET(集合)、HASH(散列)和 ZSET(有序集合)。有一部分 Redis 指令對于這 5 種結構都是通用的,如 DEL、TYPE、RENAME 等;但也有一部分 Redis 指令隻能對特定的一種或者兩種結構使用,第 3 章将對 Redis 提供的指令進行更深入的介紹。

大部分程式員應該都不會對 Redis 的 STRING、LIST、HASH 這 3 種結構感到陌生,因

為它們和很多程式設計語言内建的字元串、清單和散列等結構在實作和語義(semantics)方面都

非常相似。有些程式設計語言還有集合資料結構,在實作和語義上類似于 Redis 的 SET。ZSET 在

某種程度上是一種 Redis 特有的結構,但是當你熟悉了它之後,就會發現它也是一種非常有

用的結構。表 1-2 對比了 Redis 提供的 5 種結構,說明了這些結構存儲的值,并簡單介紹了

它們的語義。

Redis實戰之入門進階到精通
指令清單 本節在介紹每個資料類型的時候,都會在一個表格裡面展示一小部分處理這些資料結 構的指令,之後的第 3會展示一個更詳細(但仍不完整)的指令清單,完整的 Redis 指令清單 可以http://redis.io/commands 找到。

這一節将介紹如何表示 Redis 的這 5 種結構,并且還會介紹 Redis 指令的使用方法,進而為本書的後續内容打好基礎。本書展示的所有示例代碼都是用 Python 寫的,如果讀者已經按照附錄 A 裡面描述的方法安裝好了 Redis,那麼應該也已經安裝好了 Python,以及在 Python 裡面使用Redis 所需的用戶端庫。隻要讀者在電腦裡面安裝了 Redis、Python 和 redis-py 庫,就可以在閱讀本書的同時,嘗試執行書中展示的示例代碼了。

請安裝 Redis 和 Python 在閱讀後續内容之前,請讀者先按照附錄 A 中介紹的方法安裝 Redis 和Python。如果讀者覺得附錄 A 描述的安裝方法過于複雜,那麼這裡有一個更簡單的方法,但這 個方法隻能用于 Debian系統(或者該系統的衍生系統):從 http://redis.io/download 下載下傳 Redis 的 壓縮包,解壓壓縮包,執行 make&& sudo make install,之後再執行 sudo python -m easy_install redis hiredis(hiredis 是可選的,它是一個使用 C 語言編寫的高性能 Redis 用戶端)。

如果讀者熟悉過程式程式設計語言或者面向對象程式設計語言,那麼即使沒有使用過 Python,應該也

可以看懂 Python 代碼。另一方面,如果讀者決定使用其他程式設計語言來操作 Redis,那麼就需要自

己來将本書的 Python 代碼翻譯成正在使用的語言的代碼。

使用其他語言編寫的示例代碼 盡管沒有包含在書中,但本書展示的 Python 示例代碼已經被翻譯成 了 Ruby 代碼、Java 代碼和JavaScript 代碼,這些翻譯代碼可以在 https://github.com/josiahcarlson/redis-in-action 下載下傳到。跟 Python 編寫的示例代碼一樣,這些翻譯代碼也包含相應的注釋,友善讀 者參考。

為了讓示例代碼盡可能地簡單,本書會盡量避免使用 Python 的進階特性,并使用函數而不

是類或者其他東西來執行 Redis 操作,以此來将焦點放在使用 Redis 解決問題上面,而不必過多

地關注 Python 的文法。本節将使用 redis-cli 控制台與 Redis 進行互動。首先,讓我們來了解一下

Redis 中最簡單的結構:STRING。

1.2.1 Redis 中的字元串

Redis 的字元串和其他程式設計語言或者其他鍵值存儲提供的字元串非常相似。本書在使用

圖檔表示鍵和值的時候,通常會将鍵名(key name)和值的類型放在方框的頂部,并将值

放在方框的裡面。圖 1-1 以鍵為 hello、值為 world 的字元串為例,分别标記了方框的各

個部分。

Redis實戰之入門進階到精通

字元串擁有一些和其他鍵值存儲相似的指令,比如 GET(擷取值)、SET(設定值)和 DEL(删除值)。如果讀者已經按照附錄 A 中給出的方法安裝了 Redis,那麼可以根據代碼清單 1-1 展示的例子,嘗試使用 redis-cli 執行 SET、GET 和 DEL,表 1-3 描述了這 3 個指令的基本用法。

Redis實戰之入門進階到精通

使用 redis-cli 為了讓讀者在一開始就能便捷地與 Redis 進行互動,本章将使用 redis-cli 這個互動式 用戶端來介紹

Redis 指令。

除了能夠 GET、SET 和 DEL 字元串值之外,Redis 還提供了一些可以對字元串的其中一部分内容進行讀取和寫入的指令,以及一些能對字元串存儲的數值執行自增或者自減操作的指令。第 3 章

将對這些指令進行介紹,但是在此之前,我們還有許多基礎知識需要了解,下面來看一下 Redis 的清單及其功能。

1.2.2 Redis 中的清單

Redis 對連結清單(linked-list)結構的支援使得它在鍵值存儲的世界中獨樹一幟。一個清單結構可以有序地存儲多個字元串,和表示字元串時使用的方法一樣,本節使用帶有标簽的方框來表示清單,并将清單包含的元素放在方框裡面。圖 1-2 展示了一個這樣的示例。

Redis實戰之入門進階到精通

Redis 清單可執行的操作和很多程式設計語言裡面的清單操作非常相似:LPUSH 指令和 RPUSH 指令分别用于将元素推入清單的左端(left end)和右端(right end);LPOP 指令和 RPOP 指令分别用于從清單的左端和右端彈出元素;LINDEX 指令用于擷取清單在給定位置上的一個元素;LRANGE 指令用于擷取清單在給定範圍上的所有元素。代碼清單 1-2 展示了一些清單指令的使用示例,表 1-4 簡單介紹了示例中用到的各個指令。

Redis實戰之入門進階到精通

即使 Redis 的清單隻支援以上提到的幾個指令,它也已經可以用來解決很多問題了,但 Redis 并沒

有就此止步—除了上面提到的指令之外,Redis 清單還擁有從清單裡面移除元素的指令、将元素插入

清單中間的指令、将清單修剪至指定長度(相當于從清單的其中一端或者兩端移除元素)的指令,以

及其他一些指令。第 3 章将介紹許多清單指令,但是在此之前,讓我們先來了解一下 Redis 的集合。

1.2.3 Redis 的集合

Redis 的集合和清單都可以存儲多個字元串,它們之間的不同在于,清單可以存儲多個相同的字元串,而

集合則通過使用散清單來保證自己存儲的每個字元串都是各不相同的(這些散清單隻有鍵,但沒有與鍵相關聯的值)。本書表示集合的方法和表示清單的方法基本相同,圖 1-3 展示了一個包含 3 個元素的示例集合。

Redis實戰之入門進階到精通

因為 Redis 的集合使用無序(unordered)方式存儲元素,是以使用者不能像使用清單那樣,将元素推入集合

的某一端,或者從集合的某一端彈出元素。不過使用者可以使用 SADD 指令将元素添加到集合,或者使用 SREM指令從集合裡面移除元素。另外還可以通過 SISMEMBER 指令快速地檢查一個元素是否已經存在于集合中,或者使用 SMEMBERS 指令擷取集合包含的所有元素(如果集合包含的元素非常多,那麼 SMEMBERS 指令的執行速度可能會很慢,是以請謹慎地使用這個指令)。代碼清單 1-3 展示了一些集合指令的使用示例,表 1-5 簡單介紹了代碼清單裡面用到的各個指令。

Redis實戰之入門進階到精通
Redis實戰之入門進階到精通

跟字元串和清單一樣,集合除了基本的添加操作和移除操作之外,還支援很多其他操作,比

如 SINTER、SUNION、SDIFF 這 3 個指令就可以分别執行常見的交集計算、并集計算和差集計

算。第 3 章将對集合的相關指令進行更詳細的介紹,另外第 7 章還會展示如何使用集合來解決多

個問題。不過别心急,因為在 Redis 提供的 5 種資料結構中,還有兩種我們尚未了解,讓我們先

來看看 Redis 的散列。

1.2.4 Redis 的散列

Redis 的散列可以存儲多個鍵值對之間的映射。和字元串一樣,散列存儲的值既可以是字元

串又可以是數字值,并且使用者同樣可以對散列存儲的數字值執行自增操作或者自減操作。圖 1-4

展示了一個包含兩個鍵值對的散列。

Redis實戰之入門進階到精通

散列在很多方面就像是一個微縮版的 Redis,不少字元串指令都有相應的散列版本。代碼清

單 1-4 展示了怎樣對散列執行插入元素、擷取元素和移除元素等操作,表 1-6 簡單介紹了代碼清

單裡面用到的各個指令。

Redis實戰之入門進階到精通
Redis實戰之入門進階到精通

熟悉文檔資料庫的讀者可以将 Redis 的散列看作是文檔資料庫裡面的文檔,而熟悉關系資料庫的

讀者則可以将 Redis 的散列看作是關系資料庫裡面的行,因為散列、文檔和行這三者都允許使用者同時訪

問或者修改一個或多個域(field)。最後,讓我們來了解一下 Redis 的 5 種資料結構中的最後一種:有序集合。

1.2.5 Redis 的有序集合

有序集合和散列一樣,都用于存儲鍵值對:有序集合的鍵被稱為成員(member),每個成員都是各不相同的;而有序集合的值則被稱為分值(score),分值必須為浮點數。有序集合是 Redis 裡面唯一一個既可以根據成員通路元素(這一點和散列一樣),又可以根據分值以及分值的排列順序來通路元素的結構。圖 1-5 展示了一個包含兩個元素的有序集合示例。

Redis實戰之入門進階到精通

和 Redis 的其他結構一樣,使用者可以對有序集合執行添加、移除和擷取等操作,代碼清單 1-5

展示了這些操作的執行示例,表 1-7 簡單介紹了代碼清單裡面用到的各個指令。

Redis實戰之入門進階到精通
Redis實戰之入門進階到精通

現在讀者應該已經知道有序集合是什麼和它能幹什麼了,到目前為止,我們基本了解了 Redis

提供的 5 種結構。接下來的一節将展示如何通過結合散列的資料存儲能力和有序集合内建的排

序能力來解決一個常見的問題。

以上知識點解析來自于《Redis實戰》文檔其中的一部分!由于不影響觀看,隻選取了其中的一部分來展示。

需要完整版的可以點選這裡!!暗号CSDN,找群主擷取!