NOSQL們背后的共有原則
幾個星期之前,我寫了一篇文章描述了常被稱作 NOSQL 的一類新型數據庫的背后驅動。幾個星期之前,我在Qcon上發表了一個演講,其中,我介紹了一個可伸縮(scalable)的 推ter 應用的構建模式,在我們的討論中,一個顯而易見的問題就是數據庫的可擴展性問題。要解答這個問題,我試圖尋找隱藏在各種 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
到所有的節點去,由客戶端完成結果的匯聚。所有這些
都是發生在幕后的,用戶代碼無需關注這些。