NO IMAGE

什麼是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。

我們都知道,傳統關係型資料庫的最大缺陷是擴充套件性,雖然各個資料庫廠家都有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

我們通常使用的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,我想就是這個原因吧。

沒有一種解決方案是完美的,架構就是有所取捨,世界也因為多樣才美麗。