NoSQL數據庫筆談(轉)

NoSQL數據庫筆談

databases ,  appdir ,  node ,  paper
顏開 , v0.2 , 2010.2
  1. 思想篇
    1. CAP
    2. 最終一致性
      1. 變體
    3. BASE
    4. 其餘
      1. I/O的五分鐘法則
      2. 不要刪除數據
      3. RAM是硬盤,硬盤是磁帶
      4. Amdahl定律和Gustafson定律
      5. 萬兆以太網
  2. 手段篇
    1. 一致性哈希
      1. 亞馬遜的現狀
      2. 算法的選擇
    2. Quorum NRW
    3. Vector clock
    4. Virtual node
    5. gossip
      1. Gossip (State Transfer Model)
      2. Gossip (Operation Transfer Model)
    6. Merkle tree
    7. Paxos
      1. 背景
    8. DHT
    9. Map Reduce Execution
    10. Handling Deletes
    11. 存儲實現
    12. 節點變化
    13. 列存
      1. 描述
      2. 特色
  3. 軟件篇
    1. 亞數據庫
      1. MemCached
        1. 特色
        2. 內存分配
        3. 緩存策略
        4. 緩存數據庫查詢
        5. 數據冗餘與故障預防
        6. Memcached客戶端(mc)
        7. 緩存式的Web應用程序架構
        8. 性能測試
      2. dbcached
        1. Memcached 和 dbcached 在功能上同樣嗎?
    2. 列存系列
      1. Hadoop之Hbase
      2. 耶魯大學之HadoopDB
      3. GreenPlum
      4. FaceBook之Cassandra
        1. Cassandra特色
        2. Keyspace
        3. Column family(CF)
        4. Key
        5. Column
        6. Super column
        7. Sorting
        8. 存儲
        9. API
      5. Google之BigTable
      6. Yahoo之PNUTS
        1. 特色
        2. PNUTS實現
          1. Record-level mastering 記錄級別主節點
          2. PNUTS的結構
          3. Tablets尋址與切分
          4. Write調用示意圖
        3. PNUTS感悟
      7. 微軟之SQL數據服務
    3. 非雲服務競爭者
    4. 文檔存儲
      1. CouchDB
        1. 特性
      2. Riak
      3. MongoDB
      4. Terrastore
      5. ThruDB
    5. Key Value / Tuple 存儲
      1. Amazon之SimpleDB
      2. Chordless
      3. Redis
      4. Scalaris
      5. Tokyo cabinet / Tyrant
      6. CT.M
      7. Scalien
      8. Berkley DB
      9. MemcacheDB
      10. Mnesia
      11. LightCloud
      12. HamsterDB
      13. Flare
    6. 最終一致性Key Value存儲
      1. Amazon之Dynamo
        1. 功能特點
        2. 架構特點
      2. BeansDB
        1. 簡介
        2. 更新
        3. 特性
        4. 性能
      3. Nuclear
        1. 兩個設計上的Tips
      4. Voldemort
      5. Dynomite
      6. Kai
    7. 未分類
      1. Skynet
      2. Drizzle
    8. 比較
      1. 可擴展性
      2. 數據和查詢模型
      3. 持久化設計
  4. 應用篇
    1. eBay 架構經驗
    2. 淘寶架構經驗
    3. Flickr架構經驗
    4. Twitter運維經驗
      1. 運維經驗
        1. Metrics
        2. 配置管理
        3. Darkmode
        4. 進程管理
        5. 硬件
      2. 代碼協同經驗
        1. Review制度
        2. 部署管理
        3. 團隊溝通
      3. Cache
    5. 雲計算架構
    6. 反模式
      1. 單點失敗(Single Point of Failure)
      2. 同步調用
      3. 不具有回滾能力
      4. 不記錄日誌
      5. 無切分的數據庫
      6. 無切分的應用
      7. 將伸縮性依賴於第三方廠商
    7. OLAP
      1. OLAP報表產品最大的難點在哪裏?
    8. NOSQL們背後的共有原則
      1. 假設失效是必然發生的
      2. 對數據進行分區
      3. 保存同一數據的多個副本
      4. 動態伸縮
      5. 查詢支持
      6. 使用 Map/Reduce 處理匯聚
      7. 基於磁盤的和內存中的實現
      8. 僅僅是炒做?
    1. 感謝
    2. 版本志
    3. 引用

 

日前國內沒有一套比較完整的NoSQL數據庫資料,有不少先驅整理髮表了不少,但不是很系統。不材嘗試着將各家的資料整合一下,並書寫了一些本身的看法。
本書寫了一些目前的NoSql的一些主要技術,算法和思想。同時列舉了大量的現有的數據庫實例。讀徹底篇,相信讀者會對NoSQL數據庫瞭解個大概。
另外我還準備開發一個開源內存數據庫galaxydb.本書也是爲這個數據庫提供一些架構資料。php

思想篇

CAP,BASE和最終一致性是NoSQL數據庫存在的三大基石。而五分鐘法則是內存數據存儲了理論依據。這個是一切的源頭。

CAP

NoSQL數據庫


  • C: Consistency 一致性
  • A: Availability 可用性(指的是快速獲取數據)
  • P: Tolerance of network Partition 分區容忍性(分佈式)

 

10年前,Eric Brewer教授指出了著名的CAP理論,後來Seth Gilbert 和 Nancy lynch兩人證實了CAP理論的正確性。CAP理論告訴咱們,一個分佈式系統不可能知足一致性,可用性和分區容錯性這三個需求,最多隻能同時知足兩個。
熊掌與魚不可兼得也。關注的是一致性,那麼您就須要處理由於系統不可用而致使的寫操做失敗的狀況,而若是您關注的是可用性,那麼您應該知道系統的read操做可能不能精確的讀取到write操做寫入的最新值。所以系統的關注點不一樣,相應的採用的策略也是不同的,只有真正的理解了系統的需求,纔有可能利用好CAP理論。
 
做爲架構師,通常有兩個方向來利用CAP理論
  1. key-value存儲,如Amaze Dynamo等,可根據CAP三原則靈活選擇不一樣傾向的數據庫產品。
  2. 領域模型 + 分佈式緩存 + 存儲 (Qi4j和NoSql運動),可根據CAP三原則結合本身項目定製靈活的分佈式方案,難度高。
我準備提供第三種方案:實現能夠配置CAP的數據庫,動態調配CAP。
 
  • CA:傳統關係數據庫
  • AP:key-value數據庫
而對大型網站,可用性與分區容忍性優先級要高於數據一致性,通常會盡可能朝着 A、P 的方向設計,而後經過其它手段保證對於一致性的商務需求。架構設計師不要精力浪費在如何設計能知足三者的完美分佈式系統,而是應該進行取捨。
不一樣數據對於一致性的要求是不一樣的。舉例來說,用戶評論對不一致是不敏感的,能夠容忍相對較長時間的不一致,這種不一致並不會影響交易和用戶體驗。而產品價格數據則是很是敏感的,一般不能容忍超過10秒的價格不一致。

CAP理論的證實:Brewer's CAP Theorem

最終一致性

一言以蔽之:過程鬆,結果緊,最終結果必須保持一致性

 

爲了更好的描述客戶端一致性,咱們經過如下的場景來進行,這個場景中包括三個組成部分:
  • 存儲系統
存儲系統能夠理解爲一個黑盒子,它爲咱們提供了可用性和持久性的保證。
  • Process A
ProcessA主要實現從存儲系統write和read操做
  • Process B 和ProcessC 
ProcessB和C是獨立於A,而且B和C也相互獨立的,它們同時也實現對存儲系統的write和read操做。


下面以上面的場景來描述下不一樣程度的一致性:

html

  • 強一致性
強一致性(即時一致性) 假如A先寫入了一個值到存儲系統,存儲系統保證後續A,B,C的讀取操做都將返回最新值
  • 弱一致性
假如A先寫入了一個值到存儲系統,存儲系統不能保證後續A,B,C的讀取操做能讀取到最新值。此種狀況下有一個「不一致性窗口」的概念,它特指從A寫入值,到後續操做A,B,C讀取到最新值這一段時間。
  • 最終一致性
最終一致性是弱一致性的一種特例。假如A首先write了一個值到存儲系統,存儲系統保證若是在A,B,C後續讀取以前沒有其它寫操做更新一樣的值的話,最終全部的讀取操做都會讀取到最A寫入的最新值。此種狀況下,若是沒有失敗發生的話,「不一致性窗口」的大小依賴於如下的幾個因素:交互延遲,系統的負載,以及複製技術中replica的個數(這個能夠理解爲master/salve模式中,salve的個數),最終一致性方面最出名的系統能夠說是DNS系統,當更新一個域名的IP之後,根據配置策略以及緩存控制策略的不一樣,最終全部的客戶都會看到最新的值。

變體

  • Causal consistency(因果一致性)
若是Process A通知Process B它已經更新了數據,那麼Process B的後續讀取操做則讀取A寫入的最新值,而與A沒有因果關係的C則能夠最終一致性。
  • Read-your-writes consistency
若是Process A寫入了最新的值,那麼Process A的後續操做都會讀取到最新值。可是其它用戶可能要過一會才能夠看到。
  • Session consistency
此種一致性要求客戶端和存儲系統交互的整個會話階段保證Read-your-writes consistency.Hibernate的session提供的一致性保證就屬於此種一致性。
  • Monotonic read consistency
此種一致性要求若是Process A已經讀取了對象的某個值,那麼後續操做將不會讀取到更早的值。
  • Monotonic write consistency
此種一致性保證系統會序列化執行一個Process中的全部寫操做。

BASE

提及來頗有趣,BASE的英文意義是鹼,而ACID是酸。真的是水火不容啊。

前端

  • Basically Availble --基本可用
  • Soft-state --軟狀態/柔性事務
"Soft state" 能夠理解爲"無鏈接"的, 而 "Hard state" 是"面向鏈接"的
  • Eventual Consistency --最終一致性
最終一致性, 也是是 ACID 的最終目的。

BASE模型反ACID模型,徹底不一樣ACID模型,犧牲高一致性,得到可用性或可靠性: Basically Available基本可用。支持分區失敗(e.g. sharding碎片劃分數據庫) Soft state軟狀態 狀態能夠有一段時間不一樣步,異步。 Eventually consistent最終一致,最終數據是一致的就能夠了,而不是時時一致。

BASE思想的主要實現有
1.按功能劃分數據庫
2.sharding碎片 

BASE思想主要強調基本的可用性,若是你須要高可用性,也就是純粹的高性能,那麼就要以一致性或容錯性爲犧牲,BASE思想的方案在性能上仍是有潛力可挖的。

其餘


I/O的五分鐘法則

在 1987 年, Jim Gray 與 Gianfranco Putzolu 發表了這個"五分鐘法則"的觀點,簡而言之,若是一條記錄頻繁被訪問,就應該放到內存裏,不然的話就應該待在硬盤上按須要再訪問。這個臨界點就是五分鐘。 看上去像一條經驗性的法則,實際上五分鐘的評估標準是根據投入成本判斷的,根據當時的硬件發展水準,在內存中保持 1KB 的數據成本至關於硬盤中存據 400 秒的開銷(接近五分鐘)。這個法則在 1997 年左右的時候進行過一次回顧,證明了五分鐘法則依然有效(硬盤、內存實際上沒有質的飛躍),而此次的回顧則是針對 SSD 這個"新的舊硬件"可能帶來的影響。







不要刪除數據


Oren Eini(又名Ayende Rahien)建議開發者儘可能避免數據庫的軟刪除操做,讀者可能所以認爲硬刪除是合理的選擇。做爲對Ayende文章的迴應,Udi Dahan強烈建議徹底避免數據刪除。

所謂軟刪除主張在表中增長一個IsDeleted列以保持數據完整。若是某一行設置了IsDeleted標誌列,那麼這一行就被認爲是已刪除的。Ayende以爲這種方法「簡單、容易理解、容易實現、容易溝通」,但「每每是錯的」。問題在於:

刪除一行或一個實體幾乎總不是簡單的事件。它不只影響模型中的數據,還會影響模型的外觀。因此咱們纔要有外鍵去確保不會出現「訂單行」沒有對應的父「訂單」的狀況。而這個例子只能算是最簡單的狀況。……

當採用軟刪除的時候,無論咱們是否情願,都很容易出現數據受損,好比誰都不在乎的一個小調整,就可能使「客戶」的「最新訂單」指向一條已經軟刪除的訂單。

若是開發者接到的要求就是從數據庫中刪除數據,要是不建議用軟刪除,那就只能硬刪除了。爲了保證數據一致性,開發者除了刪除直接有關的數據行,還應該級聯地刪除相關數據。可Udi Dahan提醒讀者注意,真實的世界並非級聯的:

假設市場部決定從商品目錄中刪除同樣商品,那是否是說全部包含了該商品的舊訂單都要一併消失?再級聯下去,這些訂單對應的全部發票是否是也該刪除?這麼一步步刪下去,咱們公司的損益報表是否是應該重作了?

沒天理了。

問題彷佛出在對「刪除」這詞的解讀上。Dahan給出了這樣的例子:

我說的「刪除」實際上是指這產品「停售」了。咱們之後再也不賣這種產品,清掉庫存之後再也不進貨。之後顧客搜索商品或者翻閱目錄的時候不會再看見這種商品,但管倉庫的人暫時還得繼續管理它們。「刪除」是個貪方便的說法。

他接着舉了一些站在用戶角度的正確解讀:


訂單不是被刪除的,是被「取消」的。訂單取消得太晚,還會產生花費。

員工不是被刪除的,是被「解僱」的(也多是退休了)。還有相應的補償金要處理。

職位不是被刪除的,是被「填補」的(或者招聘申請被撤回)。

在上面這些例子中,咱們的着眼點應該放在用戶但願完成的任務上,而非發生在某個
實體身上的技術動做。幾乎在全部的狀況下,須要考慮的實體總不止一個。

爲了代替IsDeleted標誌,Dahan建議用一個表明相關數據狀態的字段:有效、停用、取消、棄置等等。用戶能夠藉助這樣一個狀態字段回顧過去的數據,做爲決策的依據。

刪除數據除了破壞數據一致性,還有其它負面的後果。Dahan建議把全部數據都留在數據庫裏:「別刪除。就是別
刪除。」

RAM是硬盤,硬盤是磁帶


Jim Gray在過去40年中對技術發展有過巨大的貢獻,「內存是新的硬盤,硬盤是新的磁帶」是他的名言。「實時」Web應用不斷涌現,達到海量規模的系統愈來愈多,這種後浪推前浪的發展模式對軟硬件又有何影響?

Tim Bray早在網格計算成爲熱門話題以前,就 討論過以RAM和網絡爲中心的硬件結構的優點,能夠用這種硬件創建比磁盤集羣速度更快的RAM集羣。
對於數據的隨機訪問,內存的速度比硬盤高几個數量級(即便是最高端的磁盤存儲系統也只是勉強達到1,000次尋道/秒)。其次, 隨着數據中心的網絡速度提升,訪問內存的成本更進一步下降。經過網絡訪問另外一臺機器的內存比訪問磁盤成本更低。就在我寫下這段話的時候,Sun的 Infiniband產品線中有一款具有9個全互聯非阻塞端口交換機,每一個端口的速度能夠達到30Gbit/sec!Voltaire產品的端口甚至更多;簡直不敢想象。(若是你想了解這類超高性能網絡的最新進展,請關注Andreas Bechtolsheim在Standford開設的課程。)

各類操做的時間,以2001年夏季,典型配置的 1GHz 我的計算機爲標準:java

執行單一指令 1 納秒
從L1 高速緩存取一個字 2 納秒
從內存取一個字 10 納秒
從磁盤取連續存放的一個字 200 納秒
磁盤尋址並取字 8 毫秒
以太網 2GB/s



Tim還指出Jim Gray的
名言中後半句所闡述的真理:「對於隨機訪問,硬盤慢得不可忍受;但若是你把硬盤當成磁帶來用,它吞吐連續數據的速率使人震驚;它天生適合用來給以RAM爲主的應用作日誌(logging and journaling)。」 

時間閃到幾年以後的今天,咱們發現硬件的發展趨勢在RAM和網絡領域勢頭不減,而在硬盤領域則止步不前。Bill McColl提到用於並行計算的 海量內存系統已經出現
內存是新的硬盤!硬盤速度提升緩慢,內存芯片容量指數上升,in-memory軟件架構有望給各種數據密集的應用帶來數量級的性能提高。小型機架服務器(1U、2U)很快就會具有T字節、甚至更大量的內存,這將會改變服務器架構中內存和硬盤之間的平衡。硬盤將成爲新的磁帶,像磁帶同樣做爲順序存儲介質使用(硬盤的順序訪問至關快速),而再也不是隨機存儲介質(很是慢)。這裏面有着大量的機會,新產品的性能有望提升10倍、100倍。
Dare Obsanjo指出 若是不把這句真言當回事,會帶來什麼樣的惡劣後果—— 也就是Twitter正面臨的麻煩。論及Twitter的內容管理,Obsanjo說,「若是一個設計只是簡單地反映了問題描述,你去實現它就會落入磁盤 I/O的地獄。無論你用Ruby on Rails、Cobol on Cogs、C++仍是手寫彙編都同樣,讀寫負載照樣會害死你。」換言之,應該把隨機操做推給RAM,只給硬盤留下順序操做。 

Tom WhiteHadoop Core項目的提交者,也是Hadoop項目管理委員會的成員。他對Gray的真言中「硬盤是新的磁帶」部分做了更深刻地探討。White在討論MapReduce編程模型的時候指出,爲什麼對於Hadloop這類工具來講, 硬盤仍然是可行的應用程序數據存儲介質:
本質上,在MapReduce的工做方式中,數據流式地讀出和寫入硬盤,MapReduce是以硬盤的傳輸速率不斷地對這些數據進行排序和合並。 與之相比,訪問關係數據庫中的數據,其速率則是硬盤的尋道速率(尋道指移動磁頭到盤面上的指定位置讀取或寫入數據的過程)。爲何要強調這一點?請看看尋道時間和磁盤傳輸率的發展曲線。尋道時間每一年大約提升5%,而數據傳輸率每一年大約提升20%。尋道時間的進步比數據傳輸率慢——所以採用由數據傳輸率決定性能的模型是有利的。MapReduce正是如此。
雖然固態硬盤(SSD)可否改變尋道時間/傳輸率的對比還有待觀察, White文章的跟貼中,不少人都認爲 SSD會成爲RAM/硬盤之爭中的平衡因素。 

Nati Shalom對 內存和硬盤在數據庫部署和使用中的角色做了一番有理有據的評述。 Shalom着重指出用數據庫集羣和分區來解決性能和可伸縮性的侷限。他說,「數據庫複製和數據庫分區都存在相同的基本問題,它們都依賴於文件系統/硬盤 的性能,創建數據庫集羣也很是複雜」。他提議的方案是轉向In-Memory Data Grid(IMDG),用Hibernate二級緩存或者GigaSpaces Spring DAO之類的技術做支撐,將持久化做爲服務(Persistence as a Service)提供給應用程序。Shalom解釋說,IMDG
提供在內存中的基於對象的數據庫能力,支持核心的數據庫功能,諸如高級索引和查詢、事務語義和鎖。IMDG還從應用程序的代碼中抽象出了數據的拓撲。經過這樣的方式,數據庫不會徹底消失,只是挪到了「正確的」位置。
IMDG相比直接RDBMS訪問的優點列舉以下:
  • 位於內存中,速度和併發能力都比文件系統優越得多
  • 數據可經過引用訪問
  • 直接對內存中的對象執行數據操做
  • 減小數據的爭用
  • 並行的聚合查詢
  • 進程內(In-process)的局部緩存
  • 免除了對象-關係映射(ORM)

你是否須要改變對應用和硬件的思惟方式,最終取決於你要用它們完成的工做。但彷佛公論認爲,開發者解決性能和可伸縮性的思路已經到了該變一變的時候。 node

Amdahl定律和Gustafson定律

這裏,咱們都以S(n)表示n核系統對具體程序的加速比,K表示串行部分計算時間比例。

Amdahl 定律的加速比:S(n) = 使用1個處理器的串行計算時間 / 使用n個處理器的並行計算時間python

S(n) = 1/(K+(1-K)/n) = n/(1+(n-1)K)mysql

Gustafson定律的加速比:S(n) = 使用n個處理器的並行計算量 / 使用1個處理器的串行計算量c++

S(n) = K+(1-K)n 
有點冷是否是?

通俗的講,Amdahl 定律將工做量看做1,有n核也只能分擔1-K的工做量;而Gustafson定律則將單核工做量看做1,有n核,就能夠增長n(1-K)的工做量。

這裏沒有考慮引進分佈式帶來的開銷,好比網絡和加鎖。成本仍是要仔細覈算的,不是越分佈越好。

控制算法的複雜性在常數範圍以內。

git

萬兆以太網

 

手段篇

一致性哈希

要求分佈式架構的發展提及。

第一階段
考慮到單服務器不能承載,所以使用了分佈式架構,最初的算法爲 hash() mod n, hash()一般取用戶ID,n爲節點數。此方法容易實現且可以知足運營要求。缺點是當單點發生故障時,系統沒法自動恢復。

 

NoSQL數據庫



第二階段
爲了解決單點故障,使用 hash() mod (n/2), 這樣任意一個用戶都有2個服務器備選,可由client隨機選取。因爲不一樣服務器之間的用戶須要彼此交互,因此全部的服務器須要確切的知道用戶所在的位置。所以用戶位置被保存到memcached中。

當一臺發生故障,client能夠自動切換到對應backup,因爲切換前另外1臺沒有用戶的session,所以須要client自行從新登陸。
github

 

NoSQL數據庫



這個階段的設計存在如下問題
負載不均衡,尤爲是單臺發生故障後剩下一臺會壓力過大。
不能動態增刪節點
節點發生故障時須要client從新登陸

第三階段
打算去掉硬編碼的hash() mod n 算法,改用一致性哈希(consistent hashing)分佈
假如採用Dynamo中的strategy 1
咱們把每臺server分紅v個虛擬節點,再把全部虛擬節點(n*v)隨機分配到一致性哈希的圓環上,這樣全部的用戶從本身圓環上的位置順時針往下取到第一個vnode就是本身所屬節點。當此節點存在故障時,再順時針取下一個做爲替代節點。

 

 

 

NoSQL數據庫

優勢:發生單點故障時負載會均衡分散到其餘全部節點,程序實現也比較優雅。

 

亞馬遜的現狀

aw2.0公司的Alan Williamson撰寫了一篇報道,主要是關於他在Amazon EC2上的體驗的,他抱怨說,Amazon是公司惟一使用的雲提供商,看起來它在開始時可以適應得很好,可是有一個臨界點

在開始的日子裏Amazon的表現很是棒。實例在幾分鐘內啓動,幾乎沒有遇到任何問題,即使是他們的 小實例(SMALL INSTANCE)也很健壯,足以支持適當使用的MySQL數據庫。在20個月內,Amazon雲系統一切運轉良好,不須要任何的關心和抱怨。

……

然而,在最後的八個月左右,他們「盔甲」內的漏洞開始呈現出來了。第一個弱點前兆是,新加入的Amazon SMALL實例的性能出現了問題。根據咱們的監控,在服務器場中新添加的機器,與原先的那些相比性能有所降低。開始咱們認爲這是天然出現的怪現象,只是碰 巧發生在「吵鬧的鄰居」(Noisy Neighbors)旁邊。根據隨機法則,一次快速的停機和從新啓動常常就會讓咱們回到「安靜的鄰居」旁邊,那樣咱們能夠達到目的。

…… 然而,在最後的一兩個月中,咱們發現,甚至是這些「使用高級CPU的中等實例」也遭受了與小實例相同的命運,其中,新的實例無論處於什麼位置,看起來彷佛都表現得同樣。通過調查,咱們還發現了一個新問題,它已經悄悄滲透到到Amazon的世界中,那就是內部網絡延遲。


算法的選擇

不一樣的哈希算法能夠致使數據分佈的不一樣位置,若是十分均勻,那麼一次MapReduce就涉及節點較多,但熱點均勻,方便管理。反之,熱點不均,會大體機器效率發揮不徹底。


Quorum NRW


NoSQL數據庫

  • N: 複製的節點數量
  • R: 成功讀操做的最小節點數
  • W: 成功寫操做的最小節點數

只需W + R > N,就能夠保證強一致性。

第一個關鍵參數是 N,這個 N 指的是數據對象將被複制到 N 臺主機上,N 在實例級別配置,協調器將負責把數據複製到 N-1 個節點上。N 的典型值設置爲 3.

復 制中的一致性,採用相似於 Quorum 系統的一致性協議實現。這個協議有兩個關鍵值:R 與 W。R 表明一次成功的讀取操做中最小參與節點數量,W 表明一次成功的寫操做中最小參與節點數量。R + W>N ,則會產生相似 quorum 的效果。該模型中的讀(寫)延遲由最慢的 R(W)複製決定,爲獲得比較小的延遲,R 和 W 有的時候的和又設置比 N 小。

若是N中的1臺發生故障,Dynamo當即寫入到preference list中下一臺,確保永遠可寫入

如 果W+R>N,那麼分佈式系統就會提供強一致性的保證,由於讀取數據的節點和被同步寫入的節點是有重疊的。在一個RDBMS的複製模型中 (Master/salve),假如N=2,那麼W=2,R=1此時是一種強一致性,可是這樣形成的問題就是可用性的減低,由於要想寫操做成功,必需要等 2個節點都完成之後才能夠。

在分佈式系統中,通常都要有容錯性,所以通常N都是大於3的,此時根據CAP理論,一致性,可用性和分區容錯 性最多隻能知足兩個,那麼咱們就須要在一致性和分區容錯性之間作一平衡,若是要高的一致性,那麼就配置N=W,R=1,這個時候可用性就會大大下降。若是 想要高的可用性,那麼此時就須要放鬆一致性的要求,此時能夠配置W=1,這樣使得寫操做延遲最低,同時經過異步的機制更新剩餘的N-W個節點。

當存儲系統保證最終一致性時,存儲系統的配置通常是W+R<=N,此時讀取和寫入操做是不重疊的,不一致性的窗口就依賴於存儲系統的異步實現方式,不一致性的窗口大小也就等於從更新開始到全部的節點都異步更新完成之間的時間。

(N,R,W) 的值典型設置爲 (3, 2 ,2),兼顧性能與可用性。R 和 W 直接影響性能、擴展性、一致性,若是 W 設置 爲 1,則一個實例中只要有一個節點可用,也不會影響寫操做,若是 R 設置爲 1 ,只要有一個節點可用,也不會影響讀請求,R 和 W 值太小則影響一致性,過大也很差,這兩個值要平衡。對於這套系統的典型的 SLA 要求 99.9% 的讀寫操做在 300ms 內完成。

無 論是Read-your-writes-consistency,Session consistency,Monotonic read consistency,它們都經過黏貼(stickiness)客戶端到執行分佈式請求的服務器端來實現的,這種方式簡單是簡單,可是它使得負載均衡以 及分區容錯變的更加難於管理,有時候也能夠經過客戶端來實現Read-your-writes-consistency和Monotonic read consistency,此時須要對寫的操做的數據加版本號,這樣客戶端就能夠遺棄版本號小於最近看到的版本號的數據。

在系統開發過程 中,根據CAP理論,可用性和一致性在一個大型分區容錯的系統中只能知足一個,所以爲了高可用性,咱們必須放低一致性的要求,可是不一樣的系統保證的一致性 仍是有差異的,這就要求開發者要清楚本身用的系統提供什麼樣子的最終一致性的保證,一個很是流行的例子就是web應用系統,在大多數的web應用系統中都 有「用戶可感知一致性」的概念,這也就是說最終一致性中的「一致性窗口"大小要小於用戶下一次的請求,在下次讀取操做來以前,數據能夠在存儲的各個節點之 間複製。還好比假如存儲系統提供了

read-your-write-consistency一致性,那麼當一個用戶寫操做完成之後能夠立馬看到本身的更 新,可是其它的用戶要過一會才能夠看到更新。

幾種特殊狀況:
W = 1, R = N,對寫操做要求高性能高可用。
R = 1, W = N , 對讀操做要求高性能高可用,好比相似cache之類業務。
W = Q, R = Q where Q = N / 2 + 1 通常應用適用,讀寫性能之間取得平衡。如N=3,W=2,R=2

Vector clock



NoSQL數據庫


vector clock算法。能夠把這個vector clock想象成每一個節點都記錄本身的版本信息,而一個數據,包含全部這些版本信息。來看一個例子:假設一個寫請求,第一次被節點A處理了。節點A會增長一個版本信息(A,1)。咱們把這個時候的數據記作D1(A,1)。 而後另一個對一樣key(這一段討論都是針對一樣的key的)的請求仍是被A處理了因而有D2(A,2)。

這個時候,D2是能夠覆蓋D1的,不會有衝突產生。如今咱們假設D2傳播到了全部節點(B和C),B和C收到的數據不是從客戶產生的,而是別人複製給他們的,因此他們不產生新的版本信息,因此如今B和C都持有數據D2(A,2)。好,繼續,又一個請求,被B處理了,生成數據D3(A,2;B,1),由於這是一個新版本的數據,被B處理,因此要增長B的版本信息。

假設D3沒有傳播到C的時候又一個請求被C處理記作D4(A,2;C,1)。假設在這些版本沒有傳播開來之前,有一個讀取操做,咱們要記得,咱們的W=1 那麼R=N=3,因此R會從全部三個節點上讀,在這個例子中將讀到三個版本。A上的D2(A,2);B上的D3(A,2;B,1);C上的D4(A,2;C,1)這個時候能夠判斷出,D2已是舊版本,能夠捨棄,可是D3和D4都是新版本,須要應用本身去合併。

若是須要高可寫性,就要處理這種合併問題。好假設應用完成了衝入解決,這裏就是合併D3和D4版本,而後從新作了寫入,假設是B處理這個請求,因而有D5(A,2;B,2;C,1);這個版本將能夠覆蓋掉D1-D4那四個版本。這個例子只舉了一個客戶的請求在被不一樣節點處理時候的狀況, 並且每次寫更新都是可接受的,你們能夠本身更深刻的演算一下幾個併發客戶的狀況,以及用一箇舊版本作更新的狀況。

上面問題看似好像能夠經過在三個節點裏選擇一個主節點來解決,全部的讀取和寫入都從主節點來進行。可是這樣就違背了W=1這個約定,實際上仍是退化到W=N的狀況了。因此若是系統不須要很大的彈性,W=N爲全部應用都接受,那麼系統的設計上能夠獲得很大的簡化。Dynamo 爲了給出充分的彈性而被設計成徹底的對等集羣(peer to peer),網絡中的任何一個節點都不是特殊的。

Virtual node


NoSQL數據庫
虛擬節點,未完成

gossip


Gossip協議是一個Gossip思想的P2P實現。現代的分佈式系統常用這個協議,他每每是惟一的手段。由於底層的結構很是複雜,並且Gossip也頗有效。

Gossip協議也被戲稱爲病毒式傳播,由於他的行爲生物界的病毒很類似。

Gossip (State Transfer Model)

在狀態轉移到模式下,每一個重複節點都保持的一個Vector clock和一個state version tree。每一個節點的狀態都是相同的(based on vector clock comparison),換句話說,state version tree包含有所有的衝突updates.

At query time, the client will attach its vector clock and the replica will send back a subset of the state tree which precedes the client's vector clock (this will provide monotonic read consistency). The client will then advance its vector clock by merging all the versions. This means the client is responsible to resolve the conflict of all these versions because when the client sends the update later, its vector clock will precede all these versions.
NoSQL數據庫

At update, the client will send its vector clock and the replica will check whether the client state precedes any of its existing version, if so, it will throw away the client's update.
 
NoSQL數據庫

Replicas also gossip among each other in the background and try to merge their version tree together.


NoSQL數據庫

Gossip (Operation Transfer Model)


In an operation transfer approach, the sequence of applying the operations is very important. At the minimum causal order need to be maintained. Because of the ordering issue, each replica has to defer executing the operation until all the preceding operations has been executed. Therefore replicas save the operation request to a log file and exchange the log among each other and consolidate these operation logs to figure out the right sequence to apply the operations to their local store in an appropriate order.

"Causal order" means every replica will apply changes to the "causes" before apply changes to the "effect". "Total order" requires that every replica applies the operation in the same sequence.

In this model, each replica keeps a list of vector clock, Vi is the vector clock the replica itself and Vj is the vector clock when replica i receive replica j's gossip message. There is also a V-state that represent the vector clock of the last updated state.

When a query is submitted by the client, it will also send along its vector clock which reflect the client's view of the world. The replica will check if it has a view of the state that is later than the client's view.

NoSQL數據庫


When an update operation is received, the replica will buffer the update operation until it can be applied to the local state. Every submitted operation will be tag with 2 timestamp, V-client indicates the client's view when he is making the update request. V-@receive is the replica's view when it receives the submission.

This update operation request will be sitting in the queue until the replica has received all the other updates that this one depends on. This condition is reflected in the vector clock Vi when it is larger than V-client

NoSQL數據庫


On the background, different replicas exchange their log for the queued updates and update each other's vector clock. After the log exchange, each replica will check whether certain operation can be applied (when all the dependent operation has been received) and apply them accordingly. Notice that it is possible that multiple operations are ready for applying at the same time, the replica will sort these operation in causal order (by using the Vector clock comparison) and apply them in the right order.

NoSQL數據庫


The concurrent update problem at different replica can also happen. Which means there can be multiple valid sequences of operation. In order for different replica to apply concurrent update in the same order, we need a total ordering mechanism.

One approach is whoever do the update first acquire a monotonic sequence number and late comers follow the sequence. On the other hand, if the operation itself is commutative, then the order to apply the operations doesn't matter

After applying the update, the update operation cannot be immediately removed from the queue because the update may not be fully exchange to every replica yet. We continuously check the Vector clock of each replicas after log exchange and after we confirm than everyone has receive this update, then we'll remove it from the queue.

Merkle tree

有數據存儲成樹狀結構,每一個節點的Hash是其全部子節點的Hash的Hash,葉子節點的Hash是其內容的Hash。這樣一旦某個節點發生變化,其Hash的變化會迅速傳播到根節點。須要同步的系統只須要不斷查詢跟節點的hash,一旦有變化,順着樹狀結構就可以在logN級別的時間找到發生變化的內容,立刻同步。

Paxos

paxos是一種處理一致性的手段,能夠理解爲事務吧。
其餘的手段不要Google GFS使用的Chubby的Lock service。我不大喜歡那種重型的設計就不費筆墨了。

背景

當規模愈來愈大的時候。

1、Master/slave

這個是多機房數據訪問最經常使用的方案,通常的需求用此方案便可。所以你們也常常提到「premature optimization is the root of all evil」。
優勢:利用mysql replication便可實現,成熟穩定。
缺點:寫操做存在單點故障,master壞掉以後slave不能寫。另外slave的延遲也是個困擾人的小問題。

2、Multi-master

Multi-master指一個系統存在多個master, 每一個master都具備read-write能力,需根據時間戳或業務邏輯合併版本。好比分佈式版本管理系統git能夠理解成multi-master模式。具有最終一致性。多版本數據修改能夠借鑑Dynamo的vector clock等方法。

優勢:解決了單點故障。
缺點:不易實現一致性,合併版本的邏輯複雜。

3、Two-phase commit(2PC)

Two-phase commit是一個比較簡單的一致性算法。因爲一致性算法一般用神話(如Paxos的The Part-Time Parliament論文)來比喻容易理解,下面也舉個相似神話的例子。

某班要組織一個同窗聚會,前提條件是全部參與者贊成則活動舉行,任意一人拒絕則活動取消。用2PC算法來執行過程以下

Phase 1

Prepare: 組織者(coordinator)打電話給全部參與者(participant) ,同時告知參與者列表。
Proposal: 提出週六2pm-5pm舉辦活動。
Vote: participant需vote結果給coordinator:accept or reject。
Block: 若是accept, participant鎖住週六2pm-5pm的時間,再也不接受其餘請求。
Phase 2

Commit: 若是全部參與者都贊成,組織者coodinator通知全部參與者commit, 不然通知abort,participant解除鎖定。
Failure 典型失敗狀況分析

Participant failure:
任一參與者無響應,coordinator直接執行abort
Coordinator failure:
Takeover: 若是participant一段時間沒收到cooridnator確認(commit/abort),則認爲coordinator不在了。這時候可自動成爲Coordinator備份(watchdog)
Query: watchdog根據phase 1接收的participant列表發起query
Vote: 全部participant回覆vote結果給watchdog, accept or reject
Commit: 若是全部都贊成,則commit, 不然abort。

優勢:實現簡單。
缺點:全部參與者須要阻塞(block),throughput低;無容錯機制,一節點失敗則整個事務失敗。

4、Three-phase commit (3PC)

Three-phase commit是一個2PC的改進版。2PC有一些很明顯的缺點,好比在coordinator作出commit決策並開始發送commit以後,某個participant忽然crash,這時候無法abort transaction, 這時候集羣內實際上就存在不一致的狀況,crash恢復後的節點跟其餘節點數據是不一樣的。所以3PC將2PC的commit的過程1分爲2,分紅preCommit及commit, 如圖。

 

NoSQL數據庫



(圖片來源:http://en.wikipedia.org/wiki/File:Three-phase_commit_diagram.png)

從圖來看,cohorts(participant)收到preCommit以後,若是沒收到commit, 默認也執行commit, 即圖上的timeout cause commit。

若是coodinator發送了一半preCommit crash, watchdog接管以後經過query, 若是有任一節點收到commit, 或者所有節點收到preCommit, 則可繼續commit, 不然abort。

優勢:容許發生單點故障後繼續達成一致。
缺點:網絡分離問題,好比preCommit消息發送後忽然兩個機房斷開,這時候coodinator所在機房會abort, 另外剩餘replicas機房會commit。


Google Chubby的做者Mike Burrows說過, 「there is only one consensus protocol, and that’s Paxos」 – all other approaches are just broken versions of Paxos. 意即「世上只有一種一致性算法,那就是Paxos」,全部其餘一致性算法都是Paxos算法的不完整版。相比2PC/3PC, Paxos算法的改進
P1a. 每次Paxos實例執行都分配一個編號,編號須要遞增,每一個replica不接受比當前最大編號小的提案
P2. 一旦一個 value v 被replica經過,那麼以後任何再批准的 value 必須是 v,即沒有拜占庭將軍(Byzantine)問題。拿上面請客的比喻來講,就是一個參與者一旦accept週六2pm-5pm的proposal, 就不能改變主意。之後無論誰來問都是accept這個value。
一個proposal只須要多數派贊成便可經過。所以比2PC/3PC更靈活,在一個2f+1個節點的集羣中,容許有f個節點不可用。

另外Paxos還有不少約束的細節,特別是Google的chubby從工程實現的角度將Paxos的細節補充得很是完整。好比如何避免Byzantine問題,因爲節點的持久存儲可能會發生故障,Byzantine問題會致使Paxos算法P2約束失效。

以上幾種方式原理比較以下


DHT


Distributed hash table


Map Reduce Execution

Map Reduce已經爛大街了,不過仍是要提一下。
參見:http://zh.wikipedia.org/wiki/MapReduce



Handling Deletes

但咱們執行刪除操做的時候必須很是謹慎,以防丟失掉相應的版本信息。

一般咱們給一個Object標註上"已刪除"的標籤。在足夠的時間以後,咱們在確保版本一致的狀況下能夠將它完全刪除。回收他的空間。


存儲實現

One strategy is to use make the storage implementation pluggable. e.g. A local MySQL DB, Berkeley DB, Filesystem or even a in memory Hashtable can be used as a storage mechanism.

Another strategy is to implement the storage in a highly scalable way. Here are some techniques that I learn from CouchDB and Google BigTable.

CouchDB has a MVCC model that uses a copy-on-modified approach. Any update will cause a private copy being made which in turn cause the index also need to be modified and causing the a private copy of the index as well, all the way up to the root pointer.

Notice that the update happens in an append-only mode where the modified data is appended to the file and the old data becomes garbage. Periodic garbage collection is done to compact the data. Here is how the model is implemented in memory and disks


In Google BigTable model, the data is broken down into multiple generations and the memory is use to hold the newest generation. Any query will search the mem data as well as all the data sets on disks and merge all the return results. Fast detection of whether a generation contains a key can be done by checking a bloom filter.



When update happens, both the mem data and the commit log will be written so that if the

節點變化


Notice that virtual nodes can join and leave the network at any time without impacting the operation of the ring.

When a new node joins the network
  1. 新加入的節點宣告本身的存在(廣播或者其餘手段)
  2. 他的鄰居節點要調整Key的分配和複製關係。這個操做一般是同步的
  3. 這個新加入的節點異步的拷貝數據
  4. 這個節點變化的操做被髮布到其餘節點


Notice that other nodes may not have their membership view updated yet so they may still forward the request to the old nodes. But since these old nodes (which is the neighbor of the new joined node) has been updated (in step 2), so they will forward the request to the new joined node.

On the other hand, the new joined node may still in the process of downloading the data and not ready to serve yet. We use the vector clock (described below) to determine whether the new joined node is ready to serve the request and if not, the client can contact another replica.

When an existing node leaves the network (e.g. crash)
  1. The crashed node no longer respond to gossip message so its neighbors knows about it.崩潰的節點再也不發送Gossip Message的迴應,因此他的鄰居都知道他是了
  2. The neighbor will update the membership changes and copy data asynchronously,他的鄰居處理後事,將他的活分給別人幹,同時調整節點關係。


We haven't talked about how the virtual nodes is mapped into the physical nodes. Many schemes are possible with the main goal that Virtual Node replicas should not be sitting on the same physical node. One simple scheme is to assigned Virtual node to Physical node in a random manner but check to make sure that a physical node doesn't contain replicas of the same key ranges.

Notice that since machine crashes happen at the physical node level, which has many virtual nodes runs on it. So when a single Physical node crashes, the workload (of its multiple virtual node) is scattered across many physical machines. Therefore the increased workload due to physical node crashes is evenly balanced.

列存

描述

數據庫以行、列的二維表的形式存儲數據,可是卻以一維字符串的方式存儲,例如如下的一個表:

 

EmpId Lastname Firstname Salary
1 Smith Joe 40000
2 Jones Mary 50000
3 Johnson Cathy 44000


這個簡單的表包括員工代碼(EmpId), 姓名字段(Lastname and Firstname)及工資(Salary).

這個表存儲在電腦的內存(RAM)和存儲(硬盤)中。雖然內存和硬盤在機制上不一樣,電腦的操做系統是以一樣的方式存儲的。數據庫必須把這個二維表存儲在一系列一維的「字節」中,又操做系統寫到內存或硬盤中。

行式數據庫把一行中的數據值串在一塊兒存儲起來,而後再存儲下一行的數據,以此類推。1,Smith,Joe,40000;2,Jones,Mary,50000;3,Johnson,Cathy,44000;

列式數據庫把一列中的數據值串在一塊兒存儲起來,而後再存儲下一列的數據,以此類推。1,2,3;Smith,Jones,Johnson;Joe,Mary,Cathy;40000,50000,44000;


特色

  • 良好的壓縮比。因爲大多數數據庫設計都有冗餘,如此一來,壓縮比很是高,把40多M的數據導入infobright,沒想到數據文件只有1M多
  • 列上的計算很是的快。
  • 方便MapReduce和Key-value模型的融合
  • 讀取整行的數據較慢,但部分數據較快

簡單分析含源碼

 

軟件篇

亞數據庫

我發明的新概念,就是稱不上數據庫但有一些數據庫的特徵。能夠指緩存。

MemCached

Memcached是danga.com(運營LiveJournal的技術團隊)開發的一套分佈式內存對象緩存系統,用於在動態系統中減小數據庫 負載,提高性能。

特色

  • 協議簡單
  • 基於libevent的事件處理
  • 內置內存存儲方式
  • memcached不互相通訊的分佈式



Memcached處理的原子是每個(key,value)對(如下簡稱kv對),key會經過一個hash算法轉化成hash-key,便於查找、對比以及作到儘量的散列。同時,memcached用的是一個二級散列,經過一張大hash表來維護。

Memcached有兩個核心組件組成:服務端(ms)和客戶端(mc),在一個memcached的查詢中,mc先經過計算key的hash值來 肯定kv對所處在的ms位置。當ms肯定後,客戶端就會發送一個查詢請求給對應的ms,讓它來查找確切的數據。由於這之間沒有交互以及多播協議,因此 memcached交互帶給網絡的影響是最小化的。


內存分配

默認狀況下,ms是用一個內置的叫「塊分配器」的組件來分配內存的。捨棄c++標準的malloc/free的內存分配,而採用塊分配器的主要目的 是爲了不內存碎片,不然操做系統要花費更多時間來查找這些邏輯上連續的內存塊(其實是斷開的)。用了塊分配器,ms會輪流的對內存進行大塊的分配,並 不斷重用。固然因爲塊的大小各不相同,當數據大小和塊大小不太相符的狀況下,仍是有可能致使內存的浪費。

同時,ms對key和data都有相應的限制,key的長度不能超過250字節,data也不能超過塊大小的限制 --- 1MB。
由於mc所使用的hash算法,並不會考慮到每一個ms的內存大小。理論上mc會分配機率上等量的kv對給每一個ms,這樣若是每一個ms的內存都不太同樣,那 可能會致使內存使用率的下降。因此一種替代的解決方案是,根據每一個ms的內存大小,找出他們的最大公約數,而後在每一個ms上開n個容量=最大公約數的 instance,這樣就等於擁有了多個容量大小同樣的子ms,從而提供總體的內存使用率。

緩存策略

當ms的hash表滿了以後,新的插入數據會替代老的數據,更新的策略是LRU(最近最少使用),以及每一個kv對的有效時限。Kv對存儲有效時限是在mc端由app設置並做爲參數傳給ms的。

同時ms採用是偷懶替代法,ms不會開額外的進程來實時監測過期的kv對並刪除,而是當且僅當,新來一個插入的數據,而此時又沒有多餘的空間放了,纔會進行清除動做。

緩存數據庫查詢

如今memcached最流行的一種使用方式是緩存數據庫查詢,下面舉一個簡單例子說明:

App須要獲得userid=xxx的用戶信息,對應的查詢語句相似:

「SELECT * FROM users WHERE userid = xxx」

App先去問cache,有沒有「user:userid」(key定義可預先定義約束好)的數據,若是有,返回數據;若是沒有,App會從數據庫中讀取數據,並調用cache的add函數,把數據加入cache中。

當取的數據須要更新,app會調用cache的update函數,來保持數據庫與cache的數據同步。

從上面的例子咱們也能夠發現,一旦數據庫的數據發現變化,咱們必定要及時更新cache中的數據,來保證app讀到的是同步的正確數據。固然咱們可 以經過定時器方式記錄下cache中數據的失效時間,時間一過就會激發事件對cache進行更新,但這之間總會有時間上的延遲,致使app可能從 cache讀到髒數據,這也被稱爲狗洞問題。(之後我會專門描述研究這個問題)

數據冗餘與故障預防

從設計角度上,memcached是沒有數據冗餘環節的,它自己就是一個大規模的高性能cache層,加入數據冗餘所能帶來的只有設計的複雜性和提升系統的開支。

當一個ms上丟失了數據以後,app仍是能夠從數據庫中取得數據。不過更謹慎的作法是在某些ms不能正常工做時,提供額外的ms來支持cache,這樣就不會由於app從cache中取不到數據而一會兒給數據庫帶來過大的負載。

同時爲了減小某臺ms故障所帶來的影響,能夠使用「熱備份」方案,就是用一臺新的ms來取代有問題的ms,固然新的ms仍是要用原來ms的IP地址,大不了數據從新裝載一遍。

另一種方式,就是提升你ms的節點數,而後mc會實時偵查每一個節點的狀態,若是發現某個節點長時間沒有響應,就會從mc的可用server列表裏 刪除,並對server節點進行從新hash定位。固然這樣也會形成的問題是,本來key存儲在B上,變成存儲在C上了。因此此方案自己也有其弱點,最好 能和「熱備份」方案結合使用,就能夠使故障形成的影響最小化。

Memcached客戶端(mc)

 

Memcached客戶端有各類語言的版本供你們使用,包括java,c,php,.net等等,具體可參見memcached api page [2]。
你們能夠根據本身項目的須要,選擇合適的客戶端來集成。

緩存式的Web應用程序架構

有了緩存的支持,咱們能夠在傳統的app層和db層之間加入cache層,每一個app服務器均可以綁定一個mc,每次數據的讀取均可以從ms中取得,若是 沒有,再從db層讀取。而當數據要進行更新時,除了要發送update的sql給db層,同時也要將更新的數據發給mc,讓mc去更新ms中的數據。 

性能測試

Memcached 寫速度
平均速度: 16222 次/秒
最大速度 18799 次/秒

Memcached 讀速度
平均速度: 20971 次/秒
最大速度 22497 次/秒

Memcachedb 寫速度
平均速度: 8958 次/秒
最大速度 10480 次/秒

Memcachedb 讀速度
平均速度: 6871 次/秒
最大速度 12542 次/秒

 

 

 

源代碼級別的分析
很是好的剖析文章

dbcached



● dbcached 是一款基於 Memcached 和 NMDB 的分佈式 key-value 數據庫內存緩存系統。
● dbcached = Memcached + 持久化存儲管理器 + NMDB 客戶端接口
● Memcached 是一款高性能的,分佈式的內存對象緩存系統,用於在動態應用中減小數據庫負載,提高訪問速度。
● NMDB 是一款多協議網絡數據庫(dbm類)管理器,它由內存緩存和磁盤存儲兩部分構成,使用 QDBM 或 Berkeley DB 做爲後端數據庫。
● QDBM 是一個管理數據庫的例程庫,它參照 GDBM 爲了下述三點而被開發:更高的處理速度,更小的數據庫文件大小,和更簡單的API。QDBM 讀寫速度比 Berkeley DB 要快,詳細速度比較見《 Report of Benchmark Test》。


Memcached 和 dbcached 在功能上同樣嗎?

● 兼容:Memcached 能作的,dbcached 都能作。除此以外,dbcached 還將「Memcached、持久化存儲管理器、NMDB 客戶端接口」在一個程序中結合起來,對任何原有 Memcached 客戶端來說,dbcached 仍舊是個 Memcached 內存對象緩存系統,可是,它的數據能夠持久存儲到本機或其它服務器上的 QDBM 或 Berkeley DB 數據庫中。
● 性能:前端 dbcached 的併發處理能力跟 Memcached 相同;後端 NMDB 跟 Memcached 同樣,採用了libevent 進行網絡IO處理,擁有本身的內存緩存機制,性能不相上下。
● 寫入:當「dbcached 的 Memcached 部分」接收到一個 set(add/replace/...) 請求並儲存 key-value 數據到內存中後,「dbcached 持久化存儲管理器」可以將 key-value 數據經過「NMDB 客戶端接口」保存到 QDBM 或 Berkeley DB 數據庫中。
● 速度:若是加上「-z」參數,採用 UDP 協議「只發送不接收」模式將 set(add/replace/...) 命令寫入的數據傳遞給 NMDB 服務器端,對 Memcache 客戶端寫速度的影響幾乎能夠忽略不計。在千兆網卡、同一交換機下服務器之間的 UDP 傳輸丟包率微乎其微。在命中的狀況下,讀取數據的速度跟普通的 Memcached 無差異,速度同樣快。
● 讀取:當「dbcached 的 Memcached 部分」接收到一個 get(incr/decr/...) 請求後,若是「dbcached 的 Memcached 部分」查詢自身的內存緩存未命中,則「dbcached 持久化存儲管理器」會經過「NMDB 客戶端接口」從 QDBM 或 Berkeley DB 數據庫中取出數據,返回給用戶,而後儲存到 Memcached 內存中。若是有用戶再次請求這個 key,則會直接從 Memcached 內存中返回 Value 值。
● 持久:使用 dbcached,不用擔憂 Memcached 服務器死機、重啓而致使數據丟失。
● 變動:使用 dbcached,即便由於故障轉移,添加、減小 Memcached 服務器節點而破壞了「key 信息」與對應「Memcached 服務器」的映射關係也不怕。
● 分佈:dbcached 和 NMDB 既能夠安裝在同一臺服務器上,也能夠安裝在不一樣的服務器上,多臺 dbcached 服務器能夠對應一臺 NMDB 服務器。
● 特長:dbcached 對於「讀」大於「寫」的應用尤爲適用。
● 其餘:《 dbcached 的故障轉移支持、設計方向以及與 Memcachedb 的不一樣之處

列存系列

Hadoop之Hbase

Hadoop / HBase: API: Java / any writer, Protocol: any write call, Query Method: MapReduce Java / any exec, Replication: HDFS Replication, Written in: Java, Concurrency: ?, Misc: Links: 3 Books [ 123]

耶魯大學之HadoopDB


GreenPlum



FaceBook之Cassandra


Cassandra: API: many Thrift » languages, Protocol: ?, Query Method: MapReduce, Replicaton: , Written in: Java, Concurrency: eventually consistent , Misc: like "Big-Table on Amazon Dynamo alike",  initiated by Facebook, Slides » , Clients »

Cassandra是facebook開源出來的一個版本,能夠認爲是BigTable的一個開源版本,目前twitter和digg.com在使用。

Cassandra特色


  • 靈活的schema,不須要象數據庫同樣預先設計schema,增長或者刪除字段很是方便(on the fly)。
  • 支持range查詢:能夠對Key進行範圍查詢。
  • 高可用,可擴展:單點故障不影響集羣服務,可線性擴展。

Cassandra的主要特色就是它不是一個數據庫,而是由一堆數據庫節點共同構成的一個分佈式網絡服務,對Cassandra的一個寫操做,會 被複制到其餘節點上去,對Cassandra的讀操做,也會被路由到某個節點上面去讀取。對於一個Cassandra羣集來講,擴展性能是比較簡單的事 情,只管在羣集裏面添加節點就能夠了。我看到有文章說Facebook的Cassandra羣集有超過100臺服務器構成的數據庫羣集。

Cassandra也支持比較豐富的數據結構和功能強大的查詢語言,和MongoDB比較相似,查詢功能比MongoDB稍弱一些,twitter的平臺架構部門領導Evan Weaver寫了一篇文章介紹Cassandra: http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有很是詳細的介紹。

Cassandra以單個節點來衡量,其節點的併發讀寫性能不是特別好,有文章說評測下來Cassandra每秒大約不到1萬次讀寫請求,我也看 到一些對這個問題進行質疑的評論,可是評價Cassandra單個節點的性能是沒有意義的,真實的分佈式數據庫訪問系統必然是n多個節點構成的系統,其並 發性能取決於整個系統的節點數量,路由效率,而不只僅是單節點的併發負載能力。

Keyspace

Cassandra中的最大組織單元,裏面包含了一系列Column family,Keyspace通常是應用程序的名稱。你能夠把它理解爲Oracle裏面的一個schema,包含了一系列的對象。

Column family(CF)

CF是某個特定Key的數據集合,每一個CF物理上被存放在單獨的文件中。從概念上看,CF有點象數據庫中的Table.

Key

數據必須經過Key來訪問,Cassandra容許範圍查詢,例如:start => '10050', :finish => '10070'

Column

在Cassandra中字段是最小的數據單元,column和value構成一個對,好比:name:「jacky」,column是name,value是jacky,每一個column:value後都有一個時間戳:timestamp。

和數據庫不一樣的是,Cassandra的一行中能夠有任意多個column,並且每行的column能夠是不一樣的。從數據庫設計的角度,你能夠理解 爲表上有兩個字段,第一個是Key,第二個是長文本類型,用來存放不少的column。這也是爲何說Cassandra具有很是靈活schema的原 因。

Super column

Super column是一種特殊的column,裏面能夠存聽任意多個普通的column。並且一個CF中一樣能夠有任意多個Super column,一個CF只能定義使用Column或者Super column,不能混用。下面是Super column的一個例子,homeAddress這個Super column有三個字段:分別是street,city和zip: homeAddress: {street: "binjiang road",city: "hangzhou",zip: "310052",}

Sorting

不一樣於數據庫能夠經過Order by定義排序規則,Cassandra取出的數據順序是老是必定的,數據保存時已經按照定義的規則存放,因此取出來的順序已經肯定了,這是一個巨大的性能優點。有意思的是,Cassandra按照column name而不是column value來進行排序,它 定義瞭如下幾種選項:BytesType, UTF8Type, LexicalUUIDType, TimeUUIDType, AsciiType, 和LongType,用來定義如何按照column name來排序。實際上,就是把column name識別成爲不一樣的類型,以此來達到靈活排序的目的。UTF8Type是把column name轉換爲UTF8編碼來進行排序,LongType轉換成爲64位long型,TimeUUIDType是按照基於時間的UUID來排序。例如:

Column name按照LongType排序:
{name: 3, value: "jacky"},
{name: 123, value: "hellodba"},
{name: 976, value: "Cassandra"},
{name: 832416, value: "bigtable"}

Column name按照UTF8Type排序:
{name: 123, value: "hellodba"},
{name: 3, value: "jacky"},
{name: 832416, value: "bigtable"}
{name: 976, value: "Cassandra"}

下面咱們看twitter的Schema:
<Keyspace Name="Twitter">
<ColumnFamily CompareWith="UTF8Type" Name="Statuses" />
<ColumnFamily CompareWith="UTF8Type" Name="StatusAudits" />
<ColumnFamily CompareWith="UTF8Type" Name="StatusRelationships"
CompareSubcolumnsWith="TimeUUIDType" ColumnType="Super" />
<ColumnFamily CompareWith="UTF8Type" Name="Users" />
<ColumnFamily CompareWith="UTF8Type" Name="UserRelationships"
CompareSubcolumnsWith="TimeUUIDType" ColumnType="Super" />
</Keyspace>

咱們看到一個叫Twitter的keyspace,包含若干個CF,其中StatusRelationships和 UserRelationships被定義爲包含Super column的CF,CompareWith定義了column的排序規則,CompareSubcolumnsWith定義了subcolumn的排序 規則,這裏使用了兩種:TimeUUIDType和UTF8Type。咱們沒有看到任何有關column的定義,這意味着column是能夠靈活變動的。

爲了方便你們理解,我會嘗試着用關係型數據庫的建模方法去描述Twitter的Schema,但千萬不要誤認爲這就是Cassandra的數據模型,對於Cassandra來講,每一行的colunn均可以是任意的,而不是象數據庫同樣須要在建表時就建立好。


Users CF記錄用戶的信息,Statuses CF記錄tweets的內容,StatusRelationships CF記錄用戶看到的tweets,UserRelationships CF記錄用戶看到的followers。咱們注意到排序方式是TimeUUIDType,這個類型是按照時間進行排序的UUID字段,column name是用UUID函數產生(這個函數返回了一個UUID,這個UUID反映了當前的時間,能夠根據這個UUID來排序,有點相似於timestamp 同樣),因此獲得結果是按照時間來排序的。使用過twitter的人都知道,你老是能夠看到本身最新的tweets或者最新的friends.

存儲

Cassandra是基於列存儲的(Bigtable也是同樣),這個和基於列的數據庫是一個道理。


API

下面是數據庫,Bigtable和Cassandra API的對比: Relational SELECT `column` FROM `database`.`table` WHERE `id` = key;
BigTable table.get(key, "column_family:column")
Cassandra: standard model keyspace.get("column_family", key, "column")
Cassandra: super column model keyspace.get("column_family", key, "super_column", "column")

對Cassandra數據模型的理解:

1.column name存放真正的值,而value是空。由於Cassandra是按照column name排序,並且是按列存儲的,因此每每利用column name存放真正的值,而value部分則是空。例如:「jacky」:「null」,「fenng」:」null」

2.Super column能夠看做是一個索引,有點象關係型數據庫中的外鍵,利用super column能夠實現快速定位,由於它能夠返回一堆column,並且是排好序的。

3.排序在定義時就肯定了,取出的數據確定是按照肯定的順序排列的,這是一個巨大的性能優點。

4. 很是靈活的schema,column能夠靈活定義。實際上,colume name在不少狀況下,就是value(是否是有點繞)。

5.每一個column後面的timestamp,我並無找到明確的說明,我猜想多是數據多版本,或者是底層清理數據時須要的信息。

最後說說架構,我認爲架構的核心就是有所取捨,無論是CAP仍是BASE,講的都是這個原則。架構之美在於沒有任何一種架構能夠完美的解決各類問題,數據庫和NoSQL都有其應用場景,咱們要作的就是爲本身找到合適的架構。

Hypertable

Hypertable (can you help?) Open-Source Google BigTable alike.

它是搜索引擎公司Zvents根據Google的9位研究人員在2006年發表的一篇論文《 Bigtable:結構化數據的分佈存儲系統》 開發的一款開源分佈式數據儲存系統。Hypertable是按照1000節點比例設計,以 C++撰寫,可架在 HDFS 和 KFS 上。儘管還在初期階段,但已有不錯的效能:寫入 28M 列的資料,各節點寫入速率可達7MB/s,讀取速率可達 1M cells/s。Hypertable目前一直沒有太多高負載和大存儲的應用實例,可是最近,Hypertable項目獲得了 百度的贊助支持,相信其會有更好的發展。

Google之BigTable

研究Google的產品老是感激Google給了本身那麼多方便,真心喜歡之。

Google AppEngine Datastore 是在BigTable之上建造出來的,是Google的內部存儲系統,用於處理結構化數據。AppEngine Datastore其自身及其內部都不是直接訪問BigTable的實現機制,可被視爲BigTable之上的一個簡單接口。

AppEngine Datastore所支持的項目的數據類型要比SimpleDB豐富得多,也包括了包含在一個項目內的數據集合的列表型。

若是你打算在Google AppEngine以內建造應用的話,幾乎能夠確定要用到這個數據存儲。然而,不像SimpleDB,使用谷歌網絡服務平臺以外的應用,你並不能併發地與AppEngine Datastore進行接口 (或經過BigTable)。

Yahoo之PNUTS

Yahoo!的PNUTS是一個分佈式的數據存儲平臺,它是Yahoo!雲計算平臺重要的一部分。它的上層產品一般也稱爲Sherpa。按照官方的 描述,」PNUTS, a massively parallel and geographically distributed database system for Yahoo!’s web applications.」 PNUTS顯然就深諳CAP之道,考慮到大部分web應用對一致性並不要求很是嚴格,在設計上放棄了對強一致性的追求。代替的是追求更高的 availability,容錯,更快速的響應調用請求等。

特色

  • 地理分佈式,分佈在全球多個數據中心。因爲大部分Web應用都對響應時間要求高,所以最好服務器部署在離用戶最近的本地機房。
  • 可擴展,記錄數可支持從幾萬條到幾億條。數據容量增長不會影響性能。
  • schema-free,即非固定表結構。實際使用key/value存儲的,一條記錄的多個字段實際是用json方式合併存在value中。所以delete和update必須指定primary key。但也支持批量查詢。
  • 高可用性及容錯。從單個存儲節點到整個數據中心不可用都不會影響前端Web訪問。
  • 適合存相對小型的記錄,不適合存儲大文件,流媒體等。
  • 弱一致性保證。

PNUTS實現

Record-level mastering 記錄級別主節點

每一條記錄都有一個主記錄。好比一個印度的用戶保存的記錄master在印度機房,一般修改都會調用印度。其餘地方如美國用戶看這個用戶的資料調用 的是美國數據中心的資料,有可能取到的是舊版的數據。非master機房也可對記錄進行修改,但須要master來統一管理。每行數據都有本身的版本控 制,以下圖所示。


PNUTS的結構

每一個數據中心的PNUTS結構由四部分構成
Storage Units (SU) 存儲單元
物理的存儲服務器,每一個存儲服務器上面含有多個tablets,tablets是PNUTS上的基本存儲單元。一 個tablets是一個yahoo內部格式的hash table的文件(hash table)或是一個MySQL innodb表(ordered table)。一個Tablet一般爲幾百M。一個SU上一般會存在幾百個tablets。
Routers 
每一個tablets在哪一個SU上是經過查詢router得到。一個數據中心內router一般可由兩臺雙機備份的單元提供。

Tablet Controller 
router的位置只是個內存快照,實際的位置由Tablet Controller單元決定。
Message Broker

與遠程數據的同步是由YMB提供,它是一個pub/sub的異步消息訂閱系統。
Tablets尋址與切分
存儲分hash和ordered data store。

以hash爲例介紹,先對全部的tablets按hash值分片,好比1-10,000屬於tablets 1, 10,000到20,000屬於tablets 2,依此類推分配完全部的hash範圍。一個大型的IDC一般會存在100萬如下的tablets, 1,000臺左右的SU。tablets屬於哪一個SU由routers所有加載到內存裏面,所以router訪問速度極快,一般不會成爲瓶頸。按照官方的 說法,系統的瓶頸只存在磁盤文件hash file訪問上。
當某個SU訪問量過大,則可將SU中部分tablets移到相對空閒的SU,並修改tablet controller的偏移記錄。router定位tablet失效以後會自動經過tablet controller從新加載到內存。因此切分也相對容易實現。
Tim也曾經用MySQL實現過相似大規模存儲的系統,當時的作法是把每條記錄的key屬於哪一個SU的信息保存到 一個字典裏面,好處是切分能夠得到更大的靈活性,能夠動態增長新的tablets,而不須要切分舊的tablets。但缺點就是字典無法像router這 樣,能夠高效的所有加載到內存中。因此比較而言,在實際的應用中,按段分片會更簡單,且已經足夠使用。
Write調用示意圖

 

 

PNUTS感悟


2006年Greg Linden就說I want a big, virtual database

What I want is a robust, high performance virtual relational database that runs transparently over a cluster, nodes dropping in an out of service at will, read-write replication and data migration all done automatically.

I want to be able to install a database on a server cloud and use it like it was all running on one machine.

詳細資料:
http://timyang.net/architecture/yahoo-pnuts/

微軟之SQL數據服務

SQL數據服務 是微軟 Azure 網 絡服務平臺的一部分。該SDS服務也是處於測試階段,所以也是免費的,但對數據庫大小有限制。 SQL數據服務其自身其實是一項處在許多SQL服務器之上的應用,這些SQL服務器組成了SDS平臺底層的數據存儲。你不須要訪問到它們,雖然底層的數 據庫多是關係式的;SDS是一個鍵/值型倉儲,正如咱們迄今所討論過的其它平臺同樣。

微軟看起來不一樣於前三個供應商,由於雖然鍵/值存儲對於可擴性���言很是棒,相對於RDBMS,在數據管理上卻很困難。微軟的方案彷佛是入木三分,在實現可擴性和分佈機制的同時,隨着時間的推移,不斷增長特性,在鍵/值存儲和關係數據庫平臺的鴻溝之間搭起一座橋樑。

非雲服務競爭者

在雲以外,也有一些能夠獨立安裝的鍵/值數據庫軟件產品。大部分都還很年輕,不是alpha版就是beta版,但大都是開源的;經過看看它的代碼,比起在非開源供應商那裏,你也許更能意識到潛在的問題和限制。 

文檔存儲

CouchDB

CouchDB:  API: JSON, Protocol: REST, Query Method: MapReduceR of JavaScript Funcs, Replication: Master Master, Written in: Erlang, Concurrency: MVCC,  Misc
Links: 3 CouchDB books », Couch Lounge » (partitioning / clusering),  ...

它是Apache社區基於 Erlang/OTP 構建的高性能、分佈式容錯非關係型數據庫系統(NRDBMS)。它充分利用 Erlang 自己所提供的高併發、分佈式容錯基礎平臺,而且參考 Lotus Notes 數據庫實現,採用簡單的文檔數據類型(document-oriented)。在其內部,文檔數據均以 JSON 格式存儲。對外,則經過基於 HTTP 的 REST 協議實現接口,能夠用十幾種語言進行自由操做。



CouchDB一種半結構化面向文檔的分佈式,高容錯的數據庫系統,其提供RESTFul HTTP/JSON接口。其擁有MVCC特性,用戶能夠經過自定義Map/Reduce函數生成對應的View。

在CouchDB中,數據是以JSON字符的方式存儲在文件中。

特性

 

  • RESTFul API:HTTP GET/PUT/POST/DELETE + JSON
  • 基於文檔存儲,數據之間沒有關係範式要求
  • 每一個數據庫對應單個個文件(以JSON保存),Hot backup
  • MVCC(Multi-Version-Concurrency-Control),讀寫均不鎖定數據庫
  • 用戶自定義View
  • 內建備份機制
  • 支持附件
  • 使用Erlang開發(更多的特性)

 

應用場景 在咱們的生活中,有不少document,好比信件,帳單,筆記等,他們只是簡單的信息,沒有關係的需求,咱們可能僅僅須要存儲這些數據。 這樣的狀況下,CouchDB應該是很好的選擇。固然其餘使用關係型數據庫的環境,也能夠使用CouchDB來解決。

 

根據CouchDB的特性,在某些偶 爾鏈接網絡的應用中,咱們能夠用CouchDB暫存數據,隨後進行同步。也能夠在Cloud環境中,做爲分佈式的數據存儲。CouchDB提供給予 HTTP的API,這樣全部的常見語言均可以使用CouchDB。

 

使用CouchDB,意味着咱們不須要在像使用RMDBS同樣,在設計應用前首先設計負責數據Table。咱們的開發更加快速,靈活。 
詳細參見:
http://www.javaeye.com/topic/319839

Riak

Riak: API: JSON, Protocol: REST, Query Method: MapReduce term matching , Scaling:Multiple Masters; Written in: Erlang, Concurrency: eventually consistent (stronger then MVCC via Vector Clocks), Misc: ... Links: talk »,

MongoDB

MongoDB:  API: BSON, Protocol: lots of langs, Query Method: dynamic object-based language, Replication: Master Slave, Written in: C++,Concurrency: Update in Place.Misc: ... Links: Talk »,

MongoDB是一個介於關係數據庫和非關係數據庫之間的產品,是非關係數據庫當中功能最豐富,最像關係數據庫的。他支持的數據結構很是鬆散,是 相似json的bjson格式,所以能夠存儲比較複雜的數據類型。Mongo最大的特色是他支持的查詢語言很是強大,其語法有點相似於面向對象的查詢語 言,幾乎能夠實現相似關係數據庫單表查詢的絕大部分功能,並且還支持對數據創建索引。

Mongo主要解決的是海量數據的訪問效率問題,根據官方的文檔,當數據量達到50GB以上的時候,Mongo的數據庫訪問速度是MySQL的 10倍以上。Mongo的併發讀寫效率不是特別出色,根據官方提供的性能測試代表,大約每秒能夠處理0.5萬-1.5次讀寫請求。對於Mongo的併發讀 寫性能,我(robbin)也打算有空的時候好好測試一下。

由於Mongo主要是支持海量數據存儲的,因此Mongo還自帶了一個出色的分佈式文件系統GridFS,能夠支持海量的數據存儲,但我也看到有些評論認爲GridFS性能不佳,這一點仍是有待親自作點測試來驗證了。

最後因爲Mongo能夠支持複雜的數據結構,並且帶有強大的數據查詢功能,所以很是受到歡迎,不少項目都考慮用MongoDB來替代MySQL來實現不是特別複雜的Web應用,比方說why we migrated from MySQL to MongoDB就是一個真實的從MySQL遷移到MongoDB的案例,因爲數據量實在太大,因此遷移到了Mongo上面,數據查詢的速度獲得了很是顯著的提高。

MongoDB也有一個ruby的項目MongoMapper,是模仿Merb的DataMapper編寫的MongoDB的接口,使用起來很是簡單,幾乎和DataMapper如出一轍,功能很是強大易用。 

Terrastore


Terrastore: API: Java & http, Protocol: http, Language: Java, Querying: Range queries, Predicates, Replication: Partitioned with consistent hashing, Consistency: Per-record strict consistency, Misc: Based on Terracotta

ThruDB

ThruDB: (please help provide more facts!) Uses Apache Thrift to integrate multiple backend databases as BerkeleyDB, Disk, MySQL, S3.

Key Value / Tuple 存儲

Amazon之SimpleDB

Amazon SimpleDBMisc: not open source, Book »
SimpleDB 是一個亞馬遜網絡服務平臺的一個面向屬性的鍵/值數據庫。SimpleDB仍處於公衆測試階段;當前,用戶能在線註冊其「免費」版 --免費的意思是說直到超出使用限制爲止。

SimpleDB有幾方面的限制。首先,一次查詢最多隻能執行5秒鐘。其次,除了字符串類型,別無其它數據類型。一切都以字符串形式被存儲、獲取和 比較,所以除非你把全部日期都轉爲ISO8601,不然日期比較將不起做用。第三,任何字符串長度都不能超過1024字節,這限制了你在一個屬性中能存儲 的文本的大小(好比說產品描述等)。不過,因爲該模式動態靈活,你能夠經過追加「產品描述1」、「產品描述2」等來繞過這類限制。一個項目最多能夠有 256個屬性。因爲處在測試階段,SimpleDB的域不能大於10GB,整個庫容量則不能超過1TB。

SimpleDB的一項關鍵特性是它使用一種最終一致性模型。 這個一致性模型對併發性頗有好處,但意味着在你改變了項目屬性以後,那些改變有可能不能當即反映到隨後的讀操做上。儘管這種狀況實際發生的概率很低,你也 得有所考慮。好比說,在你的演出訂票系統裏,你不會想把最後一張音樂會門票賣給5我的,由於在售出時你的數據是不一致的。

Chordless


Chordless: API: Java & simple RPC to vals, Protocol: internal, Query Method: M/R inside value objects, Scaling: every node is master for its slice of namespace, Written in:Java, Concurrency: serializable transaction isolationLinks:

Redis

Redis : (please help provide more facts!)  API: Tons of languages, Written in: C, Concurrency: in memory and saves asynchronous disk after a defined time. Append only mode available. Different kinds of fsync policies. Replication: Master / Slave,

Redis是一個很新的項目,剛剛發佈了1.0版本。Redis本質上是一個Key-Value類型的內存數據庫,很像memcached,整個數據庫統 統加載在內存當中進行操做,按期經過異步操做把數據庫數據flush到硬盤上進行保存。由於是純內存操做,Redis的性能很是出色,每秒能夠處理超過 10萬次讀寫操做,是我知道的性能最快的Key-Value DB。

Redis的出色之處不只僅是性能,Redis最大的魅力是支持保存List鏈表和Set集合的數據結構,並且還支持對List進行各類操做,例 如從List兩端push和pop數據,取List區間,排序等等,對Set支持各類集合的並集交集操做,此外單個value的最大限制是1GB,不像 memcached只能保存1MB的數據,所以Redis能夠用來實現不少有用的功能,比方說用他的List來作FIFO雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的Set能夠作高性能的tag系統等等。另外Redis也能夠對存入的Key-Value設置expire時間,所以也能夠被看成一 個功能增強版的memcached來用。

Redis的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,而且它沒有原生的可擴展機制,不具備scale(可擴展) 能力,要依賴客戶端來實現分佈式讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上。目前使用Redis的網站有 github,Engine Yard。 

Scalaris

Scalaris(please help provide more facts!) Written in: Erlang, Replication: Strong consistency over replicas, Concurrency: non blocking Paxos.

Tokyo cabinet / Tyrant


Tokyo Cabinet / TyrantLinks: nice talk », slides », Misc: Kyoto Cabinet »

它是日本最大的SNS社交網站mixi.jp開發的 Tokyo Cabinet key-value數據庫網絡接口。它擁有Memcached兼容協議,也能夠經過HTTP協議進行數據交換。對任何原有Memcached客戶端來說, 能夠將Tokyo Tyrant當作是一個Memcached,可是,它的數據是能夠持久存儲的。Tokyo Tyrant 具備故障轉移、日誌文件體積小、大數據量下表現出色等優點,詳見:http://blog.s135.com/post/362.htm

Tokyo Cabinet 2009年1月18日發佈的新版本(Version 1.4.0)已經實現 Table Database,將key-value數據庫又擴展了一步,有了MySQL等關係型數據庫的表和字段的概念,相信不久的未來,Tokyo Tyrant 也將支持這一功能。值得期待。




TC除了支持Key-Value存儲以外,還支持保存Hashtable數據類型,所以很像一個簡單的數據庫表,而且還支持基於column的條 件查詢,分頁查詢和排序功能,基本上至關於支持單表的基礎查詢功能了,因此能夠簡單的替代關係數據庫的不少操做,這也是TC受到你們歡迎的主要緣由之一, 有一個Ruby的項目 miyazakiresistance將TT的hashtable的操做封裝成和ActiveRecord同樣的操做,用起來很是爽。

TC/TT在mixi的實際應用當中,存儲了2000萬條以上的數據,同時支撐了上萬個併發鏈接,是一個久經考驗的項目。TC在保證了極高的併發 讀寫性能的同時,具備可靠的數據持久化機制,同時還支持相似關係數據庫表結構的hashtable以及簡單的條件,分頁和排序操做,是一個很棒的 NoSQL數據庫。

TC的主要缺點是在數據量達到上億級別之後,併發寫數據性能會大幅度降低, NoSQL: If Only It Was That Easy提到,他們發如今TC裏面插入1.6億條2-20KB數據的時候,寫入性能開始急劇降低。看來是當數據量上億條的時候,TC性能開始大幅度降低,從TC做者本身提供的mixi數據來看,至少上千萬條數據量的時候尚未遇到這麼明顯的寫入性能瓶頸。

這個是Tim Yang作的一個 Memcached,Redis和Tokyo Tyrant的簡單的性能評測,僅供參考

 

CT.M

GT.M: API: M, C, Python, Perl, Protocol: native, inprocess C, Misc: Wrappers: M/DB for SimpleDB compatible HTTP »MDB:X for XML »PIP for mapping to tables for SQL », Features: Small footprint (17MB), Terabyte Scalability, Unicode support, Database encryption, Secure, ACID transactions (single node), eventual consistency (replication), License: AGPL v3 on x86 GNU/Linux, Links: Slides »,

Scalien

Scalien:  API / Protocol: http (text, html, JSON), C, C++, Python, Concurrency: Paxos.

Berkley DB

Berkley DB: API: Many languages, Written in: C, Replication: Master / Slave, Concurrency: MVCC, License: SleepycatBerkleyDB Java Edition: API: Java, Written in:Java, Replication: Master / Slave, Concurrency: serializable transaction isolation, License: Sleepycat

MemcacheDB

MemcacheDB: API: Memcache protocol (get, set, add, replace, etc.), Written in: C, Data Model: Blob, Misc: Is Memcached writing to BerkleyDB.

它是新浪互動社區事業部爲在Memcached基礎上,增長Berkeley DB存儲層而開發一款支持高併發的分佈式持久存儲系統,對任何原有Memcached客戶端來說,它仍舊是個Memcached,可是,它的數據是能夠持久存儲的。

 

Mnesia

Mnesia(ErlangDB »)

LightCloud

LightCloud:  (based on Tokyo Tyrant)

HamsterDB

HamsterDB:  (embedded solution) ACID Compliance, Lock Free Architecture (transactions fail on conflict rather than block), Transaction logging & fail recovery (redo logs), In Memory support – can be used as a non-persisted cache, B+ Trees – supported [Source: Tony Bain »]

Flare

TC是日本第一大SNS網站mixi開發的,而Flare是日本第二大SNS網站green.jp開發的,有意思吧。Flare簡單的說就是給 TC添加了scale功能。他替換掉了TT部分,本身另外給TC寫了網絡服務器,Flare的主要特色就是支持scale能力,他在網絡服務端以前添加了 一個node server,來管理後端的多個服務器節點,所以能夠動態添加數據庫服務節點,刪除服務器節點,也支持failover。若是你的使用場景必需要讓TC可 以scale,那麼能夠考慮flare。

flare惟一的缺點就是他只支持memcached協議,所以當你使用flare的時候,就不能使用TC的table數據結構了,只能使用TC的key-value數據結構存儲。

最終一致性Key Value存儲

Amazon之Dynamo

Amazon DynamoMisc: not open source (see KAI below)

功能特點

  • 高可用
  • 可擴展
  • 老是可寫
  • 能夠根據應用類型優化(可用性,容錯性,高效性配置)

架構特點


  • 徹底的分佈式
  • 去中心化(人工管理工做很小)
  • Key 惟一表明一個數據對象,對該數據對象的讀寫操經過 Key 來完成.
  • 一般是一臺自帶硬盤的主機。每一個節點有三個 Java 寫的組件:請求協調器(request coordination)、成員與失敗檢測、本地持久引擎(local persistence engine)
  • 數據分區並用改進的一致性哈希(consistent hashing)方式進行復制,利用數據對象的版本化實現一致性。複製時由於更新產生的一致性問題的維護採起相似 quorum 的機制以及去中心化的複製同步協議。 
  • 每一個實例由一組節點組成,從應用的角度看,實例提供 IO 能力。一個實例上的節點可能位於不一樣的數據中心內, 這樣一個數據中心出問題也不會致使數據丟失。

 

BeansDB

簡介

BeansDB 是一個主要針對大數據量、高可用性的分佈式KeyValue存儲系統,採用HashTree和簡化的版本號來快速同步保證最終一致性(弱),一個簡化版的Dynamo。

它採用相似memcached的去中心化結構,在客戶端實現數據路由。目前只提供了Python版本的客戶端,其它語言的客戶端能夠由memcached的客戶端稍加改造獲得。

Google Group: http://groups.google.com/group/beandb/

更新

2009.12.29 第一個公開版本 0.3

特性

  • 高可用:經過多個可讀寫的用於備份實現高可用
  • 最終一致性:經過哈希樹實現快速完整數據同步(短期內數據可能不一致)
  • 容易擴展:能夠在不中斷服務的狀況下進行容量擴展。
  • 高性能:異步IO和高性能的KeyValue數據TokyoCabinet 可配置的
  • 可用性和一致性:經過N,W,R進行配置 簡單協議:Memcache兼容協議,大量可用客戶端

 

性能

 

 

在小數據集上,它跟memcached同樣快: # memstorm -s localhost:7900 -n 1000
Num of Records      10000
Non-Blocking IO     0
TCP No-Delay        0

Successful   [SET]  10000
Failed       [SET]  0
Total Time   [SET]  0.45493s
Average Time [SET]  0.00005s

Successful   [GET]  10000
Failed       [GET]  0
Total Time   [GET]  0.28609s
Average Time [GET]  0.00003s

實際部署狀況下的性能(客戶端測量): &#x100084; 服務器 請求數 評價時間(ms中位數(ms99%(ms99.9%(ms)
&#x100084; get A:7900 n=151398, avg=8.89, med=5.9499%=115.599.9%=310.2
&#x100084; get B:7900 n=100054, avg=6.84, med=0.4099%=138.599.9%=483.0
&#x100084; get C:7900 n=151250, avg=7.42, med=5.3499%=55.299.9%=156.7
&#x100084; get D:7900 n=150677, avg=7.63, med=5.0999%=97.799.9%=284.7
&#x100084; get E:7900 n=3822,   avg=3.07, med=0.1899%=44.399.9%=170.0
&#x100084; get F:7900 n=249973, avg=8.29, med=6.3699%=46.899.9%=241.5
&#x100084; set A:7900 n=10177, avg=18.53, med=12.78,99%=189.399.9%=513.6
&#x100084; set B:7900 n=10431, avg=12.85, med=1.1999%=206.199.9%=796.8
&#x100084; set C:7900 n=10556, avg=17.29, med=12.97,99%=132.299.9%=322.9
&#x100084; set D:7900 n=10164, avg=7.34,  med=0.6499%=98.899.9%=344.4
&#x100084; set E:7900 n=10552, avg=7.18,  med=2.3399%=73.699.9%=204.8
&#x100084; set F:7900 n=10337, avg=17.79, med=15.3199%=109.099.9%=369.5
 

BeansDB設計實現(很是可貴的中文資料)
PPT

 

Nuclear

人人網研發中的數據庫
詳見:
http://ugc.renren.com/2010/01/21/ugc-nuclear-guide-use/
http://ugc.renren.com/2010/01/28/ugc-nuclear-guide-theory/




兩個設計上的Tips

1. 萬事皆異步
咱們在編碼的過程當中走了一些彎路,同步的操做在高併發的狀況下帶來的性能降低是很是恐怖的,因而乎,Nuclear系統中任何的高併發操做都消除了Block。no waiting, no delay。

2. 根據系統負載控制後臺線程的資源佔用
Nuclear系統中有很多的後臺線程默默無聞的作着各類辛苦的工做,可是它們一樣會佔用系統資源,咱們的解決方案是根據系統負載動態調整線程的運行和中止,並達到平衡。

 

Voldemort

Voldemort: (can you help)

Voldemort是個和Cassandra相似的面向解決scale問題的分佈式數據庫系統,Cassandra來自於Facebook這個 SNS網站,而Voldemort則來自於Linkedin這個SNS網站。提及來SNS網站爲咱們貢獻了n多的NoSQL數據庫,例如 Cassandar,Voldemort,Tokyo Cabinet,Flare等等。Voldemort的資料不是不少,所以我沒有特別仔細去鑽研,Voldemort官方給出Voldemort的併發讀 寫性能也很不錯,每秒超過了1.5萬次讀寫。




其實如今不少公司可能都面臨着這個抽象架構圖中的相似問題。以 Hadoop 做爲後端的計算集羣,計算得出來的數據若是要反向推到前面去,用什麼方式存儲更爲恰當? 再放到 DB 裏面的話,構建索引是麻煩事;放到 Memcached 之類的 Key-Value 分佈式系統中,畢竟只是在內存裏,數據又容易丟。Voldemort 算是一個不錯的改良方案。

值得借鑑的幾點:

  • 鍵(Key)結構的設計,有點技巧;
  • 架構師熟知硬件結構是有用的。越大的系統越是如此。
  • 用好並行。Amdahl 定律之後出現的場合會更多。




詳細:
http://www.dbanotes.net/arch/voldemort_key-value.html
http://project-voldemort.com/blog/2009/06/building-a-1-tb-data-cycle-at-linkedin-with-hadoop-and-project-voldemort/

Dynomite



Dynomite: (can you help)

Kai

KAI: Open Source Amazon Dnamo implementation, Misc: slides ,

未分類

Skynet

全新的Ruby MapReduce實現

2004年,Google提出用於分佈式數據處理的MapReduce設計模式,同時還提供了第一個C++的實現。如今,一個名爲Skynet的Ruby實現已經由Adam Pisoni發佈。
Skynet是可適配、可容錯的、可自我更新的,並且徹底
是分佈式的系統,不存在單一的失敗節點。

Skynet和Google在設計上有兩點重要的區別:
Skynet沒法向工做者(Worker)發送原生代碼(Raw code),
Skynet利用結對恢復系統,不一樣的工做者會互相監控以防失敗:
若是有一個工做者因爲某種緣由離開或者放棄了,就會有另外一個工做者發現並接管它的任務。Skynet 也沒有所謂的「主」管理進程,只有工做者,它們在任什麼時候間均可以充當任何任務的主管理進程。

Skynet的使用和設置都很容易,這也正是MapReduce這個概念的真正優點。Skynet還擴展了ActiveRecord,加入了MapReduce的特性,好比distributed_find。


你要爲Starfish編寫一些小程序,它們的代碼是你將要構建其中的。若是我沒有弄錯的話,你沒法在同一臺機器上運行多種類型的MapReduce做業。Skynet是一個更全面的MR系統,能夠運行多種類型的多個做業,好比,各類不一樣的代碼。

Skynet也容許失敗。工做者會互相關照。若是一個工做者失敗了,沒法及時完成任務,另外一個工做者將會接起這個任務並嘗試完成它。Skynet也支持map_data流,也就是說,即便某個數據集很是龐大,甚至沒法放在一個數據結構中,Skynet也能夠處理。


什 麼是map_data流?大多數時候,在你準備啓動一個map_reduce做業時,必須提供一個數據的隊列,這些數據已經被分離並將被並行處理。若是隊 列過大,以致於沒法適應於內存怎麼辦?在這種狀況下,你就要不能再用隊列,而應該使用枚舉(Enumerable)。Skynet知道去對象的調 用:next或者:each方法,而後開始爲「每個(each)」分離出map_task來。經過這樣的方式,不會有人再試圖同時建立大量的數據結構。

還 有不少特性值得一提,不過最想提醒你們的是,Skynet可以與你現有的應用很是完美地集成到一塊兒,其中天然包括Rails應用。Skynet甚 至還提供了一個ActiveRecord的擴展,你能夠在模型中以分佈式的形式執行一些任務。在Geni中,咱們使用這項功能來運行特別複雜的移植,它通 常涉及到在數百萬的模型上執行Ruby代碼。
> Model.distributed_find(:all, :conditions => "id > 20").each(:somemethod)在你運行Skynet的時候,它將在每一個模型上執行:somemethod,不過是以分佈式的方式(這和你 擁有多少個工做者相關)。它在向模型分發任務前沒必要進行初始化,甚至沒必要提早獲取全部的id。所以它能夠操做無限大的數據集。 用戶的反饋如何?

Drizzle

Drizzle可 被認爲是鍵/值存儲要解決的問題的反向方案。Drizzle誕生於MySQL(6.0)關係數據庫的拆分。在過去幾個月裏,它的開發者已經移走了大量非核 心的功能(包括視圖、觸發器、已編譯語句、存儲過程、查詢緩衝、ACL以及一些數據類型),其目標是要創建一個更精簡、更快的數據庫系統。Drizzle 仍能存放關係數據;正如MySQL/Sun的Brian Aker所說那樣:「沒理由潑洗澡水時連孩子也倒掉」。它的目標就是,針對運行於16核(或以上)系統上的以網絡和云爲基礎的應用,創建一個半關係型數據 庫平臺。 

比較

可擴展性



數據和查詢模型


當你須要查詢或更新一個值的一部分時,Key/value模型是最簡單有效實現。

面向文本數據庫是Key/value的下一步, 容許內嵌和Key關聯的值. 支持查詢這些值數據,這比簡單的每次返回整個blob類型數據要有效得多。

Neo4J是惟一的存儲對象和關係做爲數學圖論中的節點和邊. 對於這些類型數據的查詢,他們可以比其餘競爭者快1000s

Scalaris是惟一提供跨越多個key的分佈式事務。

持久化設計


內存數據庫是很是快的,(Redis在單個機器上能夠完成每秒100,000以上操做)可是數據集超過內存RAM大小就不行. 並且 Durability (服務器當機恢復數據)也是一個問題

Memtables和SSTables緩衝 buffer是在內存中寫(「memtable」), 寫以前先追加一個用於durability的日誌中. 
但有足夠多寫入之後,這個memtable將被排序而後一次性做爲「sstable.」寫入磁盤中,這就提供了近似內存性能,由於沒有磁盤的查詢seeks開銷, 同時又避免了純內存操做的durability問題.(我的點評 其實Java中的Terracotta早就實現這二者結合)
B-Trees提供健壯的索引,可是性能不好,通常和其餘緩存結合起來。

應用篇

eBay 架構經驗

  • 一、 Partition Everything 切分萬物
  • 二、 Asynchrony Everywhere 到處異步
  • 三、 Automate Everything 所有自動
  • 四、 Remember Everything Fails 記錄失敗
  • 五、 Embrace Inconsistency 親不一樣是謂大同
  • 六、 Expect (R)evolution 預言演變
  • 七、 Dependencies Matter 重視依賴
  • 八、 Be Authoritative 專斷專行
  • 九、 Never Enough Data
  • 十、Custom Infrastructure 自定義基礎設施

 淘寶架構經驗

  • 一、適當放棄一致性
  • 二、備份和隔離解決穩定性問題
  • 三、分割和異步解決性能問題(相似 eBay 的 Asynchrony Everywhere)
  • 四、自動化下降人力成本(相似 eBay 的 Automate Everything)
  • 五、產品化管理

 

Flickr架構經驗

  • 使得機器自動構建 (Teach machines to build themselves)
  • 使得機器自監控(Teach machines to watch themselves)
  • 使得機器自修復(Teach machines to fix themselves)
  • 經過流程減小 MTTR (Reduce MTTR by streamlining)



Twitter運維經驗

最近看到的另一個介紹Twitter技術的視頻[Slides] [Video (GFWed)],這是Twitter的John Adams在Velocity 2009的一個演講,主要介紹了Twitter在系統運維方面一些經驗。 本文大部分整理的觀點都在Twitter(@xmpp)上發過,這裏所有整理出來並補充完整。

Twitter沒有本身的硬件,都是由NTTA來提供,同時NTTA負責硬件相關的網絡、帶寬、負載均衡等業務,Twitter operations team只關注核心的業務,包括Performance,Availability,Capacity Planning容量規劃,配置管理等,這個可能跟國內通常的互聯網公司有所區別。 

運維經驗

Metrics

Twitter的監控後臺幾乎都是圖表(critical metrics),相似駕駛室的轉速錶,時速表,讓操做者能夠迅速的瞭解系統當前的運做狀態。聯想到咱們作的相似監控後臺,數據不少,但每每還須要瀏覽者 作二次分析判斷,像這樣滿屏都是圖表的方法作得還不夠,能夠學習下這方面經驗。 據John介紹能夠從圖表上看到系統的瓶頸-系統最弱的環節(web, mq, cache, db?)
根據圖表能夠科學的制定系統容量規劃,而不是過後救火。

 


 

 

配置管理

每一個系統都須要一個自動配置管理系統,越早越好,這條一整理髮到Twitter上去以後引發不少迴應。

Darkmode

配置界面能夠enable/disable 高計算消耗或高I/O的功能,也至關於優雅降級,系統壓力過大時取消一些非核心但消耗資源大的功能。

進程管理

Twitter作了一個」Seppaku」 patch, 就是將Daemon在完成了n個requests以後主動kill掉,以保持健康的low memory狀態,這種作法據瞭解國內也有很多公司是這樣作。

硬件

Twitter將CPU由AMD換成Xeon以後,得到30%性能提高,將CPU由雙核/4核換成8核以後,減小了40%的CPU, 不過John也說,這種升級不適合本身購買硬件的公司。 

代碼協同經驗

Review制度

Twitter有上百個模塊,若是沒有一個好的制度,容易引發代碼修改衝突,並把問題帶給最終用戶。因此Twitter有一強制的source code review制度, 若是提交的代碼的svn comment沒有」reviewed by xxx」, 則pre-commit腳本會讓提交失敗, review過的代碼提交後會經過自動配置管理系統應用到上百臺服務器上。 有@xiaomics同窗在Twitter上立刻就問,時間成本可否接受?若是有緊急功能怎麼辦?我的認爲緊急修改時有兩人在場,一人修改一人 review也不是什麼難事。

部署管理

從部署圖表能夠看到每一個發佈版本的CPU及latency變化,若是某個新版本latency圖表有明顯的向上跳躍,則說明該發佈版本存在問題。另外在監控首頁列出各個模塊最後deploy版本的時間,能夠清楚的看到代碼庫的現狀。

團隊溝通

Campfire來協同工做,campfire有點像羣,可是更適合協同工做。對於Campfire就不作更多介紹,可參考Campfire官方說明。

Cache

  • Memcache key hash, 使用FNV hash 代替 MD5 hash,由於FNV更快。
  • 開發了Cache Money plugin(Ruby), 給應用程序提供read-through, write-through cache, 就像一個db訪問的鉤子,當讀寫數據庫的時候會自動更新cache, 避免了繁瑣的cache更新代碼。
  • 「Evictions make the cache unreliable for important configuration data」,Twitter使用memcache的一條經驗是,不一樣類型的數據需放在不一樣的mc,避免eviction,跟做者前文Memcached數據被踢(evictions>0)現象分析中的一些經驗一致。
  • Memcached SEGVs, Memcached崩潰(cold cache problem)據稱會給這種高度依賴Cache的Web 2.0系統帶來災難,不知道Twitter具體怎麼解決。
  • 在Web層Twitter使用了Varnish做爲反向代理,並對其評價較高。

雲計算架構

 



做者認爲,金字塔概念最能說明每一層的大小,它也表達了每 個層是依賴前層的消息傳遞。在概念上,硬件是基礎和普遍層。SaaS層是頂峯,也是最輕層。這種觀點是來自於將購買SaaS的的最終用戶角度。對於一個非 常大的企業內部,PaaS平臺層將是頂峯。使用內部開發的軟件的內部各部門將實現他們的頂峯SaaS。還要注意:大小和層位置並不必定等同於重要性。硬件 層多是最重要的,由於它是全部超過必定點的商品。

硬件層The Hardware Layer
必須考慮容錯和冗餘,大部分人認爲沒有容錯硬件廉價商品。冗餘和容錯處理在軟件層內,硬件預計要失敗的,固然故障多電源容錯服務器,RAID磁盤陣列也是必要的。

虛擬層The Virtualization Layer
基於操做系統OS的虛擬化層,虛擬資源可以在線即時增長拓展,容許供應商提供基礎設施做爲服務(SaaS),VMware,Citrix公司,Sun都提供虛擬化產品。

The IaaS Layer
提 供和控制的基於虛擬層的計算方式,終端用戶可以精確控制每一個虛擬機沒分鐘每小時耗費多少錢。好比提供一個共同的接口,如門戶網站暴露的API,容許最終用 戶建立和配置虛擬機模板的需求。最終用戶還能夠控制什麼時候打開或破壞虛擬機,以及如何在虛擬機互相聯網。在這個領域的主要競爭者例子是亞馬遜網絡服務的 EC2,S3和數據庫服務。

The PaaS Layer
這一層的目的是儘可能減小部署雲的複雜性和麻煩,最終用戶 利用和開發的這層的API和編程語言。兩個很好的例子是谷歌的App Engine 和Force.com平臺,在App Engine中,谷歌公開雲存儲,平臺和數據庫,以及使用Python和Java編程語言的API。開發人員可以編寫應用程序並部署到這一層中,後端可伸縮性架構設計徹底交給谷歌負責,最終用戶徹底沒必要擔憂管理基礎設施。Force.com平臺相似,但採用了自定義的編程語言名爲Apex。若是你是一個大型企業尋求內部開發應用的部署,這層是你的頂峯。

The SaaS Layer
如 果您是中小型企業(SME)和大企業不但願開發本身的應用程序時,SaaS的層是你的頂峯(是你將直接面對的)。您只是進行有興趣地採購如電子郵件或客戶 關係管理服務,這些功能服務已經被供應商開發成功,並部署到雲環境中了,您只需驗證的應用是否符合你的使用須要,賬單能夠基於包月租費等各類形式,,做爲 最終用戶的您不會產生開發和維護拓展應用程序軟件的任何成本。愈來愈多的企業訂閱Salesforce.com和Sugar CRM的SaaS產品。

反模式

單點失敗(Single Point of Failure)


大部分的人都堅持在單一的設備上部署咱們的應用,由於這樣部署的費用會比較低,可是咱們要清楚任何的硬件設備都會有失敗的風險的,這種單點失敗會嚴重的影響用戶體驗甚至是拖垮你的應用,所以除非你的應用能容忍失敗帶來的損失,不然得話應該儘可能的避免單點風險,好比作冗餘,熱備等。

同步調用


同步調用在任何軟件系統中都是不可避免的,可是咱們軟件工程師必須明白同步調用給軟件系統帶來的問題。若是咱們將應用程序串接起來,那麼系統的可用性就會低於任何一個單一組件的可用性。好比組件A同步調用了組件B,組件A的可用性爲99.9%,組件B的可用性爲99.9%,那麼組件A同步調用組件B的可用性就是99.9% * 99.9%=99.8%。同步調用使得系統的可用性受到了全部串接組件可用性的影響,所以咱們在系統設計的時候應該清楚哪些地方應該同步調用,在不須要同步調用的時候儘可能的進行異步的調用(而我這裏所說的異步是一種基於應用的異步,是一種設計上的異步,由於J2EE目前的底層系統出了JMS是異步API之外,其它的API都是同步調用的,因此咱們也就不能依賴於底層J2EE平臺給咱們提供異步性,咱們必須從應用和設計的角度引入異步性)

不具有回滾能力


雖然對應用的每一個版本進行回滾能力測試是很是耗時和昂貴的,可是咱們應該清楚任何的業務操做都有可能失敗,那麼咱們必須爲這種失敗做好準備,須要對系統的用戶負責,這就要求系統必定要具備回滾的能力,當失敗的時候能進行及時的回滾。(說到回滾你們可能第一時間想到的是事務的回滾,其實這裏的回滾應該是一種更寬泛意義的回滾,好比咱們記錄每一次的失敗的業務操做,這樣在出現錯誤的時候就不是依靠於事務這種技術的手段,而是經過系統自己的回滾能力來進行回滾失敗業務操做)。

不記錄日誌


日誌記錄對於一個成熟穩定的系統是很是重要的,若是咱們不進行日誌記錄,那麼我就很難統計系統的行爲。

無切分的數據庫


隨着系統規模的慢慢變大,咱們就須要打破單一數據的限制,須要對其進行切分。

無切分的應用


系統在規模小的時候,也許感受不出無切分的應用帶來的問題,可是在目前互聯網高速發展的時代,誰能保證一個小應用在一晚上或者是幾夜之後仍是小應用呢?說不定哪天,咱們就發現應用在突如其來的訪問量打擊的支離破碎。所以咱們就須要讓咱們的系統和咱們同樣具備生命力,要想讓系統具備應付大負載的能力,這就要求咱們的應用具備很好的伸縮性,這也就要求應用須要被良好的切分,只有進行了切分,咱們才能對單一的部門進行伸縮,若是應用是一塊死板的話,咱們是沒有辦法進行伸縮的。就比如火車同樣,若是火車設計之初就把他們設計爲一體的,那麼咱們還怎麼對火車的車箱進行裁剪?所以一個沒有切分的應用是一個沒有伸縮性和沒有可用性的應用。

將伸縮性依賴於第三方廠商


若是咱們的應用系統的伸縮性依賴於第三方的廠商,好比依賴於數據庫集羣,那麼咱們就爲系統的伸縮性埋下了一個定時炸彈。由於只有咱們本身最清楚咱們本身的應用,咱們應該從應用和設計的角度出發去伸縮咱們的應用,而不是依賴於第三方廠商的特性。

OLAP


聯機分析處理 (OLAP) 的概念最先是由關係數據庫之父E.F.Codd於1993年提出的,他同時提出了關於OLAP的12條準則。OLAP的提出引發了很大的反響,OLAP做爲一類產品同聯機事務處理 (OLTP) 明顯區分開來。

OLAP報表產品最大的難點在哪裏?

目前報表工具最大的難點不在於報表的樣式(如斜線等),樣式雖較繁瑣但並不是本質困難。最根本的難點在於業務 部門知道報表表明的真正含義,殊不知道報表的數據統計模型模型;而IT部門經過理解業務部門的描述,在數據庫端進行設置數據統計模型,卻對報表自己所表明 的價值很難理解。

提及來有點深奧,其實並不複雜,OLAP最基本的概念只有三個:多維觀察、數據鑽取、CUBE運算。

關於CUBE運算:OLAP分析所需的原始數據量是很是龐大的。一個分析模型,每每會涉及數百萬、數千萬條數據,甚至更多;而分析模型中包含多個維數據,這些維又能夠由瀏覽者做任意的提取組合。這樣的結果就是大量的實時運算致使時間的延滯。

咱們能夠設想,一個1000萬條記錄的分析模型,若是一次提取4個維度進行組合分析,那麼實際的運算次數將 達到4的1000次方的數量。這樣的運算量將致使數十分鐘乃至更長的等待時間。若是用戶對維組合次序進行調整,或增長、或減小某些維度的話,又將是一個重 新的計算過程。

從上面的分析中,咱們能夠得出結論,若是不能解決OLAP運算效率問題的話,OLAP將是一個毫無實用價值的概念。那麼,一個成熟產品是如何解決這個問題的呢?這涉及到OLAP中一個很是重要的技術——數據CUBE預運算。

一個OLAP模型中,度量數據和維數據咱們應該事先肯定,一旦二者肯定下來,咱們能夠對數據進行預先的處理。在正式發佈以前,將數據根據維進行最大

限度的聚類運算,運算中會考慮到各類維組合狀況,運算結果將生成一個數據CUBE,並保存在服務器上。

這樣,當最終用戶在調閱這個分析模型的時候,就能夠直接使用這個CUBE,在此基礎上根據用戶的維選擇和維組合進行復運算,從而達到實時響應的效果。

NOSQL們背後的共有原則

幾個星期以前,我寫了一篇文章描述了常被稱做 NOSQL 的一類新型數據庫的背後驅動。幾個星期以前,我在Qcon上發表了一個演講,其中,我介紹了一個可伸縮(scalable)的 twitter 應用的構建模式,在咱們的討論中,一個顯而易見的問題就是數據庫的可擴展性問題。要解答這個問題,我試圖尋找隱藏在各類 NOSQL 以後的共有模式,並展現他們是如何解決數據庫可擴展性問題的。在本文中,我將盡力勾勒出這些共有的原則。

假設失效是必然發生的

與咱們先前經過昂貴硬件之類的手段盡力去避免失效的手段不一樣,NOSQL實現都創建在硬盤、機器和網絡都會失效這些假設之上。咱們須要認定,咱們不 能完全阻止這些時效,相反,咱們須要讓咱們的系統可以在即便很是極端的條件下也能應付這些失效。Amazon S3 就是這種設計的一個好例子。你能夠在我最近的文章 Why Existing Databases (RAC) are So Breakable! 中找到進一步描述。哪裏,我介紹了一些來自 Jason McHugh 的講演的面向失效的架構設計的內容(Jason 是在 Amazon 作 S3 相關工做的高級工程師)。

對數據進行分區

經過對數據進行分區,咱們最小化了失效帶來的影響,也將讀寫操做的負載分佈到了不一樣的機器上。若是一個節點失效了,只有該節點上存儲的數據受到影響,而不是所有數據。

保存同一數據的多個副本

大部分 NOSQL 實現都基於數據副本的熱備份來保證連續的高可用性。一些實現提供了 API,能夠控制副本的複製,也就是說,當你存儲一個對象的時候,你能夠在對象級指定你但願保存的副本數。在 GigaSpaces,咱們還能夠當即複製一個新的副本到其餘節點,甚至在必要時啓動一臺新機器。這讓咱們不比在每一個節點上保存太多的數據副本,從而下降 總存儲量以節約成本。

你還能夠控制副本複製是同步仍是異步的,或者二者兼有。這決定了你的集羣的一致性、可用性與性能三者。對於同步複製,能夠犧牲性能保障一致性和可用 性(寫操做以後的任意讀操做均可以保證獲得相同版本的數據,即便是發生失效也會如此)。而最爲常見的 GigaSpaces 的配置是同步副本到被分界點,異步存儲到後端存儲。

動態伸縮

要掌控不斷增加的數據,大部分 NOSQL 實現提供了不停機或徹底從新分區的擴展集羣的方法。一個已知的處理這個問題的算法稱爲一致哈希。有不少種不一樣算法能夠實現一致哈希。

一個算法會在節點加入或失效時通知某一分區的鄰居。僅有這些節點受到這一變化的影響,而不是整個集羣。有一個協議用於掌控須要在原有集羣和新節點之間從新分佈的數據的變換區間。

另外一個(簡單不少)的算法使用邏輯分區。在邏輯分區中,分區的數量是固定的,但分區在機器上的分佈式動態的。因而,例若有兩臺機器和1000個邏輯 分區,那麼每500個邏輯分區會放在一臺機器上。當咱們加入了第三臺機器的時候,就成了每 333 個分區放在一臺機器上了。由於邏輯分區是輕量級的(基於內存中的哈希表),分佈這些邏輯分區很是容易。

第二種方法的優點在於它是可預測而且一致的,而使用一致哈希方法,分區之間的從新分佈可能並不平穩,當一個新節點加入網絡時可能會消耗更長時間。一個用戶在這時尋找正在轉移的數據會獲得一個異常。邏輯分區方法的缺點是可伸縮性受限於邏輯分區的數量。

更進一步的關於這一問題的討論,建議閱讀 Ricky Ho 的文章 NOSQL Patterns 。

查詢支持

在這個方面,不一樣的實現有至關本質的區別。不一樣實現的一個共性在於哈希表中的 key/value 匹配。一些市縣提供了更高級的查詢支持,好比面向文檔的方法,其中數據以 blob 的方式存儲,關聯一個鍵值對屬性列表。這種模型是一種無預約義結構的(schema-less)存儲,給一個文檔增長或刪除屬性很是容易,無需考慮文檔結 構的演進。而 GigaSpaces 支持不少 SQL 操做。若是 SQL查詢沒有指出特定的簡直,那麼這個查詢就會被並行地 map 到全部的節點去,由客戶端完成結果的匯聚。全部這些都是發生在幕後的,用戶代碼無需關注這些。

使用 Map/Reduce 處理匯聚

Map/Reduce 是一個常常被用來進行復雜分析的模型,常常會和 Hadoop 聯繫在一塊兒。 map/reduce 經常被看做是並行匯聚查詢的一個模式。大部分 NOSQL 實現並不提供 map/reduce 的內建支持,須要一個外部的框架來處理這些查詢。對於 GigaSpaces 來講,咱們在 SQL 查詢中隱含了對 map/reduce 的支持,同時也顯式地提供了一個稱爲 executors 的 API 來支持 map/reduce。在質疑模型中,你能夠將代碼發送到數據所在地地方,並在該節點上直接運行復雜的查詢。

這方面的更多細節,建議閱讀 Ricky Ho 的文章 Query Processing for NOSQL DB 。

基於磁盤的和內存中的實現

NOSQL 實現分爲基於文件的方法和內存中的方法。有些實現提供了混合模型,將內存和磁盤結合使用。兩類方法的最主要區別在於每 GB 成本和讀寫性能。

最近,斯坦福的一項稱爲「The Case for RAMCloud」的調查,對磁盤和內存兩種方法給出了一些性能和成本方面的有趣的比較。整體上說,成本也是性能的一個函數。對於較低性能的實現,磁盤方 案的成本遠低於基於內存的方法,而對於高性能需求的場合,內存方案則更加廉價。

內存雲的顯而易見的缺點就是單位容量的高成本和高能耗。對於這些指標,內存雲會比純粹的磁盤系統差50到100 倍,比使用閃存的系統差5-10倍(典型配置狀況和指標參見參考文獻[1])。內存雲同時還比基於磁盤和閃存的系統須要更多的機房面積。這樣,若是一個應 用須要存儲大量的廉價數據,不須要高速訪問,那麼,內存雲將不是最佳選擇。
然而,對於高吞吐量需求的應用,內存雲將更有競爭力。當 使用每次操做的成本和能量做爲衡量因素的時候,內存雲的效率是傳統硬盤系統的 100 到 1000 倍,是閃存系統的 5-10 倍。所以,對於高吞吐量需求的系統來講,內存雲不只提供了高性能,也提供了高能源效率。同時,若是使用 DRAM 芯片提供的低功耗模式,也能夠下降內存雲的功耗,特別是在系統空閒的時候。此外,內存雲還有一些缺點,一些內存雲沒法支持須要將數據在 多個數據中心之間進行數據複製。對於這些環境,更新的時延將主要取決於數據中心間數據傳輸的時間消耗,這就喪失了內存雲的時延方面的優點。此外,跨數據中 心的數據複製會讓內存雲數據一致性更能難保證。不過,內存雲仍然能夠在誇數據中心的狀況下提供低時延的讀訪問。

僅僅是炒做?

近來我見到的最多的問題就是 「NOSQL 是否是就是炒做?」 或 「NOSQL 會不會取代如今的數據庫?」

個人回答是——NOSQL 並不是始於今日。不少 NOSQL 實現都已經存在了十多年了,有不少成功案例。我相信有不少緣由讓它們在現在比以往更受歡迎了。首先是因爲社會化網絡和雲計算的發展,一些原先只有很高端的 組織纔會面臨的問題,現在已經成爲廣泛問題了。其次,已有的方法已經被發現沒法跟隨需求一塊兒擴展了。而且,成本的壓力讓不少組織須要去尋找更高性價比的方 案,而且研究證明基於普通廉價硬件的分佈式存儲解決方案甚至比如今的高端數據庫更加可靠。(進一步閱讀)全部這些致使了對這類「可伸縮性優先數據庫」的需求。這裏,我引用 AWS團隊的接觸工程師、VP, James Hamilton 在他的文章 One Size Does Not Fit All 中的一段話:

「伸縮性優先應用是那些必須具有無限可伸縮性的應用,可以不受限制的擴展比更豐富的功能更加劇要。這些應用包括不少須要高 可伸縮性的網站,如 Facebook, MySpace, Gmail, Yahoo 以及 Amazon.com。有些站點實際上使用了關係型數據庫,而大部分實際上並未使用。這些服務的共性在於可擴展性比功能公衆要,他們沒法泡在一個單一的 RDBMS 上。」

總結一下——我認爲,現有的 SQL 數據庫可能不會很快淡出歷史舞臺,但同時它們也不能解決世上的全部問題。NOSQL 這個名詞如今也變成了 Not Only SQL,這個變化表達了個人觀點。 

本書不求利,只圖學術之便。感謝諸位大牛寫了那麼多的資料,若是您不肯意被引用,學生會重寫相應的章節。

引用網誌多篇,因爲涵蓋太廣難以一一校隊,特此致歉。

 

感謝

感謝Jdon,dbanotes,infoq和Timyang.您們分享和撰寫了那麼多有用的資料。

版本志

V0.1版本在2010.2.21發佈,提供了本書的主題框架
v0.2版本在2010.2.24發佈,由於一些外界緣由,提早發佈。完善各個示例,勘誤,翻譯部份內容。
v0.3版本將在3月份或以後發佈

 

引用

http://www.jdon.com/jivejdon/thread/37999http://queue.acm.org/detail.cfm?id=1413264http://www.dbanotes.net/arch/five-minute_rule.htmlhttp://www.infoq.com/cn/news/2009/09/Do-Not-Delete-Datahttp://www.infoq.com/cn/news/2010/02/ec2-oversubscribedhttp://timyang.net/architecture/consistent-hashing-practicehttp://en.wikipedia.org/wiki/Gossip_protocolhttp://horicky.blogspot.com/2009/11/nosql-patterns.htmlhttp://snarfed.org/space/transactions_across_datacenters_io.htmlhttp://research.microsoft.com/en-us/um/people/lamport/pubs/lamport-paxos.pdfhttp://en.wikipedia.org/wiki/Distributed_hash_tablehttp://hi.baidu.com/knuthocean/blog/item/cca1e711221dcfcca6ef3f1d.htmlhttp://zh.wikipedia.org/wiki/MapReducehttp://labs.google.com/papers/mapreduce.htmlhttp://nosql-database.org/http://www.rackspacecloud.com/blog/2009/11/09/nosql-ecosystem/http://www.infoq.com/cn/news/2008/02/ruby-mapreduce-skynethttp://s3.amazonaws.com/AllThingsDistributed/sosp/amazon-dynamo-sosp2007.pdfhttp://labs.google.com/papers/bigtable.htmlhttp://www.allthingsdistributed.com/2008/12/eventually_consistent.htmlhttp://www.rackspacecloud.com/blog/2009/11/09/nosql-ecosystem/http://timyang.net/tech/twitter-operations/http://blog.s135.com/read.php?394http://www.programmer.com.cn/1760

相關文章
相關標籤/搜索