\t\tNoSQL漫談 NoSql = Not Only Sql != No Sql

什麼是NoSQL?wiki上的定義是“NoSQL is a movement promoting a loosely defined class of non-relational data stores that break with a long history of relational databases”。其實並不存在一個叫NoSQL的產品,它是一類non-relational data stores的集合。NoSQL的重點是non-relational,而傳統的數據庫是relational。

下面是wikipedia上列出了NoSQL的一些開源項目,有時間應該去了解一下。
* Cassandra
* Chordless
* CouchDB
* Db4o
* GT.M
* Hbase
* Hypertable
* Memcachedb
* Mnesia
* MongoDB
* Neo4j
* Project Voldemort
* Redis

我們都知道,傳統關係型數據庫的最大缺陷是擴展性,雖然各個數據庫廠家都有cluster的解決方案,但是不管是share storage還是share nothing的解決方案,擴展性都十分有限。目前解決數據庫擴展性的思路主要有兩個:第一是數據分片(sharding)或者功能分區,雖然說可以很好的解決數據庫擴展性的問題,但是在實際使用過程中,一旦採用數據分片或者功能分區,必然會導致犧牲“關係型”數據庫的最大優勢-join,對業務侷限性非常大,而數據庫也退化成爲一個簡單的存儲系統。另外一個思路是通過maser-slave複製的方式,通過讀寫分離技術在某種程度上解決擴展性的問題,但這種方案中,由於每個數據庫節點必須保存所有的數據,這樣每個存儲的IO subsystem必然成爲擴展的瓶頸,而且masert節點也是一個瓶頸。總的來說,傳統關係型數據庫的擴展能力十分有限。
在說NoSQL之前,首先得說兩個重要的概念,一個是CAP理論,另一個是BASE模型。
CAP
Consistency(一致性),數據一致更新,所有數據變動都是同步的
Availability(可用性),好的響應性能
Partition tolerance(分區容錯性) 可靠性
CAP原理告訴我們,這三個因素最多隻能滿足兩個,不可能三者兼顧。對於分佈式系統來說,分區容錯是基本要求,所以必然要放棄一致性。對於大型網站來說,分區容錯和可用性的要求更高,所以一般都會選擇適當放棄一致性。對應CAP理論,NoSQL追求的是AP,而傳統數據庫追求的是CA,這也可以解釋爲什麼傳統數據庫的擴展能力有限的原因。
BASE
Basically Availble:基本可用
Soft-state: 軟狀態/柔性事務
Eventual Consistency:最終一致性
BASE模型是傳統ACID模型的反面,不同與ACID,BASE強調犧牲高一致性,從而獲得可用性。基本可用是指通過sharding,允許部分分區失敗。軟狀態是指異步,允許數據在一段時間內的不一致,只要保證最終一致就可以了。最終一致性是整個NoSQL中的一個核心理念,很多NoSQL產品就是基於最終一致性而設計的,包括Amazon的Dynamo.
NoSQL產品簡介
NoSQL是很多non-relational data stores的集合,總體來說,他們基本都是基於Key-value形式的一種分佈式存儲,但是每一種NoSQL產品都面向一個特定的應用場景,根據這些應用場景,我們可以把NoSQL分爲以下類型(參考了wiki上的定義,只列舉了我們比較熟悉的產品):
KV cache:Memcached
KV store:Tokyo Tyrand/Cabinet,Memcachedb,Berkley DB
Eventually consistent KV store:dynamo,voldemort,Cassandra
Wide columnar store:BigTable,Cassandra,Hbase
document store:MongoDB
KV Cache類型不具有持久化存儲的功能,其中的memcached被我們廣泛使用,用來緩解數據庫的壓力,至於數據持久化存儲的功能則由數據庫來替代了。
KV store具備了持久化存儲的功能,其中的memcachedb是新浪在memcached的基礎上,採用Berkley DB作爲存儲層開發的分佈式KV store。Tokyo Tyrand/Cabinet是日本最大的SNS社交網站mixi.jp開發的KV store,其中TC是一個NoSQL的數據庫,用來做持久化數據存儲,TT則是TC的網絡接口(兼容memcached協議)。至於Berkley DB則是一個嵌入式數據庫,現在掌握在Oracle手中。
Eventually consistent KV store是以最終一致性原理設計的一類KV store,包括Amazon的Dynamo,Lindedin的voldemort以及Facebook的Cassandra,Dynamo的主要特點是:分佈式(去中心化),高可用,可擴展,永遠可寫等等。Dynamo的設計思想是分佈式系統中最重要的理論之一,另外一個是Bigtable。
Wide columnar store包括Bigtable,Cassandra和Hbase,這種類型是用來處理結構化數據的,它有幾個特點:具備大規模擴展能力,有類似數據庫中column的概念,非常靈活的schema,採用memtable/sstable的存儲機制,並基於列存儲。Cassandra採用了Dynamo最終一致性的理念,並借鑑了Bigtable的數據模型和實現方式,所以很多人把他看作是開源版本的Bigtable+Dynamo,這種類型的KV store是我們關注的重點。
document store是基於文檔的KV store,這種類型主要面向海量數據處理,其中MongoDB的特點是支持非常複雜的數據類型,而且查詢語言非常強大,有些類似於關係型數據庫。但它並不適合大規模併發讀寫的應用。
下面介紹幾個分佈式系統的概念:consistent hashing,virtual node,quorum,vector clock:
consistent hashing
下載 (48.42 KB)

2010-8-2 18:12
我們通常使用的hash算法是hash() mod n,但是如果發生某個節點失效時,無法快速切換到其他節點。爲了解決單點故障的問題,我們爲每個節點都增加一個備用節點,當某個節點失效時,就自動切換到備用節點上,類似於數據庫的master和slave。但是依然無法解決增加或刪除節點後,需要做hash重分佈的問題,也就是無法動態增刪節點。這時就引入了一致性hash的概念 ,將所有的節點分佈到一個hash環上,每個請求都落在這個hash環上的某個位置,只需要按照順時針方向找到的第一個節點,就是自己需要的服務節點。當某個節點發生故障時,只需要在環上找到下一個可用節點即可。一致性hash解決了增刪節點後需要hash重分佈的問題,是分佈式系統的基礎。
virtual node
虛擬節點是在一致性hash的基礎上,把一臺物理節點虛擬成多個虛擬節點,並映射到hash環的不同位置上。這樣的好處是可以根據機器硬件的性能,靈活的定義虛擬節點的個數。這裏所說的虛擬節點不是用虛擬機技術實現的,而是把一個物理節點映射爲多個虛擬節點。
quorum NRW

N: 複製的節點數,即一份數據被保存的份數。
R: 成功讀操作的最小節點數,即每次讀取成功需要的份數。
W: 成功寫操作的最小節點數 ,即每次寫成功需要的份數。
這三個因素決定了可用性,一致性和分區容錯性。對於一個分佈式系統來說,N通常都大於3,也就說同一份數據需要保存在三個以上不同的節點上,以防止單點故障。W是成功寫操作的最小節點數,這裏的寫成功可以理解爲“同步”寫,比如N=3,W=1,那麼只要寫成功一個節點就可以了,另外的兩份數據是通過異步的方式複製的。R是成功讀操作的最小節點數,讀操作爲什麼要讀多份數據呢?在分佈式系統中,數據在不同的節點上可能存在着不一致的情況,我們可以選擇讀取多個節點上的不同版本,來達到增強一致性的目的。下面我們分析幾個典型的場景:
N=W,R=1,這種情況是最強一致性的,每個節點都被同步寫入,讀取任意節點即可,所以讀取的性能最高,但是可用性是最差的,因爲必須保證每個節點都必須成功寫人。
R+W>N,這種情況也是可以保證一致性的,因爲讀取數據的節點和同步寫入的節點至少有一個重疊,比如N=3,W=2,R=2,每份數據有三個複本,每次同步寫成功兩份數據,每次讀取至少兩份數據,則說明讀取的數據至少有一份是同步寫人的最新數據,所以一致性可以得到保證,N=3,W=2,R=2是可用性和性能的一個平衡。
N=R,W=1,這種情況最大程度保證了寫的性能,數據只寫一份即成功,而讀取時則需要所有的數據複本,以此來達到保證一致性的目的,但是同樣犧牲了可用性。
W+R<=N,這種情況是不保證一致性的,因爲讀取和寫入的節點可能存在不重疊的情況,在數據同步到其他節點的這段時間窗口內,可能會出現數據不一致的情況。
總體來說,CAP原理決定了魚肉熊掌不可兼得,必須有所取捨。數據庫ACID模型保證了強一致性,但是對於大部分網站類型的應用,並不需要如此強的一致性,保證用戶感知一致性就可以了,即在用戶下次訪問之前保證數據最終一致。還有一些應用要求Read your writes consistency,即用戶對自己所做的修改即時可見,而對別人的數據則允許出現一定時間的延遲。
vector clock
vector clock相當於在數據上增加了一個版本控制。wiki上的解釋:“Vector clocks is an algorithm for generating a partial ordering of events in a distributed system and detecting causality violations.”

有Sx,Sy,Sz三個節點,N=3,W=1,R=3,數據分別初始爲(Sx:0),(Sy:0),(Sz:0),數據在Sx節點發生變更,變成了D1(Sx:1),然後又被更新變爲D2(Sx:2),此時D2(Sx:2)可以覆蓋D1(Sx:1),假設數據已經被同步到另外兩個節點,這時有兩個請求分別在Sy和Sz節點上更新數據,產生了新的版本D3(Sx:2,Sy:1)和D4(Sx:2,Sz:1)。此時,如果發生讀操作,從三個節點上讀取到不同的版本,發現D1版本不是最新的數據,而D3和D4版本都是最新的數據,這時就需要應用自己去進行合併,並由Sx節點產生了新的版本D5(Sx:3,Sy:1,Sz:1)。
存儲實現
NoSQL的存儲實現非常多,個人覺得比較有代表性的有:Memcachedb採用Berkley DB,TC底層採用Hash table和B-tree的結構,Bigtable和Cassandra採用的Memtable和SStable存儲機制。
我想說一下Cassandra的存儲機制,和數據庫類似,每次寫操作之前,必須首先記錄到日誌中,Cassandra的日誌稱爲commitlog。Memtable是一個按照key排序的內存結構,當Memtable寫滿後,會刷新到磁盤上存儲起來,稱爲SStable,SStable一旦寫入,就不能修改,只能讀取和追加。這種方式的優勢在於將隨機IO變成了順序IO,大大提高了系統的IO能力。當讀取數據時,可能需要將Memtable和SStable的數據進行合併,Cassandra使用bloom filter來快速判定一個key是否落在某個SStable中。而一旦出現Memtable中的數據丟失,則可以通過commitlog來恢復,這點很象傳統的數據庫。

數據庫和NoSQL
能否用數據庫實現NoSQL類似的應用?事實上就有人這樣做,Friendfeed就用MySQL數據庫來實現的。但是用關係型數據庫來實現,存在幾個問題:1.性能問題;2.schema無法靈活定義;3.擴展性的問題。
首先是性能問題,所有的數據庫都基於存儲優化,而不是基於內存優化的,也就是說數據庫的最佳應用場景是具有少量內存,而具有大量外部IO的情況。就算你有足夠大的cache,把所有的數據都cache到內存中,與專門設計的內存數據庫或者Key-Value cache相比,依然要慢幾個數量級。這是數據庫內部的算法決定的,所以不要指望把數據庫當cache來用,當然專門的內存數據庫除外,比如Oracle timesten.
第二個問題是schema不夠靈活,關係型數據庫中schema是無法靈活定義的,而Cassandra這類NoSQL數據庫,You can add and remove arbitrary fields on the fly。其中最根本的原因是數據庫是關係型的,新增或刪除列都必須影響到每個表中的每一行。而NoSQL則不需要,每一行的column都可以不同,可以說根本就不存在schema的概念。根據Bigtable的定義:A Bigtable is a sparse, distributed, persistent multidimensional sorted map。相對於Bigtable“稀疏”的概念,我們認爲關係型數據庫中的表是“密集”的,也可以把Bigtable理解爲一張滿是空洞的table。
第三擴展性問題,數據庫基於ACID模型設計,保證了強一致性,必然犧牲了擴展性,雖然可以用sharding或功能分區做橫向擴展,但是也讓數據庫退化成爲一個簡單的key value store。
NoSQL會取代數據庫嗎?
未來NoSQL會取代數據庫嗎?傳統的關係型數據庫還有優勢嗎?我個人認爲關係型數據庫至少在相當長的一段時間內,依然是主流,而且還有很大的發展空間。
首先,NoSQL的應用場景非常侷限,某個類型的NoSQL僅僅針對特定類型的應用場景而設計,Cassandra在facebook用來承擔inbox的搜索功能,而關係型數據庫則要通用的多,也就是說NoSQL很難拿來就用,首先你必須搞清楚自己的應用場景,所以說NoSQL對於很多人來說是此之蜜糖,彼之砒霜。
第二,利用關係型數據庫一樣可以搭建出可以靈活擴展的架構,根據CAP原理,只要有所取捨,利用關係型數據庫同樣可以做到。
第三,關係型數據庫廠家依然很強大,全世界有大量的用戶。同時,硬件的發展更是日新月異,比如SSD的出現,就可以作爲內存和磁盤之間的一層cache,甚至在不遠的將來,完全替換磁盤。隨着IO能力的巨大提升,數據庫的性能也隨着得到了更大的提升,很多現在面臨的IO問題都不再是問題。而且,針對數據庫的擴展性,廠家也提出了很多解決的方案,在一定程度上說,關係型數據庫依然是最好的解決方案之一。
作爲一名DBA,我並不擔心數據庫的未來,但我也不忽視NoSQL的巨大力量。有人將NoSQL解釋成爲Not only SQL,我想就是這個原因吧。
沒有一種解決方案是完美的,架構就是有所取捨,世界也因爲多樣才美麗。

發佈了190 篇原創文章 · 獲贊 4 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章