閑聊RedisRedis 是一個有趣的項(xiàng)目,與其把它說成鍵值存儲、鍵值緩存還不如把它說成是一個遠(yuǎn)程的數(shù)據(jù)結(jié)構(gòu)。 Redis的項(xiàng)目名是Remote Dictionary Server的縮寫,我覺得還不如叫Remote Data Structure Server – Redss 很多人把它和memcached比較,把它和tt比較,我覺得Redis在提供了諸多功能的同時又保證了代碼的簡潔和實(shí)現(xiàn)的簡潔,這個很好。 Redis中的很多功能是memcached/tt沒有的,當(dāng)然對于mongodb來說可能可以實(shí)現(xiàn)Redis的大多數(shù)功能但是又顯得過于重量級了。 所謂程序就是數(shù)據(jù)結(jié)構(gòu)加上算法,沒錯,但如果對于大多數(shù)應(yīng)用級別的程序來說,就變成了邏輯加上關(guān)系型數(shù)據(jù)庫(MSSQL/MYSQL)了。 關(guān)系型數(shù)據(jù)庫是普適的,因此也就非常重,其實(shí)有的時候我們并不需要這么完備的數(shù)據(jù)庫,那么有人會想到在內(nèi)存中維護(hù)一個自己的數(shù)據(jù)結(jié)構(gòu),直接在內(nèi)存中進(jìn)行快速操作。 而Redis正是這么一種提供了多種value數(shù)據(jù)結(jié)構(gòu)(現(xiàn)在有字符串/列表/集合/有序集合/哈希,或許將來還會有更多的數(shù)據(jù)結(jié)構(gòu))的遠(yuǎn)程鍵值存儲。 集合和列表的好處不僅僅是可以在服務(wù)端進(jìn)行直接操作,另一個好處也是節(jié)約了key占據(jù)的空間。 PS:Redis支持key的expire,但是不能為list/set中的一個item設(shè)置過期,如果需要的話貌似只能平板化成一級key,這樣就喪失了很多特性,這點(diǎn)比較郁悶。 別小看這些豐富的數(shù)據(jù)結(jié)構(gòu),如果memcached只能用來做緩存的話,Redis就可以深深地和業(yè)務(wù)邏輯結(jié)合在一起,以高效的方式實(shí)現(xiàn)緩存或存儲。 比如對于普通的鍵值存儲,我們?nèi)绻枰獮橹翟黾右豁?xiàng)需要取出修改保存三個過程,但是現(xiàn)在只需要提交一次追加在頭部/添加在尾部操作。 除此之外,Redis還提供其它一些很有用的特性: 1) 事務(wù):允許讓一組命令進(jìn)入隊(duì)列一次性執(zhí)行,在執(zhí)行的過程中不穿插其它命令(Redis的單線程保證)。但是要注意的是,并不能保證隊(duì)列中操作的key沒有 變化(并發(fā)環(huán)境),可以使用WATCH來監(jiān)視并在并發(fā)時回滾(樂觀并發(fā))。當(dāng)然,Redis中也提供了很多組合型的原子命令(比如檢查并添加,刪除后添 加,這些組合特別有用)。 2) 管道:一次性提交多個命令(如果只是進(jìn)行一些設(shè)置,命令之間不需要依賴前置命令結(jié)果的話,可以提高不少效率)。當(dāng)然,Redis還提供了很多Multi-的命令,允許一次性進(jìn)行多個值的添加,獲取等等。 3) 持久:有快照和日志兩種方式。對于(后臺)快照就是在保存的時候開啟子進(jìn)程(當(dāng)然也可以前臺方式)將整個(32G內(nèi)存的dump過程想想真恐怖?)內(nèi)存快 照寫入臨時文件(在此過程中的修改操作為父進(jìn)程的內(nèi)存頁創(chuàng)建副本,那么最壞的情況可能要多用一倍內(nèi)存),之后再替換原來的dump文件。所謂日志就是每一 次寫操作生成日志(日志的持久化也有每秒/每次和依賴于OS三種方式),適用于不太適合丟失的數(shù)據(jù)的保存,當(dāng)然效率也會差。 4) 復(fù)制:支持多層次的主從訂閱。那么我們就有很多配置方式了,可以讓主作為寫,從作為運(yùn)算,可以讓主作為內(nèi)存數(shù)據(jù)庫,從作為持久化的備份。在建立訂閱關(guān)系之 后,主會把內(nèi)存映像在后臺保存下來然后發(fā)動給各個從,并且保存后續(xù)的寫操作命令,從收到文件后恢復(fù)文件中的快照再接受主保存的后續(xù)操作命令。 5) VM:操作系統(tǒng)的頁過大,Redis默認(rèn)使用32字節(jié)的頁。把所有的鍵保存在內(nèi)存中,把所有的值壓縮(很厲害,保存10G的數(shù)據(jù)才占用2G不到的存儲,我都懷疑我看錯了)保存在swap中。也可以配置選擇使用同步或異步方式進(jìn)行換入換出。 Redis靈活的配置允許我們做各種優(yōu)化,并且也提供了盡可能靈活和豐富的API。從效率上來說,我做過簡單的性能測試,比memcached有略 微高一點(diǎn)的讀寫效率(比libevent更輕量級的網(wǎng)絡(luò)實(shí)現(xiàn)?),但是在快照方式持久化的時候,讀寫效率一下子降低,可能大量的IO都用于內(nèi)存映像的轉(zhuǎn)存 了,CPU占用也很高。在達(dá)到500萬數(shù)據(jù)量之后,讀寫效率可以降低一半。 另外要說明的是,每一個Redis的API都提供了Big O表示法,在使用之前需要了解,您不能期待雙向鏈表的隨機(jī)讀取效率和hashtable的隨機(jī)讀取效率一樣。 換一句話說,我們需要細(xì)致得去使用Redis,盡量確保比較少的大O,盡量確保比較少的網(wǎng)絡(luò)傳輸,不能像使用關(guān)系型數(shù)據(jù)庫一樣。 現(xiàn)在再來說說另外一個問題,那就是集群/數(shù)據(jù)分區(qū)。對于memcached這樣的緩存來說,一致性哈希就可以了,我們只需要保證在擴(kuò)容的時候不會損 失大量的命中,并不一定要保證數(shù)據(jù)不能丟失。在業(yè)務(wù)系統(tǒng)重啟的時候,緩存數(shù)據(jù)往往也需要重新來過,因此memcached服務(wù)端并沒有實(shí)現(xiàn)集群,這一切都 是客戶端進(jìn)行的。對于存儲就不一樣了,比如mongodb實(shí)現(xiàn)了sharding,而如果現(xiàn)在希望把Redis用作存儲并且一個節(jié)點(diǎn)不足以支持應(yīng)用的話, 我們可以手動為業(yè)務(wù)分配不同的節(jié)點(diǎn),也可以和memcached一樣采取一致性哈希(在擴(kuò)容的時候業(yè)務(wù)上可以忍受部分?jǐn)?shù)據(jù)的丟失,Redis現(xiàn)在還沒有支 持客戶端哈希的.NET客戶端)。 對于Redis 3.0,據(jù)說會支持Redis集群: 1) 節(jié)點(diǎn)之間可以互相通訊,和服務(wù)端口不同的端口通訊。 2) 所有數(shù)據(jù)的key被分成幾千份(哈希槽),分布在現(xiàn)有的節(jié)點(diǎn)中。 3) 在增加了一個節(jié)點(diǎn)后,會把相應(yīng)的數(shù)據(jù)轉(zhuǎn)移過去。 4) 新的key的操作會轉(zhuǎn)移到新節(jié)點(diǎn),老的key的操作每一次都會詢問老節(jié)點(diǎn)是否已轉(zhuǎn)移。 5) 轉(zhuǎn)移完成之后所有之后的請求會直接請求新的節(jié)點(diǎn)。 6) 節(jié)點(diǎn)支持主從多份備份,自動適應(yīng)節(jié)點(diǎn)的故障(和mongodb的replica set類似)。 據(jù)說這都會在服務(wù)端實(shí)現(xiàn),也就是proxy方式,那么到時候可能會有config/proxy/data不同形式的節(jié)點(diǎn)(和mongodb的sharding類似)。 其實(shí)如果能不根據(jù)key的數(shù)量而根據(jù)key的訪問壓力進(jìn)行遷移的話那就更好了,不過這樣config db可能需要存儲更多的數(shù)據(jù)。 總而言之,Redis創(chuàng)新點(diǎn)是很多的,使用起來也是很靈活的,當(dāng)然也就意味著配置和API的復(fù)雜。完全可以使用Redis完整實(shí)現(xiàn)一個應(yīng)用。 Mongodb實(shí)現(xiàn)超大日志/報表數(shù)據(jù)存儲,Redis實(shí)現(xiàn)部分業(yè)務(wù)數(shù)據(jù)的計(jì)算和緩存/存儲,配合起來確實(shí)不錯。 感嘆一下,開源的東西變化快,BUG修改快,客戶端比較悲劇,不斷需要和服務(wù)端保持同步的修改。 最后這里推薦一個有關(guān)Redis的ppt: Redis in Practice
View more presentations from noahd1.
當(dāng)然,也可以看看這個我做的PPT,里面有對所有API的翻譯: Redis
View more presentations from powerzhuye.
|
|