前幾天微博發生了一塊兒大的系統故障,不少技術的朋友都比較關心,其中的緣由不會超出James Hamilton在On Designing and Deploying Internet-Scale Service(1)歸納的那幾個範圍,James第一條經驗「Design for failure」是全部互聯網架構成功的一個關鍵。互聯網系統的工程理論其實很是簡單,James paper中內容幾乎稱不上理論,而是多條實踐經驗分享,每一個公司對這些經驗的理解及執行力決定了架構成敗。html
題外話說完,最近又研究了Redis。去年曾作過一個MemcacheDB, Tokyo Tyrant, Redis performance test,到目前爲止,這個benchmark結果依然有效。這1年咱們經歷了不少眼花繚亂的key value存儲產品的誘惑,從Cassandra的淡出(Twitter暫停在主業務使用)到HBase的興起(Facebook新的郵箱業務選用HBase(2)),當再回頭再去看Redis,發現這個只有1萬多行源代碼的程序充滿了神奇及大量未經挖掘的特性。Redis性能驚人,國內前十大網站的子產品估計用1臺Redis就能夠知足存儲及Cache的需求。除了性能印象以外,業界其實廣泛對Redis的認識存在必定誤區。本文提出一些觀點供你們探討。redis
這個問題的結果影響了咱們怎麼用Redis。若是你認爲Redis是一個key value store, 那可能會用它來代替MySQL;若是認爲它是一個能夠持久化的cache, 可能只是它保存一些頻繁訪問的臨時數據。Redis是REmote DIctionary Server的縮寫,在Redis在官方網站的的副標題是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems,這個定義偏向key value store。還有一些見解則認爲Redis是一個memory database,由於它的高性能都是基於內存操做的基礎。另一些人則認爲Redis是一個data structure server,由於Redis支持複雜的數據特性,好比List, Set等。對Redis的做用的不一樣解讀決定了你對Redis的使用方式。數據庫
互聯網數據目前基本使用兩種方式來存儲,關係數據庫或者key value。可是這些互聯網業務自己並不屬於這兩種數據類型,好比用戶在社會化平臺中的關係,它是一個list,若是要用關係數據庫存儲就須要轉換成一種多行記錄的形式,這種形式存在不少冗餘數據,每一行須要存儲一些重複信息。若是用key value存儲則修改和刪除比較麻煩,須要將所有數據讀出再寫入。Redis在內存中設計了各類數據類型,讓業務可以高速原子的訪問這些數據結構,而且不須要關心持久存儲的問題,從架構上解決了前面兩種存儲須要走一些彎路的問題。設計模式
不少開發者都認爲Redis不可能比Memcached快,Memcached徹底基於內存,而Redis具備持久化保存特性,即便是異步的,Redis也不可能比Memcached快。可是測試結果基本是Redis佔絕對優點。一直在思考這個緣由,目前想到的緣由有這幾方面。數據結構
Redis的數據所有放在內存帶來了高速的性能,可是也帶來一些不合理之處。好比一箇中型網站有100萬註冊用戶,若是這些資料要用Redis來存儲,內存的容量必須可以容納這100萬用戶。可是業務實際狀況是100萬用戶只有5萬活躍用戶,1周來訪問過1次的也只有15萬用戶,所以所有100萬用戶的數據都放在內存有不合理之處,RAM須要爲冷數據買單。架構
這跟操做系統很是類似,操做系統全部應用訪問的數據都在內存,可是若是物理內存容納不下新的數據,操做系統會智能將部分長期沒有訪問的數據交換到磁盤,爲新的應用留出空間。現代操做系統給應用提供的並非物理內存,而是虛擬內存(Virtual Memory)的概念。併發
基於相同的考慮,Redis 2.0也增長了VM特性。讓Redis數據容量突破了物理內存的限制。並實現了數據冷熱分離。app
Redis的VM依照以前的epoll實現思路依舊是本身實現。可是在前面操做系統的介紹提到OS也能夠自動幫程序實現冷熱數據分離,Redis只須要OS申請一塊大內存,OS會自動將熱數據放入物理內存,冷數據交換到硬盤,另一個知名的「理解了現代操做系統(3)」的Varnish就是這樣實現,也取得了很是成功的效果。異步
做者antirez在解釋爲何要本身實現VM中提到幾個緣由(6)。主要OS的VM換入換出是基於Page概念,好比OS VM1個Page是4K, 4K中只要還有一個元素即便只有1個字節被訪問,這個頁也不會被SWAP, 換入也一樣道理,讀到一個字節可能會換入4K無用的內存。而Redis本身實現則能夠達到控制換入的粒度。另外訪問操做系統SWAP內存區域時block進程,也是致使Redis要本身實現VM緣由之一。oop
做爲一個key value存在,不少開發者天然的使用set/get方式來使用Redis,實際上這並非最優化的使用方法。尤爲在未啓用VM狀況下,Redis所有數據須要放入內存,節約內存尤爲重要。
假如一個key-value單元須要最小佔用512字節,即便只存一個字節也佔了512字節。這時候就有一個設計模式,能夠把key複用,幾個key-value放入一個key中,value再做爲一個set存入,這樣一樣512字節就會存放10-100倍的容量。
這就是爲了節約內存,建議使用hashset而不是set/get的方式來使用Redis,詳細方法見參考文獻(7)。
Redis有兩種存儲方式,默認是snapshot方式,實現方法是定時將內存的快照(snapshot)持久化到硬盤,這種方法缺點是持久化以後若是出現crash則會丟失一段數據。所以在完美主義者的推進下做者增長了aof方式。aof即append only mode,在寫入內存數據的同時將操做命令保存到日誌文件,在一個併發更改上萬的系統中,命令日誌是一個很是龐大的數據,管理維護成本很是高,恢復重建時間會很是長,這樣致使失去aof高可用性本意。另外更重要的是Redis是一個內存數據結構模型,全部的優點都是創建在對內存複雜數據結構高效的原子操做上,這樣就看出aof是一個很是不協調的部分。
其實aof目的主要是數據可靠性及高可用性,在Redis中有另一種方法來達到目的:Replication。因爲Redis的高性能,複製基本沒有延遲。這樣達到了防止單點故障及實現了高可用。
要想成功使用一種產品,咱們須要深刻了解它的特性。Redis性能突出,若是可以熟練的駕馭,對國內不少大型應用具備很大幫助。但願更多同行加入到Redis使用及代碼研究行列。