NoSQL數據庫筆談
序
日前國內沒有一套比較完整的NoSQL數據庫資料,有不少先驅整理髮表了不少,但不是很系統。不材嘗試着將各家的資料整合一下,並書寫了一些本身的看法。
本書寫了一些目前的NoSql的一些主要技術,算法和思想。同時列舉了大量的現有的數據庫實例。讀徹底篇,相信讀者會對NoSQL數據庫瞭解個大概。
另外我還準備開發一個開源內存數據庫galaxydb.本書也是爲這個數據庫提供一些架構資料。php
思想篇
CAP,BASE和最終一致性是NoSQL數據庫存在的三大基石。而五分鐘法則是內存數據存儲了理論依據。這個是一切的源頭。
CAP
- C: Consistency 一致性
- A: Availability 可用性(指的是快速獲取數據)
- P: Tolerance of network Partition 分區容忍性(分佈式)
10年前,Eric Brewer教授指出了著名的CAP理論,後來Seth Gilbert 和 Nancy lynch兩人證實了CAP理論的正確性。CAP理論告訴咱們,一個分佈式系統不可能知足一致性,可用性和分區容錯性這三個需求,最多隻能同時知足兩個。
熊掌與魚不可兼得也。關注的是一致性,那麼您就須要處理由於系統不可用而致使的寫操做失敗的狀況,而若是您關注的是可用性,那麼您應該知道系統的read操做可能不能精確的讀取到write操做寫入的最新值。所以系統的關注點不一樣,相應的採用的策略也是不同的,只有真正的理解了系統的需求,纔有可能利用好CAP理論。
做爲架構師,通常有兩個方向來利用CAP理論
- key-value存儲,如Amaze Dynamo等,可根據CAP三原則靈活選擇不一樣傾向的數據庫產品。
- 領域模型 + 分佈式緩存 + 存儲 (Qi4j和NoSql運動),可根據CAP三原則結合本身項目定製靈活的分佈式方案,難度高。
我準備提供第三種方案:實現能夠配置CAP的數據庫,動態調配CAP。
- CA:傳統關係數據庫
- AP:key-value數據庫
而對大型網站,可用性與分區容忍性優先級要高於數據一致性,通常會盡可能朝着 A、P 的方向設計,而後經過其它手段保證對於一致性的商務需求。架構設計師不要精力浪費在如何設計能知足三者的完美分佈式系統,而是應該進行取捨。
不一樣數據對於一致性的要求是不一樣的。舉例來說,用戶評論對不一致是不敏感的,能夠容忍相對較長時間的不一致,這種不一致並不會影響交易和用戶體驗。而產品價格數據則是很是敏感的,一般不能容忍超過10秒的價格不一致。
最終一致性
一言以蔽之:過程鬆,結果緊,最終結果必須保持一致性
爲了更好的描述客戶端一致性,咱們經過如下的場景來進行,這個場景中包括三個組成部分:
存儲系統能夠理解爲一個黑盒子,它爲咱們提供了可用性和持久性的保證。
ProcessA主要實現從存儲系統write和read操做
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的後續操做都會讀取到最新值。可是其它用戶可能要過一會才能夠看到。
此種一致性要求客戶端和存儲系統交互的整個會話階段保證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 這個"新的舊硬件"可能帶來的影響。
隨着閃存時代的來臨,五分鐘法則一分爲二:是把 SSD 當成較慢的內存(extended buffer pool )使用仍是當成較快的硬盤(extended disk)使用。小內存頁在內存和閃存之間的移動對比大內存頁在閃存和磁盤之間的移動。在這個法則首次提出的 20 年以後,在閃存時代,5 分鐘法則依然有效,只不過適合更大的內存頁(適合 64KB 的頁,這個頁大小的變化偏偏體現了計算機硬件工藝的發展,以及帶寬、延時)。
不要刪除數據
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 White是
Hadoop 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爲節點數。此方法容易實現且可以知足運營要求。缺點是當單點發生故障時,系統沒法自動恢復。
第二階段
爲了解決單點故障,使用 hash() mod (n/2), 這樣任意一個用戶都有2個服務器備選,可由client隨機選取。因爲不一樣服務器之間的用戶須要彼此交互,因此全部的服務器須要確切的知道用戶所在的位置。所以用戶位置被保存到memcached中。
當一臺發生故障,client能夠自動切換到對應backup,因爲切換前另外1臺沒有用戶的session,所以須要client自行從新登陸。github
這個階段的設計存在如下問題
負載不均衡,尤爲是單臺發生故障後剩下一臺會壓力過大。
不能動態增刪節點
節點發生故障時須要client從新登陸
第三階段
打算去掉硬編碼的hash() mod n 算法,改用一致性哈希(consistent hashing)分佈
假如採用Dynamo中的strategy 1
咱們把每臺server分紅v個虛擬節點,再把全部虛擬節點(n*v)隨機分配到一致性哈希的圓環上,這樣全部的用戶從本身圓環上的位置順時針往下取到第一個vnode就是本身所屬節點。當此節點存在故障時,再順時針取下一個做爲替代節點。
優勢:發生單點故障時負載會均衡分散到其餘全部節點,程序實現也比較優雅。
亞馬遜的現狀
aw2.0公司的Alan Williamson撰寫了一篇報道,主要是關於他在Amazon EC2上的體驗的,他抱怨說,Amazon是公司惟一使用的雲提供商,看起來它在開始時可以適應得很好,可是有一個臨界點:
在開始的日子裏Amazon的表現很是棒。實例在幾分鐘內啓動,幾乎沒有遇到任何問題,即使是他們的
小實例(SMALL INSTANCE)也很健壯,足以支持適當使用的MySQL數據庫。在20個月內,Amazon雲系統一切運轉良好,不須要任何的關心和抱怨。
……
然而,在最後的八個月左右,他們「盔甲」內的漏洞開始呈現出來了。第一個弱點前兆是,新加入的Amazon SMALL實例的性能出現了問題。根據咱們的監控,在服務器場中新添加的機器,與原先的那些相比性能有所降低。開始咱們認爲這是天然出現的怪現象,只是碰 巧發生在「吵鬧的鄰居」(Noisy Neighbors)旁邊。根據隨機法則,一次快速的停機和從新啓動常常就會讓咱們回到「安靜的鄰居」旁邊,那樣咱們能夠達到目的。
…… 然而,在最後的一兩個月中,咱們發現,甚至是這些「使用高級CPU的中等實例」也遭受了與小實例相同的命運,其中,新的實例無論處於什麼位置,看起來彷佛都表現得同樣。通過調查,咱們還發現了一個新問題,它已經悄悄滲透到到Amazon的世界中,那就是內部網絡延遲。
算法的選擇
不一樣的哈希算法能夠致使數據分佈的不一樣位置,若是十分均勻,那麼一次MapReduce就涉及節點較多,但熱點均勻,方便管理。反之,熱點不均,會大體機器效率發揮不徹底。
Quorum NRW
- 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
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
虛擬節點,未完成
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.
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.
Replicas also gossip among each other in the background and try to merge their version tree together.
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.
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
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.
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, 如圖。
(圖片來源: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
- 新加入的節點宣告本身的存在(廣播或者其餘手段)
- 他的鄰居節點要調整Key的分配和複製關係。這個操做一般是同步的
- 這個新加入的節點異步的拷貝數據
- 這個節點變化的操做被髮布到其餘節點
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)
- The crashed node no longer respond to gossip message so its neighbors knows about it.崩潰的節點再也不發送Gossip Message的迴應,因此他的鄰居都知道他是了
- 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 [
1, 2, 3]
耶魯大學之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 SimpleDB: Misc: 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 isolation, Links:
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 / Tyrant: Links: 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: Sleepycat, BerkleyDB 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 Dynamo: Misc: 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
實際部署狀況下的性能(客戶端測量): 􀂄 服務器 請求數 評價時間(ms) 中位數(ms) 99%(ms) 99.9%(ms)
􀂄 get A:7900 n=151398, avg=8.89, med=5.94, 99%=115.5, 99.9%=310.2
􀂄 get B:7900 n=100054, avg=6.84, med=0.40, 99%=138.5, 99.9%=483.0
􀂄 get C:7900 n=151250, avg=7.42, med=5.34, 99%=55.2, 99.9%=156.7
􀂄 get D:7900 n=150677, avg=7.63, med=5.09, 99%=97.7, 99.9%=284.7
􀂄 get E:7900 n=3822, avg=3.07, med=0.18, 99%=44.3, 99.9%=170.0
􀂄 get F:7900 n=249973, avg=8.29, med=6.36, 99%=46.8, 99.9%=241.5
􀂄 set A:7900 n=10177, avg=18.53, med=12.78,99%=189.3, 99.9%=513.6
􀂄 set B:7900 n=10431, avg=12.85, med=1.19, 99%=206.1, 99.9%=796.8
􀂄 set C:7900 n=10556, avg=17.29, med=12.97,99%=132.2, 99.9%=322.9
􀂄 set D:7900 n=10164, avg=7.34,