qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          NoSQL生態系統

            要想了解NoSQL,必須先了解現有的這些工具,去理解那些引導它們開拓出新的存儲領域的設計思路。

            NoSQL 其名

            在給 NoSQL 下定義之前,我們先來試著從它的名字上做一下解讀。顧名思義,NoSQL 系統的數據操作接口應該是非 SQL 類型的。但在 NoSQL 社區,NoSQL 被賦予了更具有包容性的含義,其意為 Not Only SQL,即 NoSQL 提供了一種與傳統關系型數據庫不同的存儲模式,這為開發者提供了關系型數據庫之外的另一種選擇。

            NoSQL 的啟示

            NoSQL 運動受到了很多相關研究論文的啟示,在所有資料中,最核心的有兩個:Google 的 BigTable 論文和 Amazon 的 Dynamo 論文。

            特性概述

            NoSQL 系統舍棄了一些 SQL 標準中的功能,取而代之的是一些簡單靈活的功能。NoSQL 的構建思想就是盡量簡化數據操作,盡量讓操作的執行效率可預估。當你去考查一個 NoSQL 系統時,下面的幾點是值得注意的。

            數據模型及操作模型:你的應用層數據模型是行、對象還是文檔型的呢?這個系統是否能支持你進行一些統計工作呢?

            可靠性:當你更新數據時,新的數據是否立刻寫到持久化存儲中去了?新的數據是否同步到多臺機器上了?

            擴展性:你的數據量有多大,單機是否能容下?你的讀寫量需求單機是否能支持?

            分區策略:考慮到對擴展性、可用性或者持久性的要求,你是否需要一份數據被存在多臺機器上?你是否需要知道或者說你能否知道數據在哪臺機器上?

            一致性:你的數據是否被復制到了多臺機器上?這些不同節點的數據如何保證一致性?

            事務機制:業務是否需要 ACID 事務機制?

            單機性能:如果你打算持久化的將數據存在磁盤上,哪種數據結構能滿足你的需求(你的需求是讀多還是寫多)?寫操作是否會成為磁盤瓶頸?

            負載可評估:對于一個讀多寫少的應用,諸如響應用戶請求的網絡應用,我們總會花很多精力來關注負載情況。你可能需要進行數據規模的監控,對多個用戶的數據進行匯總統計。你的應用場景是否需要這樣的功能呢?

            NoSQL 數據模型及操作模型

            數據庫的數據模型指的是數據在數據庫中的組織方式,數據庫的操作模型指的是存取這些數據的方式。通常數據模型包括關系模型、鍵值模型以及各種圖 結構模型。操作語言可能包括 SQL、鍵值查詢及 MapReduce 等。NoSQL 通常結合了多種數據模型和操作模型,提供不一樣的架構方式。

            基于Key值存儲的NoSQL數據模型

            在鍵值型系統中,復雜的聯合查詢以及滿足多個條件的數據查詢操作就不那么容易實現了,需要換一種思維來建立和使用鍵名。比如要獲取部門號為 20 的所有員工的信息,應用層可以先獲取 Key 為 employee_departments:20的這個列表,然后再循環地拿這個列表中的 ID 通過獲取 employee:ID 得到所有員工的信息。

            Key-Value 存儲

            Key-Value 存儲可以說是最簡單的 NoSQL 存儲,每個 Key 值對應一個任意的數據值。對 NoSQL 系統來說,這個任意的數據值是什么,它并不關心。比如在員工信念數據庫里,employee:30這個 Key 對應的可能就是一段包含員工所有信息的二進制數據。這個二進制的格式可能是 Protocol Buffer、Thrift 或者 Avro 都無所謂。

            Key-結構化數據存儲

            Key-結構化數據存儲的典型代表是 Redis,Redis 將 Key-Value 存儲的 Value 變成了結構化的數據類型。Value 的類型包括數字、字符串、列表、集合以及有序集合。除了 set/get/delete 操作以為,Redis 還提供了很多針對以上數據類型的特殊操作,比如針對數字可以執行增、減操作,對 list 可以執行 push/pop 操作,通過提供這種針對單個 Value 進行的特定類型的操作,Redis 可以說實現了功能與性能的平衡。

          Key-文檔存儲

            Key-文檔存儲的代表有 CouchDB、MongoDB 和 Riak。這種存儲結構下 Key-Value 的 Value 是結構化的文檔,通常這些文檔是被轉換成 JSON 或者類似于 JSON 的結構進行存儲。文檔可以存儲列表,鍵值對以及層次結構復雜的文檔。

            BigTable 的列簇式存儲

            HBase 和 Cassandra 的數據模型都借鑒自 Google 的 BigTable。這種數據模型的特點是列式存儲,每一行數據的各項被存儲在不同的列中(這些列的集合稱作列簇)。而每一列中每一個數據都包含一個時間戳 屬性,這樣列中的同一個數據項的多個版本都能保存下來。

            列式存儲可以這樣理解:將行 ID、列簇號,列號以及時間戳一起,組成一個 Key,然后將 Value 按 Key 的順序進行存儲。Key 值的結構化使這種數據結構能夠實現一些特別的功能,最常用的就是將一個數據的多個版本存成時間戳不同的幾個值,這樣就能方便地保存歷史數據。這種結構也能 天然地進行高效的松散列數據(在很多行中并沒有某列的數據)存儲。當然,對于那些很少有某一行有 NULL 值的列,由于每一個數據必須包含列標識,這又會造成空間的浪費。

            圖結構存儲

            圖結構存儲是 NoSQL 的另一種存儲實現。其指導思想是:數據并非對等的,關系型的存儲或者鍵值對的存儲,可能都不是最好的存儲方式。圖結構是計算機科學的基礎結構之一,Neo4j 和 HyperGraphDB 是當前最流行的圖結構數據庫。

            復雜查詢

            在 NoSQL 存儲系統中,有很多比鍵值查找更復雜的操作。比如 MongoDB 可以在任意數據行上建立索引,可以使用 Javascript 語法設定復雜的查詢條件。BigTable 型的系統通常支持對單獨某一行的數據進行遍歷,允許對單列的數據進行按特定條件的篩選。CouchDB 允許你創建同一份數據的多個視圖,通過運行 MapReduce 任務來實現一些更為復雜的查詢或者更新操作。很多 NoSQL 系統都支持與 Hadoop 或者其他 MapReduce 框架結合來進行一些大規模數據分析工作。

            事務機制

            與關系型數據庫不同的是,NoSQL 系統通常注重性能和擴展性,而非事務機制。傳統的 SQL 數據庫的事務通常都是支持 ACID 的強事務機制。ACID 的支持使得應用者能夠很清楚他們當前的數據狀態。對很多 NoSQL 系統來說,對性能的考慮遠在 ACID 的保證之上。通常 NoSQL 系統僅提供行級別的原子性保證,也就是說同時對同一個 Key 下的數據進行的兩個操作,在實際執行時是會串行的,保證了每一個 Key-Value 對不會被破壞。

            Schema-free 的存儲

            還有一個很多 NoSQL 的共同點,就是它通常并沒有強制的數據結構約束。即使是在文檔型存儲或者列式存儲上,也不會要求某一個數據列在每一行數據上都必須存在。

            數據可靠性

            最理想的狀態是,數據庫會把所有寫操作立刻寫到持久化存儲的設備,同時復制多個副本到不同地理位置的不同節點上,以防止數據丟失。但這種對數據安全性的要求對性能是有影響的,所以不同的 NoSQL 系統在自身性能的考慮下,在數據安全上采取了不太一樣的策略。

            單機可靠性

            單機可靠性理解起來非常簡單,它的定義是寫操作不會由于機器重啟或者斷電而丟失。通常單機可靠性的保證是通過把數據寫到磁盤來完成的,而這通常會造成磁盤I/O成為整個系統的瓶頸。下面我們談談一些在單機可靠性的保證下提高性能的方法。

            控制fsync的調用頻率

            Redis 提供了幾種對 fsync 調用頻率的控制方法。應用開發者可以配置 Redis 在每次更新操作后都執行一次 fsync,這樣會比較安全,當然也就比較慢。Redis 也可以設置成N秒種調用一次 fsync,這樣性能會更好一點。但這樣的后果就是一旦出現故障,最多可能導致N秒內的數據丟失。而對一些可靠性要求不太高的場合(比如僅僅把 Redis 當 Cache 用的時候),應用開發者甚至可以直接關掉 fsync 的調用:讓操作系統來決定什么時候需要把數據 flush 到磁盤(譯者注:這只是 Redis append only file 的機制,Redis 是可以關閉 aof 日志的,另外,Redis 本身支持將內存中數據 dump 成 rdb 文件的機制,和上面說的不是一回事)。

           使用日志型的數據結構

            Cassandra、HBase、Redis 和 Riak 都會把寫操作順序的寫入到一個日志文件中。相對于存儲系統中的其他數據結構,上面說到的日志文件可以頻繁地進行 fsync 操作,這樣就把對磁盤的隨機寫變成順序寫了。

            通過合并寫操作提高吞吐性能

            Cassandra 有一個機制,它會把一小段時間內的幾個并發的寫操作放在一起進行一次 fsync 調用,這種做法叫 group commit。

            多機可靠性

            由于硬件層面有時會造成無法恢復的損壞,單機可靠性的保證在這時就鞭長莫及了。對于一些重要數據,跨機器做備份保存是必備的安全措施。一些 NoSQL 系統提供了多機可靠性的支持。

            Redis 采用傳統的主從數據同步的方式。

            MongoDB 提供了一種叫 Replica Sets 高可用架構。

            Riak、Cassandra 和 Voldemort 提供了一些更靈活的可配置策略,并提供一個可配置的參數N,代表每一個數據會被備份的份數。為了應對整個數據中心出現故障的情況,需要實現跨數據中心的多機備份功能。

            橫向擴展帶來性能提升

            橫向擴展的目標是達到線性的效果,即如果你增加一倍的機器,那么負載能力應該也能相應的增加一倍。其主要需要解決的問題是如何讓數據在多臺機器間分布,這里面涉及到分片技術。

            分片的意思,就是沒有任何一臺機器可以處理所有寫請求,也沒有任何一臺機器可以處理對所有數據的讀請求。下面我們將會對 hash 分片和范圍分片兩種分片方式進行描述。

            如非必要,請勿分片

            分片會導致系統復雜程度大增,所以,如果沒有必要,請不要使用分片。普通情況下,我們可以使用讀寫分離和構建緩存的方式來緩解我們的數據讀壓力。但如果寫操作達到單點無法承擔的程度,那我們可能就真的需要進行分片了。

            通過協調器進行數據分片

            一種分片策略是通過引入一個中間代理層來實現,該代理層記錄數據在各個節點的分布狀況,所有讀寫請求都通過代理層來做路由。比如與 CouchDB 的兩個項目:Lounge 和 BigCouch。類似的,Twitter 自己也實現了一個叫 Gizzard 的協調器,可以實現數據分片和備份功能。

            一致性 hash 環算法

            一致性 hash 是一種被廣泛應用的技術,其最早在一個叫 distributed hash tables(DHTs)的系統中進行使用。那些類 Dynamo 的應用,比如 Cassandra、Voldemort 和 Riak,基本上都使用了一致性 hash 環算法。

            如圖 1 所示,一致性 hash 環算法有一個 hash 函數H,所有存儲數據的節點和數據本身都可以通過這個函數算出一個 hash 值,作為自己在下面環上的位置。然后每個節點會負責存儲其 hash 值到下一個節點間的所有數據的存儲。這樣使得即使節點數變化了,大部分數據并不需要進行遷移。

          圖 1 一致性 hash 環算法的 hash 函數

          連續范圍分區

            使用連續范圍分區的方法進行數據分片,需要我們保存一份映射關系表,標明哪一段 Key 值對應存在哪臺機器上。與一致性 hash 類似,連續范圍分區會把 Key 值按連續的范圍分段,每段數據會被指定保存在某個節點上,然后會被冗余備份到其他節點。

            BigTable 的處理方式

            Google BigTable 論文中描述了一種范圍分區方式,它將數據切分成一個個的 tablet 數據塊。每個 tablet 保存一定數量的鍵值對。然后存儲在 Tablet 服務器上。tablet 塊的大小會保持在一定范圍,太大的塊會分裂成兩個,太小的塊又會合并成一個。BigTable 通過一個叫 Chubby 的模塊來實現節點狀態檢測。類似的在 Hadoop 中有一個叫 ZooKeeper 的工具實現此功能。

            一致性

            上面講到了通過將數據冗余存儲到不同的節點來保證數據安全和減輕負載,下面我們來看看這樣做引發的一個問題:保證數據在多個節點間的一致性是非常困難的。在多個點間保持數據的一致性的問題,也就是本章的主題。下面我們首先來看一下在著名的 CAP 理論。

            一致性(C):在分布式系統中的所有數據備份,在同一時刻是否同樣的值。

            可用性(A):在集群中一部分節點故障后,集群整體是否還能響應客戶端的讀寫請求。

            分區容忍性(P):集群中的某些節點在無法聯系后,集群整體是否還能繼續進行服務。

            而 CAP 理論就是說在分布式存儲系統中,最多只能實現上面的兩點。再加之當前的網絡硬件肯定會出現延遲丟包等問題,所以分區容忍性是我們必須需要實現的。結果就是我們只能在一致性和可用性之間進行權衡,沒有 NoSQL 系統能同時保證這三點。

            對一致性的保證,通常有強一致性和弱一致性的選擇,而在弱一致性里,又以最終一致性的實現較為普遍。

            如果我們采用 NRW 的設定,N為數據需要備份的份數,R為讀操作需要讀到的不同節點上的數據份數,W為寫操作需要成功寫到不同節點的數據份數,那么當R+W>N時,既 是強一致性的保證,當R+W

            寫在最后的話

            目前 NoSQL 系統來處在它的萌芽期,我們上面討論到的很多 NoSQL 系統,它們的架構、設計和接口可能都會改變。本章的目的,不在于讓你了解這些 NoSQL 系統目前是如何工作的,而在于讓你理解這些系統之所以這樣實現的原因。NoSQL 系統把更多的設計工作留給了應用開發工作者來做。理解上面這些組件的架構,不僅能讓你寫出下一個 NoSQL 系統,更讓你對現有系統應用得更好。



          posted on 2011-12-13 15:28 順其自然EVO 閱讀(144) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          <2011年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 乌拉特前旗| 新疆| 芷江| 定远县| 南溪县| 苍山县| 历史| 遂宁市| 藁城市| 呼和浩特市| 托克逊县| 丰镇市| 安庆市| 金湖县| 鹰潭市| 桦南县| 庄河市| 敦煌市| 九龙县| 穆棱市| 轮台县| 米脂县| 恩平市| 乌拉特中旗| 卫辉市| 东光县| 屏山县| 化德县| 柘城县| 南投县| 孝感市| 马边| 新干县| 咸宁市| 灵山县| 兴城市| 河南省| 沙坪坝区| 鄯善县| 三明市| 宜昌市|