《深刻理解redis》之一:爲何選擇redis

redis是單線程應用程序,佔用較少的內存,能夠快速讀寫數據。web

在基於sql的關係型數據庫中,開發者和數據庫管理員經過將數據規範化爲列、行、表,並經過外鍵關係創建關聯的方式建立數據庫模式。redis

mongdb 、elasticsearch這樣的nosql 數據存儲技術 須要在數據裝載到實際存儲以前 轉換成json文檔數據格式。算法

redis跳過這種中間轉換,它爲特定的數據結構(字符串、列表、哈希、集合、有序集合)提供了一系列命令。sql

經過算法和數據進行交互。以數據在redis中的存儲方式及可用的命令直接構造解決方案,同時能以更直接的方式對目標操做系統的內存和磁盤空間進行調優和監控。數據庫

-------------------------------------------------------------------------------------------------express

世界上大多數圖書館將它們的書目數據存儲並構建於持久性二進制格式機讀編目格式標準(MAchine-Readable Cataloging ,簡稱 MARC)。json

MARC格式是由固定長度+可變長度字段組成的,這些字段的數值範圍從001~999,相應的能夠有字符數據或者含有數據的子字段。此外,每一個字段能夠包含最多兩個指示符,用來修改字段的含義。緩存

MARC域中最經常使用且最爲重要的兩個是100 主要條目-我的名稱 字段 和245題名說明字段。網絡

以David Foster Wallace的書 Infinite jest 示例:數據結構

=100 1\$aWallace,David Foster
=245 10$aInfinite jest:$ba novel$cDavid Foster Wallace

 

爲了在redis裏使用MARC數據,每條MARC記錄都被建模表示爲 marc:{counter} 的哈希鍵,其中counter是全局遞增的計數器。每一個MARC字段都是一個哈希,其鍵爲  marc:{counter}:{field}。因爲部分MARC域會因不一樣的信息而出現重複,所以哈希鍵會包含一個全局計數器,例如: marc:{counter}:{field-counter}。

簡單地存儲上述兩個字段須要如下6條redis命令:

10.143.128.165:6379> INCR marc
(integer) 1
10.143.128.165:6379> INCR marc:1:100
(integer) 1
10.143.128.165:6379> HSET marc:1:100:1 a "Wallace ,Divid Foster"
(integer) 1
10.143.128.165:6379> INCR marc:1:245
(integer) 1
10.143.128.165:6379> HMSET marc:1:245:1 a "Infinite jest:" b "a novel" c "David Foster Wallace"
OK
10.143.128.165:6379> HGETALL marc:1:245:1
1) "a"
2) "Infinite jest:"
3) "b"
4) "a novel"
5) "c"
6) "David Foster Wallace"

redis中鍵的結構以下圖所示:

redis中MARC數據存儲能夠僅經過單個redis的哈希數據類型及一致的鍵語法結構完成。爲了提高redis中書目數據的實用性,並實現以書名和做者名字數字排序的方式獲取圖書館數據的列表記錄,可使用諸如列表或者有序集合等redis中其餘數據類型達成。

在redis中,使用哈希和列表來表達MARC字段和子字段能提供更多信息。

書目記錄的功能性需求,FRBR,是一種能夠替代MARC的文檔,他基於實體-關係(ER)模型。FRBR ER 模型包含了根據抽象規則進行歸類的屬性組。最高抽象是Work(做品)類,表明了用來惟一識別一件富有智慧的做品最爲通用的屬性,包括標題、做者和學科。

Expression(內容表達)類由諸如版本和與父work有肯定關係的譯本組成。

Manifestation(載體表現)和Item(單件)是最後兩個FRBR類,包含更多詳細的數據,其中item是一個具體的物理對象,是更爲通用的Manifestation的具體實例。

僅有少數真實系統或者技術爲圖書館數據實現了FRBR模型,而redis提供使用真實數據測試此類模型的方法。採用將MARC數據映射到FRBR的Work、Expression、Manifestation、Item上的方法,那麼MARC 100和245就能在redis中映射到FRBR的Work。

10.143.128.165:6379> HMSET frbr:work:1 title "Infinite Jest" "created by" "David Foster Wallace"
OK

新的做品frbr:work:1能夠經過下列redis鍵和哈希從而關聯到其他的類:

10.143.128.165:6379> HMSET frbr:expression:1 date 1996 "realization of" frbr:work:1
OK
10.143.128.165:6379> HMSET frbr:manifestation:1  publisher "Little ,Brown and Company"  "physical embodiment of" frbr:expression:1
OK
10.143.128.165:6379> HMSET frbr:item:1   'exemplar of'  frbr:manifestation:1 identifier 33027005910579
OK

在上述 expression 例子中,具體日期是經過 realization of 屬性關聯回  frbr:work:1 。一樣,frbr:manifestation:1哈希擁有兩個字段:出版社和物質載體。物質載體字段的值是  frbr:expression:1 鍵,它將manifestation關聯回expression。最後的frbr:item:1哈希擁有一個條形識別碼屬性和關聯到 frbr:manifestation:1哈希的鍵。

在對MARC和FRBR二者的實驗中,redis哈希數據結構實體提供了基本表達。當具體的屬性多於一個值時,例如當要表達做品的多個做者時,要解決多值屬性的問題,經過像以前那樣爲每一個MARC字段建立一個計數器。舉例來講,針對電子書或者其餘擁有網絡可解析URL的材料,MARC 856字段(電子位置與存取)會爲其存儲URL。若是想爲以前的MARC示例添加兩個URL,例如在Google books裏該書的連接地址及該書的wiki頁面,對應命令以下:

10.143.128.165:6379> INCR global:marc:1:856
(integer) 1
10.143.128.165:6379> HMSET marc:1:856:1 ind1 4 ind2 u https://books.google.com/books?id=Ndxndx7djd
OK
10.143.128.165:6379> HMSET marc:1:856:2 ind1 4 ind2 u https://infinitejest.wallacewiki.com/
OK

針對MARC鍵的命名方法知足重複MARC字段的需求,可是若是單一MARC域擁有多個、重複的子字段呢?首先想到的是 能夠存儲以某種分隔符分割的字符串,其中存儲的每一個值是MARC中特定字段的值。這就要求客戶端進行額外的解析工做來獲取全部不一樣的子字段,同時將失去將這些子字段直接存儲至redis所帶來的額外優點。解決MARC多值子字段問題的第二種方法是進一步擴展redis鍵語法,併爲每一個子字段使用列表或者其餘數據結構。下面擴展MARC 856這個例子,若是想添加第二個電子書的url,如 Amazon kindle版本的url連接:

0.143.128.165:6379> LPUSH marc:1:856:1:u https://books.google.com/books?id=Ndxndx7djd  http://www.amazon.com/Infinite-Jest-David-Foster-Wallace/
(integer) 2
10.143.128.165:6379> HMSET marc:1:856:1 u marc:1:856:1:u
OK

將多個子字段存儲到redis列表 這樣的方法工做的很好,可是若是但願MARC字段的子字段沒有重複的值 該怎麼辦?能夠經過redis的集合類型數據解決。集合的定義就是 只包含惟一的值。使用集合存儲子字段的值看起來是個很是棒的解決方案,但若是須要在子域中存放有序值,集合就顯得捉襟見肘了。

redis的有序集合 確保集合中子字段惟1、沒有重複,還保持了子字段的有序:

10.143.128.165:6379> DEL marc:1:856:1:u
(integer) 1
10.143.128.165:6379> ZADD marc:1:856:1:u 1 https://books.google.com/books?id=Ndxndx7djd 2 http://www.amazon.com/Infinite-Jest-David-Foster-Wallace/
(integer) 2
10.143.128.165:6379> ZRANGE marc:1:856:1:u 0 -1 WITHSCORES
1) "https://books.google.com/books?id=Ndxndx7djd"
2) "1"
3) "http://www.amazon.com/Infinite-Jest-David-Foster-Wallace/"
4) "2"

在該示例中,研究瞭如何表示稱爲MARC的圖書館數據遺留格式,以及MARC的字段和子字段如何以哈希的形式存儲到redis中。

--------------------------------------------------------------流行的使用模式

對於redis來講,一種很是受歡迎的使用模式是做爲web應用程序的內存緩存

經過利用redis爲鍵設置過時時間的功能,流行的redis緩存策略之一--最近最少使用(less recently userd,LRU)策略變得很是健壯,足以應對最大的網絡站點。它將最受歡迎的內容保存在緩存中,同時將陳舊的、較少使用的數據驅逐出數據存儲。這種緩存的使用場景並不假定原始的web元素或者頁面是有redis中的數據產生的。最多見的使用模式是有其餘來源的數據動態生成web內容,而將redis做爲出色的web緩存層。

第二種流行的使用模式是將redis用做web頁面使用狀況和玩家排行榜上的用戶行爲等定量數據的指標存儲經過在字符串上進行位操做,redis能夠很是高效地將二進制信息存儲於特定的字符上。就拿網站使用來講,有個從日期構造的鍵 page-usage:2016-11-01,它對應一個字符串,當該頁面被用戶訪問時,就將其中 的一位設置爲1.

網站在11月1日的每日使用狀況能夠經過page-usage:2016-11-01鍵上調用簡單的redis的bitcount命令獲取。

第三種流行的redis使用模式是經過發佈/訂閱(簡稱pub/sub)模型做爲不一樣系統之間的通訊層。在這種模型中,消息的發佈方將消息發送至一到多個信道(channel)上,這些消息會被訂閱或者監聽信道上發來消息的其餘系統處理。

一般,消息發佈方無需知道具體的訂閱方就能將消息發送給他們(相對點對點消息通訊模式來講),發佈方僅需知道消息內容和用於發送消息的信道便可。一樣,訂閱方也無需知道每一個發送方,只需關注信道接受消息便可。發佈/訂閱很是棒,由於它擴展起來很是容易,同時消息的發佈方和訂閱方能夠是幾乎徹底不一樣的程序和系統。

相關文章
相關標籤/搜索