[翻譯]Redis: 三十分鐘從入門到精通 - 第一部分

hasse發表於2011-11-29

我不止一次說過:“學習Redis是程式設計師花費30分鐘最有效的方式。”這句“哲言”闡釋了Redis有多麼有用,Redis有多麼易學——但是,這是真的麼?真的能在30分鐘內學會,甚至精通Redis麼?

讓我們來嘗試下吧。這一部分,我們將學習“Redis是什麼”。下一部分,我們將探討一些簡單的例子。剩下的時間裡我們將讓你自己搭建和玩轉Redis。

Redis簡介

Redis經常為描述一個Key/Value儲存引擎。這個描述非常準確,但是可能並不像你想象的那樣。當然,我想把它看做是一個資料結構引擎會更有幫助一些。Redis支援5種不同的資料結構:字串(Strings),hash表,集合(sets)和有序集合(sorted sets)。每一種資料結構都自己獨特的特性並支援獨特的命令。無論哪一種型別,都是用一個key去取一個value。雖然key是以二進位制的形式儲存,比較複雜,但是你總是可以用一個字串作為一個key。

讓我們看看每一種型別吧。

Strings

Strings是5種資料結構中最簡單的了。不幸的是,它的名字起得很糟糕,其實與我們常說的字串沒有任何關係。或許叫做single或者simple更好(譯註:一對一對映)。人們在使用Redis或者思考Key Value時,實際上是在思考String結構(但是記住,那只是5種結構中的一種)。正像Key一樣,一個string value可以是任何二進位制陣列。你可以儲存一個持續增長的計數器,一個實際的字串,或者一個二進位制序列化後的物件。這些都是很常用的。最常用的string method是GETSET

SET pages:about "about us"
GET pages:about
about us

你可以使用string做很多事情,不但因為它還有其他一些命令(如:INCR或者GETRANGE),還因為我們可以儲存其他型別的資料。比如,我們可以使用String結構去管理使用者。它的key可以是他們的email,而數值可以是使用者序列化之後的物件。

Hashes

hash資料結構和你想象中的hash表、字典是一致的。我們與其直接操作一個key(像string一樣),不如操作一個key的多個成員。所以說,我們不是僅get和set一個hash值,而是get和set值的一個成員:

HSET goku power 9001
HGET goku power
9001

和其他Redis中的結構一樣,成員和值最終是以二進位制陣列儲存的,所以它們可以是任何型別的資料。儘管field很像key,傾向於使用字串。問題是什麼情況下我們應該使用一個Hash表而不是一個String?比方說,這兩者的區別在哪裡?(我使用json來表達複雜的值)

SET users:goku {race: 'sayan', power: 9001}
HSET users:goku race sayan
HSET users:goku power 9001

區別出現在當你要修改和查詢它的時候。如果你需要控制單獨的field,而又不想把整個物件都載入到你的應用中的話,就應該使用hash表。反之,一個String或許就能滿足你的需要。(譯註:String只能控制一級key/value,而hash可以控制更深層次key/value設定。)

Lists

列表讓你將一個陣列與單個key相關聯。實際上,你可以把它想象成是動態陣列。你可以使用insert,append,pop,push,trim等操作。Redis不支援二維索引。你只能通過資料的key來訪問資料。

 length = redis.lpush('users:newest', 'user:goku')
 if length > 100
   #trim is to we only keep 100 "newest" users
   redis.rpop('users:newest')
 end

上面的程式碼儲存了一個在列表中最新註冊使用者的引用。這裡我們在執行時維護列表的長度,儘管我們也可以把它移交給一個後臺任務。我們如何做到這點?

 # get the 10 newest users
 keys = redis.lrange('users:newest', 0, 10)
 #multi get the actual 10 user objects
 redis.mget(*keys)

習慣上來說,開發者都會避免使用這類重複查詢資料庫的動作。但是,有了Redis,這種行為是常見而且高效的。

Sets

集合和列表很像,除了它提供的集合特性(不允許重複元素出現在集合中)。你可以使用SDIFF做集合間的差分,SUNION做集合間的並或者SUNIONSTORE將並集儲存在一個另一個集合中而不是返回出來,等等。集合是一種你可以用來跟蹤好友和標籤的資料結構:

SADD friends:leto ghanima
SADD friends:leto duncan
SADD friends:paul duncan
SADD friends:paul gurney
SINTER friends:leto friends:paul
1) "duncan"

Sorted Sets

比較不同資料結構的好壞是沒有意義的,因為它們各自都滿足不同場景和不同需求,但是排序集合是非常棒的。一個排序集合和普通集合很相似,除了一點,它的值都關聯一個score filed。換句話說,當你將一個值加入一個排序集合時,你必須同時制定一個score。score決定了在集合中值的排列順序。建立在上一個例子的基礎上,我們可以為我們的資料加權:

 ZADD friends:leto 1000 ghanima
 ZADD friends:leto 994 duncan
 ZADD friends:leto 2 farad'n
 ZRANGEBYSCORE friends:leto 500 1000
 1) "duncan"
 2) "ghanima"

上面的程式碼獲取了leto朋友中所有score在500到1000的人。

排序集合不僅僅可以用在管理朋友上。score屬性同樣可以用來跟蹤時間序列(比如使用從1970年到當前時間的毫秒數)或者根據遊戲分數來排序玩家。

Redis Querying

在Redis中,資料只能被使用key查詢。即使你使用一個hash表,我們不能說找到值為sayan所對應的key。在檢視列表時,我們看到自己是如何構建二級索引的。管理你自己的二級索引總是痛苦的,而且有時它會因為太複雜而無法擴充套件。然而,需要記住兩件事。一,你應該玩轉它、嘗試它,在你真正開始寫程式碼之前,即使面對一個複雜的情況,也沒什麼大不了的。二,不要害怕重複訪問Redis。

除了上文舉出的5種資料結構外,Redis還有key的通用命令(稱為key-commands),比如DEL,EXISITSRENAME。或許最常用的命令就是KEYS命令了,它接受一個模式然後返回一組找到的key。例如,mogade.com使用一組類似ranks:daily:GAME_ID:20110830的key來管理每天的遊戲等級。如果你要刪除8月份所有的遊戲等級,可以這樣做:

 keys = redis.keys("ranks:daily:*:201108*")
 redis.del(*keys)

注意:keys-command線性地搜尋所有的key來找到匹配者。這樣做會很慢,一般文件建議你在開發或者debug時才使用。

其他需知事項

Redis的安裝和維護都非常方便。資料被儲存在單個磁碟檔案中,這個檔案可以簡單地通過拷貝來進行備份。它被一個易懂的配置檔案驅動。

所有你的資料都會被讀入到記憶體。它同樣支援虛擬記憶體,但是有人說這個特性沒有試驗成功。虛擬記憶體的使用可能會再後來版本中被去掉。

Redis支援主從複製(master-slave)。它不會做任何自動的失敗備份或者碎片管理。這些可能都是需要你通過比如HAProxy來完成的。Redis Cluster(Redis叢集)功能會加入到不久後的release裡,用於解決這個問題。我們應該關注近期的relase。(如果你感興趣,請參考這篇文件

還有更多關於Redis的內容等著我們。它支援事務,有更多的命令、更多的管理特性,支援key的自動過期,甚至是一個分發/訂閱者 API。儘管我對技術文件非常挑剔,但仍然被Redis的文件參考所震驚。

Redis比其他許多儲存解決方案要更具體。對於複雜的系統來說,正確方式是從一個一個特性入手各個擊破,而不是一口氣吃成胖子。Redis需要把所有東西都載入到記憶體,這或許會限制你對它的使用。然而,當一個個特性有個資料模型合適使用Redis的資料結構時,這是一件令人非常高興的事。Redis非常迅捷,而且API非常簡單。我已經將原數百行的查詢程式碼轉換成了ZADD ZREVRANGE的呼叫。

總之,Redis是非常易於學習和理解的。給定一個問題,你或多或少會清楚Redis是否合適。

結論

把Redis想象成一個Key/Value儲存工具是錯誤的。它要更甚於一個Key/Value儲存工具。它同樣代表一個完全不同的思考資料模型的方式。有時,它不見得有效,但是一旦它有效,啊,那是多麼令人高興!

或許你需要休息下?看看Redis的官網?或者,你可以讀一讀第二部分

原文連結 :Redis: Zero to Master in 30 minutes - Part 1

本文參與iTran樂譯專案。

相關文章