大規模分佈式存儲系統:原理解析與架構實戰
楊傳輝前端
分佈式系統的數據量遠遠超出了單個計算機的存儲和處理能力。程序員
一個2億用戶的電信運營商,若是平均每一個用戶天天撥打接聽總共10個電話,每一個電話400字節,5年的話費記錄總量即爲0.2G×10×0.4K×365×5=1.46PB。除了分佈式系統,人們還很難有其餘高效的手段來存儲和處理這些PB級甚至更多的數據。算法
單機和分佈式有兩個明顯的不一樣:數據庫
首先,分佈式環境下會出現一部分計算機工做正常,另外一部分計算機工做不正常的狀況,程序須要在這種狀況下儘量地正常工做,這個挑戰很是大。
其次,單機環境下的函數調用經常能夠在微秒級內返回,因此除了少數訪問外部設備(例如磁盤、網卡等)的函數採用異步方式調用外,大部分函數採用同步調用的方式,編譯器和操做系統在調用先後自動保存與恢復程序的上下文;在分佈式環境下,計算機之間的函數調用(遠程調用,即RPC)的返回時間一般是毫秒或亞毫秒(0.1~1.0毫秒)級,差很少是單機環境的100倍,使用同步方式遠遠不能發揮現代CPU處理器的性能,因此分佈式環境下的RPC一般採用異步調用方式,程序須要本身保存和恢復調用先後的上下文,並須要處理更多的異常。編程
著名公司後端
爲了處理這些海量內容,每一個互聯網公司在後端都有一套成熟的分佈式系統用於數據的存儲、計算以及價值提取。
Google的核心技術正是後端這些處理海量數據的分佈式系統。和Google相似,國外的亞馬遜、微軟以及國內互聯網三巨頭阿里巴巴、百度和騰訊的核心技術也是其後端的海量數據處理系統。
互聯網公司的分佈式存儲系統由數量衆多的、低成本和高性價比的普通PC服務器經過網絡鏈接而成。緩存
本書做者2007年年末加入百度公司,從事大規模分佈式存儲的研究和實踐工做,曾經開發過相似GFS、MapReduce和Bigtable的分佈式系統,後來轉戰阿里巴巴繼續開發分佈式數據庫OceanBase。安全
分佈式存儲是基礎,雲存儲和大數據是構建在分佈式存儲之上的應用。服務器
移動終端的計算能力和存儲空間有限,並且有在多個設備之間共享資源的強烈的需求,這就使得網盤、相冊等雲存儲應用很快流行起來。雲存儲的核心仍是後端的大規模分佈式存儲系統。
大數據則更近一步,不只須要存儲海量數據,還須要經過合適的計算框架或者工具對這些數據進行分析,抽取其中有價值的部分。若是沒有分佈式存儲,便談不上對大數據進行分析。網絡
分佈式存儲系統
分佈式存儲系統能夠擴展到幾百臺甚至幾千臺的集羣規模,並且,隨着集羣規模的增加,系統總體性能表現爲線性增加。
分佈式存儲系統的挑戰主要在於數據、狀態信息的持久化,要求在自動遷移、自動容錯、併發讀寫的過程當中保證數據的一致性。
分佈式存儲涉及的技術主要有:
數據分佈:如何將數據分佈到多臺服務器纔可以保證數據分佈均勻
一致性:如何將數據的多個副本複製到多臺服務器,即便在異常狀況下,也可以保證不一樣副本之間的數據一致性
容錯:檢測服務器故障並自動將出現故障的服務器上的數據和服務遷移到集羣中的其餘服務器
負載均衡:新增服務器和集羣運行中實現負載均衡
分佈式事務,多版本併發控制
數據分類
非結構化數據:包括全部格式的辦公文檔、文本、圖片、圖像、音頻和視頻信息等。
結構化數據:通常存儲在關係數據庫中,能夠用二維關係表結構來表示。結構化數據的模式(Schema,包括屬性、數據類型以及數據之間的聯繫)和內容是分開的,數據的模式須要預先定義。
不一樣的分佈式存儲系統適合處理不一樣類型的數據
分佈式存儲系統分爲四類:
一、分佈式文件系統
互聯網應用須要存儲大量的圖片、照片、視頻等非結構化數據對象,這類數據以對象的形式組織,對象之間沒有關聯,這樣的數據通常稱爲Blob(Binary Large Object,二進制大對象)數據。分佈式文件系統用於存儲Blob對象。
在系統實現層面,分佈式文件系統內部按照數據塊(chunk)來組織數據
二、分佈式鍵值系統
分佈式鍵值系統用於存儲關係簡單的半結構化數據,它只提供基於主鍵的CRUD(Create/Read/Update/Delete)功能,即根據主鍵建立、讀取、更新或者刪除一條鍵值記錄。
從數據結構的角度看,分佈式鍵值系統與傳統的哈希表比較相似,不一樣的是,分佈式鍵值系統支持將數據分佈到集羣中的多個存儲節點。
通常用做緩存,好比Memcache。
一致性哈希是分佈式鍵值系統中經常使用的數據分佈技術。
三、分佈式表格系統
分佈式表格系統用於存儲關係較爲複雜的半結構化數據,與分佈式鍵值系統相比,分佈式表格系統不只僅支持簡單的CRUD操做,並且支持掃描某個主鍵範圍。分佈式表格系統以表格爲單位組織數據,每一個表格包括不少行,經過主鍵標識一行,支持根據主鍵的CRUD功能以及範圍查找功能。
分佈式表格系統借鑑了不少關係數據庫的技術,例如支持某種程度上的事務。
與分佈式數據庫相比,分佈式表格系統主要支持針對單張表格的操做,不支持一些特別複雜的操做,好比多表關聯,多表聯接,嵌套子查詢;另外,在分佈式表格系統中,同一個表格的多個數據行也不要求包含相同類型的列,適合半結構化數據。
四、分佈式數據庫
分佈式數據庫通常是從單機關係數據庫擴展而來,用於存儲結構化數據。分佈式數據庫採用二維表格組織數據,提供SQL關係查詢語言,支持多表關聯,嵌套子查詢等複雜操做,並提供數據庫事務以及併發控制。
典型的系統包括MySQL數據庫分片(MySQL Sharding)集羣,阿里巴巴OceanBase系統也是一個支持自動擴展的分佈式關係數據庫。
存儲引擎
存儲引擎就是哈希表、B樹等數據結構在機械磁盤、SSD等持久化介質上的實現。單機存儲系統是單機存儲引擎的一種封裝,對外提供文件、鍵值、表格或者關係模型。
哈希存儲引擎是哈希表的持久化實現,……
數據庫將一個或多個操做組成一組,稱做事務,事務必須知足原子性、一致性、隔離性以及持久性。
爲了保證持久性,對於數據庫的每個變化都要在磁盤上記錄日誌,當數據庫系統忽然發生故障,重啓後可以恢復到以前一致的狀態。
摩爾定律:每18個月計算機等IT產品的性能會翻一番;或者說相同性能的計算機等IT產品,每18個月價錢會降一半。
早期的CPU爲單核芯片,現代服務器基本爲多核或多個CPU
經典的多CPU架構爲對稱多處理結構,即在一個計算機上聚集了一組處理器,它們之間對稱工做,無主次或從屬關係,共享相同的物理內存及總線。
SMP系統的每一個CPU有兩個核心(core),CPU與內存之間經過總線通訊。每一個核心有各自的L1d Cache(L1數據緩存)及L1i Cache(L1指令緩存),同一個CPU的多個核心共享L2以及L3緩存。
某些CPU還能夠經過超線程技術(Hyper-Threading Technology)使得一個核心具備同時執行兩個線程的能力。
如今的主流服務器架構通常爲NUMA(Non-Uniform Memory Access,非一致存儲訪問)架構。它具備多個NUMA節點,每一個NUMA節點是一個SMP結構,通常由多個CPU(如4個)組成,而且具備獨立的本地內存、IO槽口等。NUMA節點能夠直接快速訪問本地內存,也能夠經過NUMA互聯互通模塊訪問其餘NUMA節點的內存。
以Intel x48主板爲例,它是典型的南、北橋架構。北橋芯片經過前端總線(Front Side Bus,FSB)與CPU相連,內存模塊以及PCI-E設備(如高端的SSD設備Fusion-IO)掛接在北橋上
網卡(包括千兆以及萬兆網卡),硬盤以及中低端固態盤(如Intel 320系列SSD)掛接在南橋上。
傳統的數據中心網絡拓撲
接入層交換機、匯聚層以及核心層的交換機。
因爲同一個接入層的服務器每每部署在一個機架內,所以,設計系統的時候須要考慮服務器是否在一個機架內,減小跨機架拷貝大量數據。例如,Hadoop HDFS默認存儲三個副本,其中兩個副本放在同一個機架,就是這個緣由。
Google在2008年的時候將網絡改造爲扁平化拓撲結構,即三級CLOS網絡,同一個集羣內最多支持20480臺服務器,且任何兩臺都有1Gb帶寬。CLOS網絡須要額外投入更多的交換機,帶來的好處也是明顯的,設計系統時不須要考慮底層網絡拓撲,從而很方便地將整個集羣作成一個計算資源池。
同一個數據中心內部的傳輸延時是比較小的,網絡一次來回的時間在1毫秒以內。數據中心之間的傳輸延遲是很大的,取決於光在光纖中的傳輸時間。例如,北京與杭州之間的直線距離大約爲1300千米,光在信息傳輸中走折線,假設折線距離爲直線距離的1.5倍,那麼光傳輸一次網絡來回延時的理論值爲1300×1.5×2/300000=13毫秒,實際測試值大約爲40毫秒。
存儲系統的性能瓶頸通常在於IO。順序讀取1MB數據的時間爲:磁盤尋道時間+數據讀取時間,即10ms+1MB/100MB/s×1000=20ms。存儲系統的性能瓶頸主要在於磁盤隨機讀寫。
固態磁盤(SSD),各大互聯網公司都有大量基於SSD的應用。SSD的特色是隨機讀取延遲小,可以提供很高的IOPS(每秒讀寫,Input/Output Per Second)性能;主要問題在於容量和價格。
磁盤適合大塊順序訪問的存儲系統,SSD適合隨機訪問較多或者對延時比較敏感的關鍵系統。
從分佈式系統的角度看,整個集羣中全部服務器上的存儲介質(內存、機械硬盤,SSD)構成一個總體,其餘服務器上的存儲介質與本機存儲介質同樣都是可訪問的,區別僅僅在於須要額外的網絡傳輸及網絡協議棧等訪問開銷
集羣中有30個機架,每一個機架接入40臺服務器,同一個機架的服務器接入到同一個接入交換機,不一樣機架的服務器接入到不一樣的接入交換機。
哈希存儲引擎不支持順序掃描
B樹(B-Tree)存儲引擎支持順序掃描,對應的存儲系統是關係數據庫。
LSM樹(Log-Structured Merge Tree)存儲引擎和B樹存儲引擎同樣,支持增、刪、改、隨機讀取以及順序掃描。它經過批量轉儲技術規避磁盤隨機寫入問題,普遍應用於互聯網的後臺存儲系統,例如Google Bigtable、Google LevelDB以及Facebook開源的Cassandra系統
Bitcask是一個基於哈希表結構的鍵值存儲系統,它僅支持追加操做(Append-only),即全部的寫操做只追加而不修改老的數據。在Bitcask系統中,每一個文件有必定的大小限制,當文件增長到相應的大小時,就會產生一個新的文件,老的文件只讀不寫。在任意時刻,只有一個文件是可寫的,用於數據追加,稱爲活躍數據文件。
Bitcask數據文件中的數據是一條一條的寫入操做,每一條記錄的數據項分別爲主鍵(key)、value內容(value)、主鍵長度(key_sz)、value長度(value_sz)、時間戳(timestamp)以及crc校驗值。(數據刪除操做也不會刪除舊的條目,而是將value設定爲一個特殊的值用做標識)。內存中採用基於哈希表的索引數據結構,哈希表的做用是經過主鍵快速地定位到value的位置。哈希表結構中的每一項包含了三個用於定位數據的信息,分別是文件編號(file id),value在文件中的位置(value_pos),value長度(value_sz),經過讀取file_id對應文件的value_pos開始的value_sz個字節,這就獲得了最終的value值。寫入時首先將Key-Value記錄追加到活躍數據文件的末尾,接着更新內存哈希表,所以,每一個寫操做總共須要進行一次順序的磁盤寫入和一次內存操做。
系統基於一個假設,value的長度遠大於主鍵的長度。假如value的平均長度爲1KB,每條記錄在內存中的索引信息爲32字節,那麼,磁盤內存比爲32:1。這樣,32GB內存索引的數據量爲32GB×32=1TB。
Bitcask系統中的記錄刪除或者更新後,原來的記錄成爲垃圾數據。若是這些數據一直保存下去,文件會無限膨脹下去,爲了解決這個問題,Bitcask須要按期執行合併(Compaction)操做以實現垃圾回收。所謂合併操做,即將全部老數據文件中的數據掃描一遍並生成新的數據文件,這裏的合併其實就是對同一個key的多個操做以只保留最新一個的原則進行刪除,每次合併後,新生成的數據文件就再也不有冗餘數據了。
Bitcask系統中的哈希索引存儲在內存中,若是不作額外的工做,服務器斷電重啓重建哈希表須要掃描一遍數據文件,若是數據文件很大,這是一個很是耗時的過程。Bitcask經過索引文件(hint file)來提升重建哈希表的速度。索引文件就是將內存中的哈希索引錶轉儲到磁盤生成的結果文件。
相比哈希存儲引擎,B樹存儲引擎不只支持隨機讀取,還支持範圍掃描
葉子節點保存每行的完整數據
B+樹一次檢索最多須要h-1次磁盤IO,複雜度爲O(h)=O(logdN)(N爲元素個數,d爲每一個節點的出度,h爲B+樹高度)
修改操做首先須要記錄提交日誌,接着修改內存中的B+樹。若是內存中的被修改過的頁面超過必定的比率,後臺線程會將這些頁面刷到磁盤中持久化
緩衝區管理器負責將可用的內存劃分紅緩衝區,緩衝區是與頁面同等大小的區域,磁盤塊的內容能夠傳送到緩衝區中。緩衝區管理器的關鍵在於替換策略,即選擇將哪些頁面淘汰出緩衝池。
LSM樹(Log Structured Merge Tree)的思想很是樸素,就是將對數據的修改增量保持在內存中,達到指定的大小限制後將這些修改操做批量寫入磁盤,讀取時須要合併磁盤中的歷史數據和內存中最近的修改操做。LSM樹的優點在於有效地規避了磁盤隨機寫入問題,但讀取時可能須要訪問較多的磁盤文件
LevelDB存儲引擎主要包括:內存中的MemTable和不可變MemTable(Immutable MemTable,也稱爲Frozen MemTable,即凍結MemTable)以及磁盤上的幾種主要文件:當前(Current)文件、清單(Manifest)文件、操做日誌(Commit Log,也稱爲提交日誌)文件以及SSTable文件。當應用寫入一條記錄時,LevelDB會首先將修改操做寫入到操做日誌文件,成功後再將修改操做應用到MemTable,這樣就完成了寫入操做。
當MemTable佔用的內存達到一個上限值後,須要將內存的數據轉儲到外存文件中。LevelDB會將原先的MemTable凍結成爲不可變MemTable,並生成一個新的MemTable。新到來的數據被記入新的操做日誌文件和新生成的MemTable中。顧名思義,不可變MemTable的內容是不可更改的,只能讀取不能寫入或者刪除。LevelDB後臺線程會將不可變MemTable的數據排序後轉儲到磁盤,造成一個新的SSTable文件,這個操做稱爲Compaction。SSTable文件是內存中的數據不斷進行Compaction操做後造成的,且SSTable的全部文件是一種層級結構,第0層爲Level 0,第1層爲Level 1,以此類推。
SSTable中的文件是按照記錄的主鍵排序的,每一個文件有最小的主鍵和最大的主鍵。LevelDB的清單文件記錄了這些元數據,包括屬於哪一個層級、文件名稱、最小主鍵和最大主鍵。當前文件記錄了當前使用的清單文件名。在LevelDB的運行過程當中,隨着Compaction的進行,SSTable文件會發生變化,新的文件會產生,老的文件被廢棄,此時每每會生成新的清單文件來記載這種變化,而當前文件則用來指出哪一個清單文件纔是當前有效的。
直觀上,LevelDB每次查詢都須要從老到新讀取每一個層級的SSTable文件以及內存中的MemTable。LevelDB作了一個優化,因爲LevelDB對外只支持隨機讀取單條記錄,查詢時LevelDB首先會去查看內存中的MemTable,若是MemTable包含記錄的主鍵及其對應的值,則返回記錄便可;若是MemTable沒有讀到該主鍵,則接下來到一樣處於內存中的不可變Memtable中去讀取;相似地,若是仍是沒有讀到,只能依次重新到老讀取磁盤中的SSTable文件。
數據模型
文件、關係以及隨着NoSQL技術流行起來的鍵值模型、關係弱化的表格模型
文件系統以目錄樹的形式組織文件,以類UNIX操做系統爲例,根目錄爲/,包含/usr、/bin、/home等子目錄,每一個子目錄又包含其餘子目錄或者文件
POSIX(Portable Operating System Interface)是應用程序訪問文件系統的API標準,它定義了文件系統存儲接口及操做集。
POSIX標準適合單機文件系統,在分佈式文件系統中,出於性能考慮,通常不會徹底遵照這個標準。NFS(Network File System)文件系統容許客戶端緩存文件數據,多個客戶端併發修改同一個文件時可能出現不一致的狀況。舉個例子,NFS客戶端A和B須要同時修改NFS服務器的某個文件,每一個客戶端都在本地緩存了文件的副本,A修改後先提交,B後提交,那麼,即便A和B修改的是文件的不一樣位置,也會出現B的修改覆蓋A的狀況。
對象模型與文件模型比較相似,用於存儲圖片、視頻、文檔等二進制數據塊,典型的系統包括Amazon Simple Storage(S3),Taobao File System(TFS)。這些系統弱化了目錄樹的概念,Amazon S3只支持一級目錄,不支持子目錄,Taobao TFS甚至不支持目錄結構。與文件模型不一樣的是,對象模型要求對象一次性寫入到系統,只能刪除整個對象,不容許修改其中某個部分。
SQL查詢還有一個強大的特性是容許在WHERE、FROM和HAVING子句中使用子查詢,子查詢又是一個完整的select-from-where語句。
大量的NoSQL系統採用了鍵值模型(也稱爲Key-Value模型),Key-Value模型過於簡單,支持的應用場景有限,NoSQL系統中使用比較普遍的模型是表格模型。
表格模型弱化了關係模型中的多表關聯,支持基於單表的簡單操做,典型的系統是Google Bigtable以及其開源Java實現HBase。表格模型除了支持簡單的基於主鍵的操做,還支持範圍掃描,另外,也支持基於列的操做。與關係模型不一樣的是,表格模型通常不支持多表關聯操做,Bigtable這樣的系統也不支持二級索引,事務操做支持也比較弱,各個系統支持的功能差別較大,沒有統一的標準。另外,表格模型每每還支持無模式(schema-less)特性,也就是說,不須要預先定義每行包括哪些列以及每一個列的類型,多行之間容許包含不一樣列。
關係數據庫在海量數據場景面臨以下挑戰:一、事務關係模型要求多個SQL操做知足ACID特性,全部的SQL操做要麼所有成功,要麼所有失敗。在分佈式系統中,若是多個操做屬於不一樣的服務器,保證它們的原子性須要用到兩階段提交協議,而這個協議的性能很低,且不能容忍服務器故障,很難應用在海量數據場景。二、聯表傳統的數據庫設計時須要知足範式要求,例如,第三範式要求在一個關係中不能出如今其餘關係中已包含的非主鍵信息。假設存在一個部門信息表,其中每一個部門有部門編號、部門名稱、部門簡介等信息,那麼在員工信息表中列出部門編號後就不能加入部門名稱、部門簡介等部門有關的信息,不然就會有大量的數據冗餘。而在海量數據的場景,爲了不數據庫多表關聯操做,每每會使用數據冗餘等違反數據庫範式的手段。實踐代表,這些手段帶來的收益遠高於成本。
關係數據庫採用B樹存儲引擎,更新操做性能不如LSM樹這樣的存儲引擎。另外,若是隻有基於主鍵的增、刪、查、改操做,關係數據庫的性能也不如專門定製的Key-Value存儲系統。
數據庫事務具備原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)以及持久性(Durability)
多個事務併發執行時,若是它們的執行結果和按照某種順序一個接着一個串行執行的效果等同,這種隔離級別稱爲可串行化。可串行化是比較理想的狀況,商業數據庫爲了性能考慮,每每會定義多種隔離級別。事務的併發控制通常經過鎖機制來實現,鎖能夠有不一樣的粒度,能夠鎖住行,也能夠鎖住數據塊甚至鎖住整個表格
爲了提升讀事務性能,能夠採用寫時複製(Copy-On-Write,COW)或者多版本併發控制(Multi-Version Concurrency Control,MVCC)技術來避免寫事務阻塞讀事務。
原子性,事務的原子性也體如今事務對數據的讀取上,例如,一個事務對同一數據項的屢次讀取的結果必定是相同的。
一致性,事務須要保持數據庫數據的正確性、完整性和一致性,通常狀況下銀行帳務餘額不能是負數,信用卡消費不能超過該卡的信用額度等。
隔離性,數據庫須要保證每個事務在它的修改所有完成以前,對其餘的事務是不可見的,換句話說,不能讓其餘事務看到該事務的中間狀態。從銀行帳戶A轉一筆款項a到帳戶B,不能讓其餘事務(例如帳戶查詢)看到A帳戶已經扣除款項a但B帳戶卻尚未增長款項a的狀態。
永久性,事務完成後,它對於數據庫的影響是永久性的,即便系統出現各類異常也是如此。
出於性能考慮,許多數據庫容許使用者選擇犧牲隔離屬性來換取併發度,從而得到性能的提高。SQL定義了4種隔離級別。
隔離級別的下降可能致使讀到髒數據或者事務執行異常
鎖也分爲兩種類型:讀鎖以及寫鎖,容許對同一個元素加多個讀鎖,但只容許加一個寫鎖,且寫事務將阻塞讀事務。這裏的元素能夠是一行,也能夠是一個數據塊甚至一個表格
T1和T2兩個事務操做不一樣行,初始時A=B=25,T1將A加100,T2將B乘以2,因爲T1和T2操做不一樣行,兩個事務沒有鎖衝突,能夠並行執行而不會破壞系統的一致性。
T1掃描從A到C的全部行,將它們的結果相加後更新A,初始時A=C=25,假設在T1執行過程當中T2插入一行B,那麼,事務T1和T2沒法作到可串行化。爲了保證數據庫一致性,T1執行範圍掃描時須要鎖住從A到C這個範圍的全部更新,T2插入B時,因爲整個範圍被鎖住,T2獲取鎖失敗而等待T1先執行完成。
多個事務併發執行可能引入死鎖。表2-6中T1讀取A,而後將A的值加100後更新B,T2讀取B,而後將B的值乘以2更新A,初始時A=B=25。T1持有A的讀鎖,須要獲取B的寫鎖,而T2持有B的讀鎖,須要A的寫鎖。T1和T2這兩個事務循環依賴,任何一個事務都沒法順利完成。
解決死鎖的思路主要有兩種:第一種思路是爲每一個事務設置一個超時時間,超時後自動回滾,表2-6中若是T1或T2兩者之中的某個事務回滾,則另一個事務能夠成功執行。第二種思路是死鎖檢測。死鎖出現的緣由在於事務之間互相依賴,T1依賴T2,T2又依賴T1,依賴關係構成一個環路。檢測到死鎖後能夠經過回滾其中某些事務來消除循環依賴。
互聯網業務中讀事務佔的比例每每遠遠超過寫事務,不少應用的讀寫比例達到6:1,甚至10:1。寫時複製(Copy-On-Write,COW)讀操做不用加鎖,極大地提升了讀取性能。
1)拷貝:將從葉子到根節點路徑上的全部節點拷貝出來。 2)修改:對拷貝的節點執行修改。 3)提交:原子地切換根節點的指針,使之指向新的根節點。
若是讀操做發生在第3步提交以前,那麼,將讀取老節點的數據,不然將讀取新節點,讀操做不須要加鎖保護
寫時複製技術涉及引用計數,對每一個節點維護一個引用計數,表示被多少節點引用,若是引用計數變爲0,說明沒有節點引用,能夠被垃圾回收。
寫時複製技術原理簡單,問題是每次寫操做都須要拷貝從葉子到根節點路徑上的全部節點,寫操做成本高
除了寫時複製技術,多版本併發控制,即MVCC(Multi-Version Concurrency Control),也可以實現讀事務不加鎖。MVCC對每行數據維護多個版本,不管事務的執行時間有多長,MVCC老是可以提供與事務開始時刻相一致的數據。
以MySQL InnoDB存儲引擎爲例,InnoDB對每一行維護了兩個隱含的列,其中一列存儲行被修改的「時間」,另一列存儲行被刪除的「時間」,注意,InnoDB存儲的並非絕對時間,而是與時間對應的數據庫系統的版本號,每當一個事務開始時,InnoDB都會給這個事務分配一個遞增的版本號,因此版本號也能夠被認爲是事務號。對於每一行查詢語句,InnoDB都會把這個查詢語句的版本號同這個查詢語句遇到的行的版本號進行對比,而後結合不一樣的事務隔離級別,來決定是否返回改行。
若是行的修改或者刪除版本號大於事務號,說明行是被該事務後面啓動的事務修改或者刪除的。在可重複讀取隔離級別下,後開始的事務對數據的影響不該該被先開始的事務看見,因此應該忽略後開始的事務的更新或者刪除操做。
MVCC讀取數據的時候不用加鎖,每一個查詢都經過版本檢查,只得到本身須要的數據版本,從而大大提升了系統的併發度。固然,爲了實現多版本,必須對每行存儲額外的多個版本的數據。另外,MVCC存儲引擎還必須按期刪除再也不須要的版本,及時回收空間。
故障恢復
數據庫運行過程當中可能會發生故障,這個時候某些事務可能執行到一半但沒有提交,當系統重啓時,須要可以恢復到一致的狀態,即要麼提交整個事務,要麼回滾。數據庫系統以及其餘的分佈式存儲系統通常採用操做日誌(有時也稱爲提交日誌,即Commit Log)技術來實現故障恢復。操做日誌分爲回滾日誌(UNDO Log)、重作日誌(REDO Log)以及UNDO/REDO日誌。
爲了保證數據庫的一致性,數據庫操做須要持久化到磁盤,若是每次操做都隨機更新磁盤的某個數據塊,系統性能將會不好。所以,經過操做日誌順序記錄每一個數據庫操做並在內存中執行這些操做,內存中的數據按期刷新到磁盤,實現將隨機寫請求轉化爲順序寫請求。
操做日誌記錄了事務的操做。例如,事務T對錶格中的X執行加10操做,初始時X=5,更新後X=15,那麼,UNDO日誌記爲<T,X,5>,REDO日誌記爲<T,X,15>,UNDO/REDO日誌記爲<T,X,5,15>。關係數據庫系統通常採用UNDO/REDO日誌。
存儲系統若是採用REDO日誌,其寫操做流程以下: 1)將REDO日誌以追加寫的方式寫入磁盤的日誌文件。 2)將REDO日誌的修改操做應用到內存中。 3)返回操做成功或者失敗。
存儲系統要求先將REDO日誌刷入磁盤才能夠更新內存中的數據,若是每一個事務都要求將日誌當即刷入磁盤,系統的吞吐量將會不好。所以,存儲系統每每有一個是否當即刷入磁盤的選項,對於一致性要求很高的應用,能夠設置爲當即刷入;相應地,對於一致性要求不過高的應用,能夠設置爲不要求當即刷入,首先將REDO日誌緩存到操做系統或者存儲系統的內存緩衝區中,按期刷入磁盤。這種作法有一個問題,若是存儲系統意外故障,可能丟失最後一部分更新操做。
成組提交(Group Commit)技術是一種有效的優化手段。REDO日誌首先寫入到存儲系統的日誌緩衝區中: a)日誌緩衝區中的數據量超過必定大小,好比512KB; b)距離上次刷入磁盤超過必定時間,好比10ms。當知足以上兩個條件中的某一個時,將日誌緩衝區中的多個事務操做一次性刷入磁盤,接着一次性將多個事務的修改操做應用到內存中並逐個返回客戶端操做結果。與按期刷入磁盤不一樣的是,成組提交技術保證REDO日誌成功刷入磁盤後才返回寫操做成功。這種作法可能會犧牲寫事務的延時,但大大提升了系統的吞吐量。
若是全部的數據都保存在內存中,那麼可能出現兩個問題: ●故障恢復時須要回放全部的REDO日誌,效率較低。若是REDO日誌較多,好比超過100GB,那麼,故障恢復時間是沒法接受的。 ●內存不足
所以,須要將內存中的數據按期轉儲(Dump)到磁盤,這種技術稱爲checkpoint(檢查點)技術。系統按期將內存中的操做以某種易於加載的形式(checkpoint文件)轉儲到磁盤中,並記錄checkpoint時刻的日誌回放點,之後故障恢復只須要回放checkpoint時刻的日誌回放點以後的REDO日誌。因爲將內存數據轉儲到磁盤須要很長的時間,而這段時間還可能有新的更新操做,checkpoint必須找到一個一致的狀態。checkpoint流程以下: 1)日誌文件中記錄"START CKPT"。 2)將內存中的數據以某種易於加載的組織方式轉儲到磁盤中,造成checkpoint文件。checkpoint文件中每每記錄"START CKPT"的日誌回放點,用於故障恢復。 3)日誌文件中記錄"END CKPT"。
傳統的行式數據庫將一個個完整的數據行存儲在數據頁中。若是處理查詢時須要用到大部分的數據列,這種方式在磁盤IO上是比較高效的。
列式數據庫是將同一個數據列的各個值存放在一塊兒。插入某個數據行時,該行的各個數據列的值也會存放到不一樣的地方。
列式數據庫大大地提升了OLAP大數據量查詢的效率。固然,列式數據庫不是萬能的,每次讀取某個數據行時,須要分別從不一樣的地方讀取各個數據列的值,而後合併在一塊兒造成數據行
不少列式數據庫還支持列組(column group,Bigtable系統中稱爲locality group),即將多個常常一塊兒訪問的數據列的各個值存放在一塊兒。若是讀取的數據列屬於相同的列組,列式數據庫能夠從相同的地方一次性讀取多個數據列的值,避免了多個數據列的合併。列組是一種行列混合存儲模式,這種模式可以同時知足OLTP和OLAP的查詢需求。
因爲同一個數據列的數據重複度很高,所以,列式數據庫壓縮時有很大的優點。例如,Google Bigtable列式數據庫對網頁庫壓縮能夠達到15倍以上的壓縮率
另外,能夠針對列式存儲作專門的索引優化。好比,性別列只有兩個值,「男」和「女」,能夠對這一列創建位圖索引:如圖2-12所示,「男」對應的位圖爲100101,表示第一、四、6行值爲「男」;「女」對應的位圖爲011010,表示第二、三、5行值爲「女」。若是須要查找男性或者女性的個數,只須要統計相應的位圖中1出現的次數便可。另外,創建位圖索引後0和1的重複度高,能夠採用專門的編碼方式對其進行壓縮。
分佈式系統面臨的第一個問題就是數據分佈,即將數據均勻地分佈到多個存儲節點。另外,爲了保證可靠性和可用性,須要將數據複製多個副本,這就帶來了多個副本之間的數據一致性問題。大規模分佈式存儲系統的重要目標就是節省成本,於是只能採用性價比較高的PC服務器。這些服務器性能很好,可是故障率很高,要求系統可以在軟件層面實現自動容錯。當存儲節點出現故障時,系統可以自動檢測出來,並將原有的數據和服務遷移到集羣中其餘正常工做的節點。
分佈式系統中有兩個重要的協議,包括Paxos選舉協議以及兩階段提交協議。Paxos協議用於多個節點之間達成一致,每每用於實現總控節點選舉。兩階段提交協議用於保證跨多個節點操做的原子性,這些操做要麼所有成功,要麼所有失敗。
服務器宕機
重啓後也須要恢復內存信息。
設計容錯系統的一個基本原則是:網絡永遠是不可靠的,任何一個消息只有收到對方的回覆後才能夠認爲發送成功,系統設計時老是假設網絡將會出現異常並採起相應的處理措施。
磁盤故障分爲兩種狀況:磁盤損壞和磁盤數據錯誤。
多臺服務器,即便其中一臺服務器磁盤出現故障,也能從其餘服務器上恢復數據
對於磁盤數據錯誤,每每能夠採用校驗和(checksum)機制來解決
在分佈式系統中,若是某個節點向另一個節點發起RPC(Remote Procedure Call)調用,這個RPC執行的結果有三種狀態:「成功」、「失敗」、「超時」(未知狀態),也稱爲分佈式存儲系統的三態。
當出現超時狀態時,只能經過不斷讀取以前操做的狀態來驗證RPC操做是否成功。固然,設計分佈式存儲系統時能夠將操做設計爲「冪等」的,也就是說,操做執行一次與執行屢次的結果相同,例如,覆蓋寫就是一種常見的冪等操做。
因爲異常的存在,分佈式存儲系統設計時每每會將數據冗餘存儲多份,每一份稱爲一個副本。
副本是分佈式存儲系統容錯技術的惟一手段。因爲多個副本的存在,如何保證副本之間的一致性是整個分佈式系統的理論核心。
通常來講,存儲系統能夠支持強一致性,也能夠爲了性能考慮只支持最終一致性。從客戶端的角度看,通常要求存儲系統可以支持讀寫一致性,會話一致性,單調讀,單調寫等特性。
常見的性能指標有:系統的吞吐能力以及系統的響應時間
這兩個指標每每是矛盾的,追求高吞吐的系統,每每很難作到低延遲;追求低延遲的系統,吞吐量也會受到限制
若是系統部署在同一個數據中心,只要系統設計合理,在保證強一致性的前提下,不會對性能和可用性形成太大的影響。Alibaba的OceanBase系統以及Google的分佈式存儲系統都傾向強一致性。
生成一張有30張縮略圖(假設圖片原始大小爲256KB)的頁面須要多少時間?
●方案1:順序操做,每次先從磁盤中讀取圖片,再執行生成縮略圖操做,執行時間爲:30×10ms(磁盤隨機讀取時間)+30×256K/30MB/s(假設縮略圖生成速度爲30MB/s)=560ms
●方案2:並行操做,一次性發送30個請求,每一個請求讀取一張圖片並生成縮略圖,執行時間爲:10ms+256K/300MB/s=18ms
分佈式系統區別於傳統單機系統在於可以將數據分佈到多個節點,並在多個節點之間實現負載均衡。數據分佈的方式主要有兩種,一種是哈希分佈,如一致性哈希,表明系統爲Amazon的Dynamo系統;另一種方法是順序分佈,即每張表格上的數據按照主鍵總體有序,表明系統爲Google的Bigtable系統。Bigtable將一張大表根據主鍵切分爲有序的範圍,每一個有序範圍是一個子表。
哈希取模的方法很常見,其方法是根據數據的某一種特徵計算哈希值,並將哈希值與集羣中的服務器創建映射關係,從而將不一樣哈希值的數據分佈到不一樣的服務器上。所謂數據特徵能夠是key-value系統中的主鍵(key),也能夠是其餘與業務邏輯相關的值。例如,將集羣中的服務器按0到N-1編號(N爲服務器的數量),根據數據的主鍵(hash(key)%N)或者數據所屬的用戶id(hash(user_id)%N)計算哈希值,來決定將數據映射到哪一臺服務器。
若是哈希函數的散列特性很好,哈希方式能夠將數據比較均勻地分佈到集羣中去,然而,找出一個散列特性很好的哈希函數是很難的。這是由於,若是按照主鍵散列,那麼同一個用戶id下的數據可能被分散到多臺服務器,這會使得一次操做同一個用戶id下的多條記錄變得困難;若是按照用戶id散列,容易出現「數據傾斜」(data skew)問題,即某些大用戶的數據量很大,不管集羣的規模有多大,這些用戶始終由一臺服務器處理。
傳統的哈希分佈算法還有一個問題:當服務器上線或者下線時,N值發生變化,數據映射徹底被打亂,幾乎全部的數據都須要從新分佈,這將帶來大量的數據遷移。
一種思路是再也不簡單地將哈希值和服務器個數作除法取模映射,而是將哈希值與服務器的對應關係做爲元數據,交給專門的元數據服務器來管理。訪問數據時,首先計算哈希值,再查詢元數據服務器,得到該哈希值對應的服務器。這樣,集羣擴容時,能夠將部分哈希值分配給新加入的機器並遷移對應的數據。另外一種思路就是採用一致性哈希。
哈希散列破壞了數據的有序性,只支持隨機讀取操做,不可以支持順序掃描
順序分佈在分佈式表格系統中比較常見,通常的作法是將大表順序劃分爲連續的範圍,每一個範圍稱爲一個子表,總控服務器負責將這些子表按照必定的策略分配到存儲節點上。
用戶表(User表)的主鍵範圍爲1~7000,在分佈式存儲系統中劃分爲多個子表,分別對應數據範圍1~1000,1001~2000,……6001~7000
讀User表時,須要經過Meta表查找相應的User子表所在的存儲節點
分佈式存儲系統的每一個集羣中通常有一個總控節點,其餘節點爲工做節點,由總控節點根據全局負載信息進行總體調度。工做節點剛上線時,總控節點須要將數據遷移到該節點,另外,系統運行過程當中也須要不斷地執行遷移任務,將數據從負載較高的工做節點遷移到負載較低的工做節點。
分佈式存儲系統經過複製協議將數據同步到多個存儲節點,並確保多個副本之間的數據一致性。
同一份數據的多個副本中每每有一個副本爲主副本(Primary),其餘副本爲備副本(Backup),由主副本將數據複製到備份副本。
複製協議分爲兩種,強同步複製以及異步複製,兩者的區別在於用戶的寫請求是否須要同步到備副本才能夠返回成功。
一致性和可用性是矛盾的,強同步複製協議能夠保證主備副本之間的一致性,可是當備副本出現故障時,也可能阻塞存儲系統的正常寫服務,系統的總體可用性受到影響;異步複製協議的可用性相對較好,可是一致性得不到保障,主副本出現故障時還有數據丟失的可能。
主副本將寫請求複製到其餘備副本,常見的作法是同步操做日誌
假設全部副本的個數爲N,且N>2,即備副本個數大於1。那麼,實現強同步協議時,主副本能夠將操做日誌併發地發給全部備副本並等待回覆,只要至少1個備副本返回成功就能夠回覆客戶端操做成功。強同步的好處在於若是主副本出現故障,至少有1個備副本擁有完整的數據,分佈式存儲系統能夠自動地將服務切換到最新的備副本而不用擔憂數據丟失的狀況。
強同步複製和異步複製都是將主副本的數據以某種形式發送到其餘副本,這種複製協議稱爲基於主副本的複製協議
在任什麼時候刻只能有一個副本爲主副本
NWR複製協議,其中,N爲副本數量,W爲寫操做的副本數,R爲讀操做的副本數。NWR協議中多個副本再也不區分主和備
只要W+R>N,能夠保證讀到的副本中至少有一個包含了最新的更新。然而,這種協議的問題在於不一樣副本的操做順序可能不一致,從多個副本讀取時可能出現衝突。這種方式在實際系統中比較少見,不建議使用。
存儲系統設計時須要在一致性和可用性之間權衡,在某些場景下,不容許丟失數據,在另一些場景下,極小的機率丟失部分數據時容許的,可用性更加劇要。例如,Oracle數據庫的DataGuard複製組件包含三種模式:
●最大保護模式(Maximum Protection):即強同步複製模式,
●最大性能模式(Maximum Performance):即異步複製模式
單臺服務器故障的機率是不高的,然而,只要集羣的規模足夠大,天天均可能有機器故障發生
在分佈式系統中,故障檢測每每經過租約(Lease)協議實現
容錯處理的第一步是故障檢測,心跳是一種很天然的想法。假設總控機A須要確認工做機B是否發生故障,那麼總控機A每隔一段時間,好比1秒,向工做機B發送一個心跳包。若是一切正常,機器B將響應機器A的心跳包;不然,機器A重試必定次數後認爲機器B發生了故障。然而,機器A收不到機器B的心跳並不能確保機器B發生故障並中止了服務,在系統運行過程當中,可能發生各類錯誤,好比機器A與機器B之間網絡發生問題,機器B過於繁忙致使沒法響應機器A的心跳包
租約機制就是帶有超時時間的一種受權。假設機器A須要檢測機器B是否發生故障,機器A能夠給機器B發放租約,機器B持有的租約在有效期內才容許提供服務,不然主動中止服務。機器B的租約快要到期的時候向機器A從新申請租約。正常狀況下,機器B經過不斷申請租約來延長有效期,當機器B出現故障或者與機器A之間的網絡發生故障時,機器B的租約將過時,從而機器A可以確保機器B再也不提供服務,機器B的服務能夠被安全地遷移到其餘服務器。
單層結構的分佈式存儲系統維護了多個副本,例如副本個數爲3,主備副本之間經過操做日誌同步。某單層結構的分佈式存儲系統有3個數據分片A、B、C,每一個數據分片存儲了三個副本。其中,A1,B1,C1爲主副本,分別存儲在節點1,節點2以及節點3。假設節點1發生故障,將被總控節點檢測到,總控節點選擇一個最新的副本,好比A2或者A3替換A1成爲新的主副本並提供寫服務。
兩層結構的分佈式存儲系統會將全部的數據持久化寫入底層的分佈式文件系統,每一個數據分片同一時刻只有一個提供服務的節點。如圖3-5所示,某雙層結構的分佈式存儲系統有3個數據分片,A、B和C。它們分別被節點1,節點2和節點3所服務。當節點1發生故障時,總控節點將選擇一個工做節點,好比節點2,加載A的服務。因爲A的全部數據都存儲在共享的分佈式文件系統中,節點2只須要從底層分佈式文件系統讀取A的數據並加載到內存中。
總控節點自身也可能出現故障,爲了實現總控節點的高可用性(High Availability),總控節點的狀態也將實時同步到備機,當故障發生時,能夠經過外部服務選舉某個備機做爲新的總控節點,而這個外部服務也必須是高可用的。爲了進行選主或者維護系統中重要的全局信息,能夠維護一套經過Paxos協議實現的分佈式鎖服務,好比Google Chubby或者它的開源實現Apache Zookeeper。
分佈式存儲系統中每每有一個總控節點用於維護數據分佈信息,執行工做機管理,數據定位,故障檢測和恢復,負載均衡等全局調度工做。
開源的Hadoop也可以擴展到3000臺以上的集羣。
同一個組內的節點服務相同的數據,這樣的系統稱爲同構系統。同構系統的問題在於增長副本須要遷移的數據量太大,假設每一個存儲節點服務的數據量爲1TB,內部傳輸帶寬限制爲20MB/s,那麼增長副本拷貝數據須要的時間爲1TB/20MB/s=50000s,大約十幾個小時。
系統中有五個分片(A,B,C,D,E),每一個分片包含三個副本,如分片A的三個副本分別爲A1,A2以及A3。假設節點1發生永久性故障,那麼能夠從剩餘的節點中任意選擇健康的節點來增長A,B以及E的副本。因爲整個集羣都參與到節點1的故障恢復過程,故障恢復時間很短,並且集羣規模越大,優點就會越明顯。
異構系統
分佈式系統涉及的協議不少,例如租約,複製協議,一致性協議
兩階段提交協議用於保證跨多個節點操做的原子性,也就是說,跨多個節點的操做要麼在全部節點上所有執行成功,要麼所有失敗。兩階段提交協議(Two-phase Commit,2PC)常常用來實現分佈式事務。
Paxos協議用於確保多個節點對某個投票(例如哪一個節點爲主節點)達成一致。
在兩階段協議中,系統通常包含兩類節點:一類爲協調者( coordinator),一般一個系統中只有一個;另外一類爲事務參與者( participants, cohorts 或 workers),通常包含多個。
一、階段1:請求階段(Prepare Phase)。在請求階段,協調者通知事務參與者準備提交或者取消事務,而後進入表決過程。在表決過程當中,參與者將告知協調者本身的決策:贊成(事務參與者本地執行成功)或者取消(事務參與者本地執行失敗)。
二、階段2:提交階段(Commit Phase)。在提交階段,協調者將基於第一個階段的投票結果進行決策:提交或者取消。當且僅當全部的參與者贊成提交事務協調者才通知全部的參與者提交事務,不然協調者通知全部的參與者取消事務。參與者在接收到協調者發來的消息後將執行相應的操做。
A組織B、C和D三我的去爬長城:若是全部人都贊成去爬長城,那麼活動將舉行;若是有一人不一樣意去爬長城,那麼活動將取消。
假如D一直不能回覆郵件,那麼A、B和C將不得不處於一直等待的狀態。而且B和C所持有的資源一直不能釋放,
A能夠經過引入事務的超時機制防止資源一直不能釋放的狀況。
更爲嚴重的是,假如A發完郵件後生病住院了,即便B、C和D都發郵件告訴A贊成下週三去爬長城,若是A沒有備份,事務將被阻塞。
兩階段提交協議可能面臨兩種故障:
●事務參與者發生故障。給每一個事務設置一個超時時間,若是某個事務參與者一直不響應,到達超時時間後整個事務失敗。
●協調者發生故障。協調者須要將事務相關信息記錄到操做日誌並同步到備用協調者,假如協調者發生故障,備用協調者能夠接替它完成後續的工做。若是沒有備用協調者,協調者又發生了永久性故障,事務參與者將沒法完成事務而一直等待下去。
大多數分佈式存儲系統都採用敬而遠之的作法,放棄對分佈式事務的支持。
Paxos協議用於解決多個節點之間的一致性問題。多個節點之間經過操做日誌同步數據,若是隻有一個節點爲主節點,那麼,很容易確保多個節點之間操做日誌的一致性。考慮到主節點可能出現故障,系統須要選舉出新的主節點。Paxos協議正是用來實現這個需求。
爲了實現高可用性,主節點每每將數據以操做日誌的形式同步到備節點。若是主節點發生故障,備節點會提議本身成爲主節點。這裏存在的問題是網絡分區的時候,可能會存在多個備節點提議(Proposer,提議者)本身成爲主節點。Paxos協議保證,即便同時存在多個proposer,也可以保證全部節點最終達成一致,即選舉出惟一的主節點。
大多數狀況下,系統只有一個proposer,他的提議也老是會很快地被大多數節點接受。Paxos協議執行步驟以下: 1)批准(accept):Proposer發送accept消息要求全部其餘節點(acceptor,接受者)接受某個提議值,acceptor能夠接受或者拒絕。 2)確認(acknowledge):若是超過一半的acceptor接受,意味着提議值已經生效,proposer發送acknowledge消息通知全部的acceptor提議生效。
當出現網絡或者其餘異常時,系統中可能存在多個proposer,他們各自發起不一樣的提議。
若是proposer第一次發起的accept請求沒有被acceptor中的多數派批准(例如與其餘proposer的提議衝突),那麼,須要完整地執行一輪Paxos協議。過程以下:
Paxos協議須要考慮兩個問題:正確性,即只有一個提議值會生效;可終止性,即最後總會有一個提議值生效。
Paxos協議有兩種用法:一種用法是用它來實現全局的鎖服務或者命名和配置服務,例如 Apache Zookeeper
另一種用法是用它來將用戶數據複製到多個數據中心
2PC協議最大的缺陷在於沒法處理協調者宕機問題。若是協調者宕機,那麼,2PC協議中的每一個參與者可能都不知道事務應該提交仍是回滾,整個協議被阻塞,執行過程當中申請的資源都沒法釋放。所以,常見的作法是將2PC和Paxos協議結合起來,經過2PC保證多個數據分片上的操做的原子性,經過Paxos協議實現同一個數據分片的多個副本之間的一致性。另外,經過Paxos協議解決2PC協議中協調者宕機問題。當2PC協議中的協調者出現故障時,經過Paxos協議選舉出新的協調者繼續提供服務。
跨機房部署方案有三個:集羣總體切換、單個集羣跨機房、Paxos選主副本。
在前兩種方案中,總控節點須要和工做節點之間保持租約(lease),當工做節點出現故障時,自動將它上面服務的主副本切換到其餘工做節點。若是採用Paxos協議選主副本,那麼,每一個數據分片的多個副本構成一個Paxos複製組。B一、B二、B三、B4構成一個複製組,某一時刻B1爲複製組的主副本,當B1出現故障時,其餘副本將嘗試切換爲主副本,Paxos協議保證只有一個副本會成功。這樣,總控節點與工做節點之間再也不須要保持租約,總控節點出現故障也不會對工做節點產生影響。
Google文件系統(GFS)是構建在廉價服務器之上的大型分佈式系統。
GFS是Google分佈式存儲的基石,其餘存儲系統,如Google Bigtable、Google Megastore、Google Percolator均直接或者間接地構建在GFS之上。另外,Google大規模批處理系統MapReduce也須要利用GFS做爲海量數據的輸入輸出。
GFS系統的節點可分爲三種角色:GFS Master(主控服務器)、GFS ChunkServer(CS,數據塊服務器)以及GFS客戶端。
客戶端是GFS提供給應用程序的訪問接口,它是一組專用接口,不遵循POSIX規範,以庫文件的形式提供。客戶端訪問GFS時,首先訪問主控服務器節點,獲取與之進行交互的CS信息,而後直接訪問這些CS,完成數據存取工做。
CDN經過將網絡內容發佈到靠近用戶的邊緣節點,使不一樣地域的用戶在訪問相同網頁時能夠就近獲取。
所謂的邊緣節點是CDN服務提供商通過精心挑選的距離用戶很是近的服務器節點,僅「一跳」(Single Hop)之遙。用戶在訪問時就無需再通過多個路由器,大大減小訪問時間。
DNS在對域名解析時再也不向用戶返回源服務器的IP,而是返回了由智能CDN負載均衡系統選定的某個邊緣節點的IP。用戶利用這個IP訪問邊緣節點,而後該節點經過其內部DNS解析獲得源服務器IP併發出請求來獲取用戶所需的頁面,若是請求成功,邊緣節點會將頁面緩存下來,下次用戶訪問時能夠直接讀取,而不須要每次都訪問源服務器。
淘寶CDN系統用於支持用戶購物,尤爲是「雙11」光棍節時的海量圖片請求。圖片存儲在後臺的TFS集羣中,CDN系統將這些圖片緩存到離用戶最近的邊緣節點。
相比分佈式存儲系統,分佈式緩存系統的實現要容易不少。這是由於緩存系統不須要考慮數據持久化,若是緩存服務器出現故障,只須要簡單地將它從集羣中剔除便可。
因爲Blob存儲系統讀訪問量大,更新和刪除不多,特別適合經過CDN技術分發到離用戶最近的節點。
新上線的CDN緩存節點配備的磁盤均爲SSD。
分佈式鍵值模型能夠當作是分佈式表格模型的一種特例。然而,因爲它只支持針對單個key-value的增、刪、查、改操做,所以,適用哈希分佈算法。
Amazon Dynamo以很簡單的鍵值方式存儲數據,不支持複雜的查詢。
Dynamo寫入數據時,首先,根據一致性哈希算法計算出每一個數據副本所在的存儲節點,其中一個副本做爲本次寫操做的協調者。接着,協調者併發地往全部其餘副本發送寫請求,每一個副本將接收到的數據寫入本地,協調者也將數據寫入本地。當某個副本寫入成功後,回覆協調者。若是發給某個副本的寫請求失敗,協調者會將它加入重試列表不斷重試。等到W-1個副本回複寫入成功後(即加上協調者共W個副本寫入成功),協調者能夠回覆客戶端寫入成功。協調者回復客戶端成功後,還會繼續等待或者重試,直到全部的副本都寫入成功。
Dynamo讀取數據時,首先,根據一致性哈希算法計算出每一個副本所在的存儲節點,其中一個副本做爲本次讀操做的協調者。接着,協調者根據負載策略選擇R個副本,併發地向它們發送讀請求。每一個副本讀取本地數據,協調者也讀取本地數據。當某個副本讀取成功後,回覆協調者讀取結果。等到R-1個副本回復讀取成功後(即加上協調者共R個副本讀取成功),協調者能夠回覆客戶端。這裏分爲兩種狀況:若是R個副本返回的數據徹底一致,將某個副本的讀取結果回覆客戶端;不然,須要根據衝突處理規則合併多個副本的讀取結果。Dynamo系統默認的策略是根據修改時間戳選擇最新的數據,固然用戶也能夠自定義衝突處理方法。讀取過程當中若是發現某些副本上的數據版本太舊,Dynamo內部會異步發起一次讀取修復操做,使用衝突解決後的結果修正錯誤的副本。
Dynamo設計支持可插拔的存儲引擎,好比Berkerly DB(BDB),MySQL InnoDB等。
Dynamo採用無中心節點的P2P設計,增長了系統可擴展性,但同時帶來了一致性問題,影響上層應用。另外,一致性問題也使得異常狀況下的測試變得更加困難,因爲Dynamo只保證最基本的最終一致性,多客戶端併發操做的時候很難預測操做結果,也很難預測不一致的時間窗口,影響測試用例設計。
主流的分佈式系統通常都帶有中心節點,這樣可以簡化設計,並且中心節點只維護少許元數據,通常不會成爲性能瓶頸。
無中心節點的設計短時間以內難以成爲主流
Tair是淘寶開發的一個分佈式鍵/值存儲引擎。Tair分爲持久化和非持久化兩種使用方式:非持久化的Tair能夠當作是一個分佈式緩存,持久化的Tair將數據存放於磁盤中。
Tair做爲一個分佈式系統,是由一箇中心控制節點和若干個服務節點組成。其中,中心控制節點稱爲Config Server,服務節點稱爲Data Server。Config Server負責管理全部的Data Server,維護其狀態信息;Data Server對外提供各類數據服務,並以心跳的形式將自身情況彙報給Config Server。Config Server是控制點,並且是單點,目前採用一主一備的形式來保證可靠性,全部的Data Server地位都是等價的。
根據數據的主鍵計算哈希值後,分佈到Q個桶中,桶是負載均衡和數據遷移的基本單位。Config Server按照必定的策略把每一個桶指派到不一樣的Data Server上。
當某臺Data Server故障不可用時,Config Server可以檢測到。每一個哈希桶在Tair中存儲多個副本,若是是備副本,那麼Config Server會從新爲其指定一臺Data Server,若是是持久化存儲,還將複製數據到新的Data Server上。若是是主副本,那麼ConfigServer首先將某個正常的備副本提高爲主副本,對外提供服務。接着,再選擇另一臺Data Server增長一個備副本,確保數據的備份數。
機器加入或者負載不均衡可能致使桶遷移,遷移的過程當中須要保證對外服務。當遷移發生時,假設Data Server A要把桶三、四、5遷移到Data Server B。遷移完成前,客戶端的路由表沒有變化,客戶端對三、四、5的訪問請求都會路由到A。如今假設3還沒開始遷移,4正在遷移中,5已經遷移完成。那麼若是對3訪問,A直接服務;若是對5訪問,A會把請求轉發給B,而且將B的返回結果返回給用戶;若是對4訪問,由A處理,同時若是是對4的修改操做,會記錄修改日誌,等到桶4遷移完成時,還要把修改日誌發送到B,在B上應用這些修改操做,直到A和B之間數據徹底一致遷移才真正完成。
Tair默認包含兩個存儲引擎:Mdb和Fdb,此外,還支持Berkerly DB、Tokyo Cabinet、InnoDB、Leveldb等各類存儲引擎。
Amazon Dynamo採用P2P架構,而在Tair中引入了中心節點Config Server。這種方式很容易處理數據的一致性,再也不須要向量時鐘、數據回傳、Merkle樹、衝突處理等複雜的P2P技術。另外,中心節點的負載很低。做者認爲,分佈式鍵值系統的總體架構應該參考Tair,而不是Dynamo。
Tair最主要的用途在於分佈式緩存,持久化存儲起步比較晚,在實現細節上也有一些不盡如人意的地方。例如,Tair持久化存儲經過複製技術來提升可靠性,然而,這種複製是異步的。所以,當有Data Server發生故障時,客戶有可能在必定時間內讀不到最新的數據,甚至發生最新修改的數據丟失的狀況。
分佈式表格系統對外提供表格模型,每一個表格由不少行組成,經過主鍵惟一標識,每一行包含不少列。整個表格在系統中全局有序,順序分佈。
Hadoop
Bigtable是Google開發的基於GFS和Chubby的分佈式表格系統。Google的不少數據,包括Web索引、衛星圖像數據等在內的海量結構化和半結構化數據,都存儲在Bigtable中。
Bigtable系統由不少表格組成,每一個表格包含不少行,每行經過一個主鍵(Row Key)惟一標識,每行又包含不少列(Column)。某一行的某一列構成一個單元(Cell),每一個單元包含多個版本的數據。總體上看,Bigtable是一個分佈式多維映射表。另外,Bigtable將多個列組織成列族(column family),這樣,列名由兩個部分組成:(column family,qualifier)。列族是Bigtable中訪問控制的基本單元,也就是說,訪問權限的設置是在列族這一級別上進行的。Bigtable中的列族在建立表格的時候須要預先定義好,個數也不容許過多;然而,每一個列族包含哪些qualifier是不須要預先定義的,qualifier能夠任意多個,適合表示半結構化數據。Bigtable中的行主鍵能夠是任意的字符串,最大不超過64KB。Bigtable表中的數據按照行主鍵進行排序,排序使用的是字典序。行主鍵com.cnn.www是域名www.cnn.com變換後的結果,這樣作的好處是使得全部www.cnn.com下的子域名在系統中連續存放。這一行數據包含兩個列族:"contents"和"anchor"。其中,列族"anchor"又包含兩個列,qualifier分別爲"cnnsi.com"和"my:look.ca"。 Google的不少服務,好比Web檢索和用戶的個性化設置,都須要保存不一樣時間的數據,這些不一樣的數據版本必須經過時間戳來區分。t四、t5和t6表示保存了三個時間點獲取的網頁
失效的版本將會由Bigtable的垃圾回收機制自動刪除
Bigtable構建在GFS之上,爲文件系統增長一層分佈式索引層。另外,Bigtable依賴Google的Chubby(即分佈式鎖服務)進行服務器選舉及全局信息維護。
Bigtable將大表劃分爲大小在100~200MB的子表(tablet),每一個子表對應一個連續的數據範圍。
客戶端程序庫(Client):提供Bigtable到應用程序的接口,應用程序經過客戶端程序庫對錶格的數據單元進行增、刪、查、改等操做。客戶端經過Chubby鎖服務獲取一些控制信息,但全部表格的數據內容都在客戶端與子表服務器之間直接傳送;
主控服務器(Master):管理全部的子表服務器,包括分配子表給子表服務器,指導子表服務器實現子表的合併,接受來自子表服務器的子表分裂消息,監控子表服務器,在子表服務器之間進行負載均衡並實現子表服務器的故障恢復等。
Chubby是一個分佈式鎖服務,底層的核心算法爲Paxos。Paxos算法的實現過程須要一個「多數派」就某個值達成一致,進而才能獲得一個分佈式一致性狀態。也就是說,只要一半以上的節點不發生故障,Chubby就可以正常提供服務。Chubby服務部署在多個數據中心,典型的部署爲兩地三數據中心五副本,同城的兩個數據中心分別部署兩個副本,異地的數據中心部署一個副本,任何一個數據中心總體發生故障都不影響正常服務
Bigtable系統保證強一致性
Bigtable中Master對Tablet Server的監控是經過Chubby完成的,Tablet Server在初始化時都會從Chubby中獲取一個獨佔鎖
因爲Bigtable負載均衡的過程當中會停一會讀寫服務,負載均衡策略不該當過於激進。
隨着數據不斷寫入和刪除,某些子表可能太大,某些子表可能過小,須要執行子表分裂與合併操做。順序分佈與哈希分佈的區別在於哈希分佈每每是靜態的,而順序分佈是動態的,須要經過分裂與合併操做動態調整。
Bigtable採用Merge-dump存儲引擎。數據寫入時須要先寫操做日誌,成功後應用到內存中的MemTable中,寫操做日誌是往磁盤中的日誌文件追加數據,很好地利用了磁盤設備的特性。當內存中的MemTable達到必定大小,須要將MemTable轉儲(Dump)到磁盤中生成SSTable文件。因爲數據同時存在MemTable和可能多個SSTable中,讀取操做須要按從舊到新的時間順序合併SSTable和內存中的MemTable數據。數據在SSTable中連續存放,所以能夠同時知足隨機讀取和順序讀取兩種需求。爲了防止磁盤中的SSTable文件過多,須要定時將多個SSTable經過compaction過程合併爲一個SSTable,從而減小後續讀操做須要讀取的文件個數。
插入、刪除、更新、增長(Add)等操做在Merge-dump引擎中都當作一回事,除了最先生成的SSTable外,SSTable中記錄的只是操做,而不是最終的結果,須要等到讀取(隨機或者順序)時才合併獲得最終結果。
數據在SSTable中按照主鍵有序存儲
Tablet Server的緩存包括兩種:塊緩存(Block Cache)和行緩存(Row Cache)。其中,塊緩存的單位爲SSTable中的數據塊,行緩存的單位爲一行記錄。隨機讀取時,首先查找行緩存;若是行緩存不命中,接着再查找塊緩存。
Compaction後生成新的SSTable,原有的SSTable成爲垃圾須要被回收掉
Master按期執行垃圾回收任務,這是一個標記刪除(mark-and-sweep)過程
GFS+Bigtable兩層架構以一種很優雅的方式兼顧系統的強一致性和可用性。底層文件系統GFS是弱一致性系統,可用性和性能很好,可是多客戶端追加可能出現重複記錄等數據不一致問題;上層的表格系統Bigtable經過多級分佈式索引的方式使得系統對外總體表現爲強一致性。
單副本服務。Bigtable架構很是適合離線或者半線上應用,然而,Tablet Server節點出現故障時部分數據短期內沒法提供讀寫服務,不適合實時性要求特別高的業務,如交易類業務。
Google Bigtable架構把可擴展性基本作到了極致,Megastore則是在Bigtable系統之上提供友好的數據庫功能支持,加強易用性。Megastore是介於傳統的關係型數據庫和NoSQL之間的存儲技術,它在Google內部使用普遍,如Google App Engine、社交類應用等。
最新讀取和快照讀取利用了Bigtable存儲多版本數據的特性,保證不會讀到未提交的事務。非一致性讀取忽略日誌的狀態而直接讀取Bigtable內存中最新的值,可能讀到不完整的事務。
Megastore事務中的寫操做採用了預寫式日誌(Write-ahead日誌或REDO日誌),也就是說,只有當全部的操做都在日誌中記錄下來後,寫操做纔會對數據執行修改。
Paxos協議使用了樂觀鎖的機制:儘管可能有多個寫操做同時試圖寫同一個日誌位置,但最後只有一個會成功。其餘失敗的寫操做都會觀察到成功的寫操做,而後停止並重試。
假設事務T1和T2對同一個實體組併發執行,T1執行時讀取a和b,T2讀取a和d,接着T1和T2同時提交。Paxos協議保證T1和T2中有且只有一個事務提交成功,假如T1提交成功,T2將從新讀取a和d後再次經過Paxos協議提交
對於多個集羣之間的操做日誌同步,Megastore系統採用的是基於Paxos的複製協議機制,對於普通的Master-Slave強同步機制,Master宕機後,Slave若是須要切換爲Master繼續提供服務須要首先確認Master宕機,檢測Master宕機這段時間是須要中止寫服務的,不然將形成數據不一致。
分佈式數據庫
有不少思路能夠實現關係數據庫的可擴展性。例如,在應用層劃分數據,將不一樣的數據分片劃分到不一樣的關係數據庫上,如MySQL Sharding;或者在關係數據庫內部支持數據自動分片,如Microsoft SQL Azure;或者乾脆從存儲引擎開始重寫一個全新的分佈式數據庫,如Google Spanner以及Alibaba OceanBase。
爲了擴展關係數據庫,最簡單也是最爲常見的作法就是應用層按照規則將數據拆分爲多個分片,分佈到多個數據庫節點,並引入一箇中間層來對應用屏蔽後端的數據庫拆分細節。
以MySQL Sharding架構爲例,分爲幾個部分:中間層dbproxy集羣、數據庫組、元數據服務器、常駐進程。
應用程序經過MySQL原生的客戶端與系統交互,支持JDBC,原有的單機訪問數據庫程序能夠無縫遷移。
中間層解析客戶端SQL請求並轉發到後端的數據庫。具體來說,它解析MySQL協議,執行SQL路由,SQL過濾,讀寫分離,結果歸併,排序以及分組,等等。
主機負責全部的寫事務及強一致讀事務,備機能夠支持有必定延遲的讀事務。
元數據服務器主要負責維護dbgroup拆分規則並用於dbgroup選主。dbproxy經過元數據服務器獲取拆分規則從而肯定SQL語句的執行計劃。另外,若是dbgroup的主機出現故障,須要經過元數據服務器選主。元數據服務器自己也須要多個副本實現HA,一種常見的方式是採用Zookeeper實現。
部署在每臺數據庫服務器上的常駐進程,用於實現監控,單點切換,安裝,卸載程序等。dbgroup中的數據庫須要進行主備切換,軟件升級等,這些控制邏輯須要與數據庫讀寫事務處理邏輯隔離開來。假設數據庫按照用戶哈希分區,同一個用戶的數據分佈在一個數據庫組上。若是SQL請求只涉及同一個用戶(這對於大多數應用都是成立的),那麼,中間層將請求轉發給相應的數據庫組,等待返回結果並將結果返回給客戶端;若是SQL請求涉及多個用戶,那麼中間層須要轉發給多個數據庫組,等待返回結果並將結果執行合併、分組、排序等操做後返回客戶端。因爲中間層的協議與MySQL兼容,客戶端徹底感覺不到與訪問單臺MySQL機器之間的差異。
引入數據庫中間層將後端分庫分表對應用透明化在大型互聯網公司內部很常見。
數據庫複製:MySQL主備之間只支持異步複製,並且主庫壓力較大時可能產生很大的延遲,所以,主備切換可能會丟失最後一部分更新事務,這時每每須要人工介入。
Microsoft SQL Azure是微軟的雲關係型數據庫,後端存儲又稱爲雲SQL Server(Cloud SQL Server)。它構建在SQL Server之上,經過分佈式技術提高傳統關係型數據庫的可擴展性和容錯能力。
Google Spanner是Google的全球級分佈式數據庫(Globally-Distributed Database)。Spanner的擴展性達到了全球級,能夠擴展到數百個數據中心,數百萬臺機器,上萬億行記錄。更爲重要的是,除了誇張的可擴展性以外,它還能經過同步複製和多版本控制來知足外部一致性,支持跨數據中心事務。
Spanner構建在Google下一代分佈式文件系統Colossus之上。Colossus是GFS的延續,相比GFS,Colossus的主要改進點在於實時性,而且支持海量小文件。
正常狀況下,這個主副本會在快要到期的時候將本身再次選爲主副本;若是出現異常,例如主副本所在的spanserver宕機,其餘副本會在10秒後經過Paxos協議選舉爲新的主副本。
Google的分佈式存儲系統一步步地從Bigtable到Megastore,再到Spanner,這也印證了分佈式技術和傳統關係數據庫技術融合的必然性,即底層經過分佈式技術實現可擴展性,上層經過關係數據庫的模型和接口將系統的功能暴露給用戶。阿里巴巴的OceanBase系統在設計之初就考慮到這兩種技術融合的必然性,所以,一開始就將系統的最終目標定爲:可擴展的關係數據庫。
Amazon Web Services(AWS)是Amazon構建的一個雲計算平臺的總稱,它提供了一系列雲服務。經過這些服務,用戶可否訪問和使用Amazon的存儲和計算基礎設施。
一、計算類:AWS核心產品爲彈性計算雲EC2(Elastic Computing)。EC2幾乎能夠認爲是迄今爲止雲計算領域最爲成功的產品,通俗地講,就是提供虛擬機,用戶的應用程序部署在EC2實例中。EC2架構的核心是彈性伸縮,當託管的應用程序訪問量變化時可以自動增長或者減小EC2實例,並經過彈性負載均衡技術將訪問請求分發到新增的EC2實例上。在計費模式上,EC2按照使用量計費,而不是採用傳統的預付費方式
EBS(Elastic Block Store)是一個分佈式塊設備,能夠像本地的磁盤同樣直接掛載在EC2實例上,與本地磁盤不一樣的是,保存到EBS的數據會由EBS的管理節點自動複製到多個存儲節點上。EC2實例的本地存儲是不可靠的,若是EC2實例出現故障,本地存儲上保存的數據將會丟失,而保存到EBS上的數據不會丟失。EBS用於替代EC2實例的本地存儲,從而加強EC2可靠性。
二、存儲類:存儲類產品較多,包括簡單對象存儲S3,表格存儲系統SimpleDB、 DynamoDB、分佈式關係數據庫服務(Relational Datastore Service,RDS)以及簡單消息存儲(Simple Queue Service,SQS)
爲了提升訪問性能,S3中的對象還可以經過CloudFront緩存到不一樣地理位置的內容分發網絡(Content Delivery Network,CDN)節點。SimpleDB和DynamoDB是分佈式表格系統,支持對一張表格進行讀寫操做;RDS是分佈式數據庫,目前支持MySQL以及Oracle兩種數據庫。
三、工具集中包含各類語言的SDK、程序自動部署以及各類管理工具。另外,AWS經過CloudWatch系統提供豐富的監控功能。
假設網站MyWebSite.com託管在AWS平臺的某個可用區域中。AWS開發者將Web應用上傳到AWS平臺並部署到指定的EC2實例上。EC2實例通常分紅多個自動擴展組(Auto Scaling Group),並經過彈性負載均衡(Elastic Load Balancing)技術將訪問請求自動分發到自動擴展組內的EC2實例。開發者的Web應用能夠使用AWS平臺上的存儲類服務,包括S三、SimpleDB、DynamoDB、RDS以及SQS。
網站上每每有一些大對象,好比圖片、視頻,這些大對象存儲在S3系統中,並經過內容分發技術緩存到多個CloudFront節點。當Internet用戶瀏覽MyWebSite.com時,可能會請求S3中的大對象,這樣的請求將經過DNS按照必定的策略定位到CloudFront節點。CloudFront首先在本地緩存節點查找對象,若是不存在,將請求源站獲取S3中存儲的對象數據,這一步操做稱爲回源。
Google雲平臺(Google App Engine,GAE)是一種PaaS服務,使得外部開發者能夠經過Google指望的方式使用它的基礎設施服務,目前支持Python和Java兩種語言。GAE尤爲適用於企業構建本身的企業私有云。
GAE雲平臺主要包含以下幾個部分:
一、前端服務器。前端的功能包括負載均衡以及路由。前端服務器將靜態內容請求轉發到靜態文件服務器,將動態內容請求轉發到應用服務器。
二、應用服務器。應用服務器裝載應用的代碼並處理接收到的動態內容請求。
三、應用管理節點(App Master)。調度應用服務器,將應用服務器的變化通知前端,從而前端能夠將訪問流量切換到正確的應用服務器。
四、存儲區。包括DataStore、MemCache以及BlobStore三個部分。應用的持久化數據主要存儲在DataStore中,MemCache用於緩存,BlobStore是DataStore的一種補充,用於存儲大對象。
五、服務區。除了必備的應用服務器以及存儲區以外,GAE還包含不少服務,好比圖像處理服務(Images)、郵件服務、抓取服務(URL fetch)、任務隊列(Task Queue)以及用戶服務(Users)等。
六、管理工具。GAE提供Web管理工具用於管理應用並監控應用的運行狀態,好比資源消耗、應用日誌等。
GAE的核心組件爲應用服務器以及存儲區,其中,應用服務器用於託管GAE平臺用戶的應用程序,存儲區提供雲存儲服務
GAE對外不提供虛擬機服務,所以,對於不一樣的開發語言,須要提供不一樣的應用服務器實現,目前支持Python和Java兩種語言
從託管Web應用程序的角度看,雲平臺主要包括雲存儲以及應用運行平臺,
雲存儲組件包括兩層:分佈式存儲層以及存儲訪問層。分佈式存儲層管理存儲服務器集羣,實現各個存儲設備之間的協同工做,保證數據可靠性,對外屏蔽數據所在位置,數據遷移,數據複製,機器增減等變化,使得整個分佈式系統看起來像是一臺服務器。分佈式存儲層是雲存儲系統的核心,也是整個雲存儲平臺最難實現的部分。CDN節點將雲存儲系統中的熱點數據緩存到離用戶最近的位置,從而減小用戶的訪問延時並節約帶寬。
應用運行平臺的主體爲計算實例,計算實例最主要的功能有兩個:開發者的應用程序運行環境以及離線任務處理。不一樣的雲計算平臺廠商的計算實例形式每每不一樣:AWS(Amazon Web Service)平臺中的計算實例爲Amazon的彈性計算(Elastic Computing,EC2)虛擬機,它們既用於託管開發者的Web程序,又可用來執行Hadoop MapReduce計算或者圖像以及視頻轉換等離線任務;GAE(Google App Engine)平臺中的計算實例分爲前端實例(Frontend Instance)以及後端實例(Backend Instance),其中,前端實例爲GAE特有的Python、Java以及Go語言運行容器,用於託管開發者使用Python、Java或者Go語言開發的Web程序,後端實例執行運行時間較長的離線任務;
雲存儲平臺還包含一些公共服務,這些基礎服務由雲存儲組件及運行平臺組件所共用,如:
一、消息服務。消息服務將執行流程異步化,用於應用程序解耦
二、緩存服務。緩存服務用於存儲雲存儲系統中的讀多寫少的熱點數據,大多數雲存儲平臺提供Memcache服務
三、用戶管理。用戶管理主要功能是用戶身份認證,確保用戶的身份合法,並存儲用戶相關的我的信息。雲計算平臺通常支持單點登陸,在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的系統。
四、權限管理。爲多個服務提供集中的權限控制,以確保應用和數據只能被有受權的用戶訪問。
五、安全服務。SQL注入漏洞、XSS跨站腳本漏洞。主機入侵檢測經過主機日誌安全分析,實時偵測系統密碼破解,異常IP登陸等攻擊行爲並實時報警;DDos緩解技術可以抵禦SYN flood以及其餘拒絕服務攻擊。
六、計費管理。計算出用戶的使用費用,並提供完善和詳細的報表。雲存儲系統計費涉及的參數通常包括:CPU時間,網絡出口帶寬,存儲量以及服務調用次數(包括讀寫API調用次數)。
七、資源管理。管理雲存儲平臺中的全部服務器資源,將應用程序或者虛擬機映射自動部署到合適的計算實例,另外,自動調整計算實例的數量來幫助運行於其上的應用更好地應對突發流量。當計算實例發生故障時,資源管理系統還須要通知前端的負載均衡層,將流量切換到其餘計算實例。
八、運維管理。雲存儲平臺的運維須要作到自動化,從而下降運維成本
NoSQL存儲系統則百花齊放,常見的NoSQL系統包括僅支持根據主鍵進行CRUD(Create,Read,Update,Delete)操做的鍵值(Key-Value)存儲系統,也有基於傳統的B樹或者LSM樹(Log-Structured Merge Tree)的存儲系統。
CDN以及P2P技術將雲存儲系統中的熱點數據緩存到離用戶較近的邊緣節點或者臨近的其餘用戶的客戶端,從而起到訪問加速的做用,而且節省雲存儲服務提供商的網絡帶寬成本。
雲存儲系統經過存儲訪問層被我的用戶的終端設備直接訪問,或者被雲存儲平臺中託管的應用程序訪問。雲存儲訪問層的功能包括:Web服務、負載均衡、安全服務以及計費。雲存儲系統對外提供統一的訪問接口,常見的接口是REST或者SOAP這樣的Web服務,須要經過Apache或者Nginx這樣的Web服務器進行協議轉化,Web服務器前端常用LVS(Linux Virtual Server)、HaProxy這樣的軟件或者專業的負載均衡設備(如F5負載均衡器)進行負載均衡。存儲訪問層須要提供安全和計費服務,安全服務包括身份認證、訪問受權、綜合防禦、安全審計、DDos攻擊預防/防火牆等。
基於虛擬機的彈性計算平臺的優點在於兼容性,支持各類編程語言和平臺。
雲引擎。典型的雲引擎爲Google App Engine,底層設計的涉及的技術主要是應用容器(好比Java Tomcat、Jetty,Python Runtime)以及應用容器自動伸縮。當應用的負載太高時,自動增長應用的運行容器數;反之,自動減小應用的運行容器數。
提到大數據,首先想到的就是MapReduce,不少人甚至將大數據與MapReduce畫等號。雖然MapReduce解決了海量數據離線分析問題,可是,隨着應用對數據的實時性要求愈來愈高,流式計算系統和實時分析系統獲得愈來愈普遍的應用。
數據的爆發式的增加,有一個趨勢叫新摩爾定律。根據IDC做出的預測,數據一直都在以每一年50%的速度增加,也就是說每兩年增長一倍,這意味着人類在最近兩年產生的數據量至關於以前產生的所有數據量。
從各類各樣類型的數據,包括非結構化數據、半結構化數據以及結構化數據中,快速獲取有價值信息的能力,就是大數據技術。
一提到大數據,大部分人首先想到的就是Hadoop。Hadoop是Google GFS以及MapReduce系統的開源實現,用戶能夠在不瞭解分佈式底層細節的狀況下開發分佈式程序。它提供了離線處理功能,但沒法作到動態和實時的分析。爲了解決實時性問題,流計算和實時分析系統應運而生。
大數據技術進一步從海量數據中抽取數據的價值,從而誕生Google搜索引擎、Amazon商品推薦系統。
提到大數據,大多數人首先想到的就是MapReduce。MapReduce使得普通程序員能夠在不瞭解分佈式底層細節的前提下開發分佈式程序。使用者只需編寫兩個稱爲Map和Reduce的函數便可,MapReduce框架會自動處理數據劃分、多機並行執行、任務之間的協調,而且可以處理某個任務執行失敗或者機器出現故障的狀況。
MapReduce框架包含三種角色:主控進程(Master)用於執行任務劃分、調度、任務之間的協調等;Map工做進程(Map Worker,簡稱Map進程)以及Reduce工做進程(Reduce Worker,簡稱Reduce進程)分別用於執行Map任務和Reduce任務。
MapReduce框架實現時主要作了兩點優化:
一、本地化:儘可能將任務分配給離輸入文件最近的Map進程,如同一臺機器或者同一個機架。經過本地化策略,可以大大減小傳輸的數據量。
二、備份任務:若是某個Map或者Reduce任務執行的時間較長,主控進程會生成一個該任務的備份並分配給另一個空閒的Map或者Reduce進程。在大集羣環境下,即便全部機器的配置相同,機器的負載不一樣也會致使處理能力相差很大,經過備份任務減小「拖後腿」的任務,從而下降整個做業的整體執行時間。
MapReduce框架有效地解決了海量數據的離線批處理問題,引起了一系列的擴展和改進。這些擴展包括:Google Tenzing、Google Pregel。
Google Tenzing是一個構建在MapReduce之上的SQL執行引擎,支持SQL查詢且可以擴展到成千上萬臺機器,極大地方便了數據分析人員。
- 查詢服務器(Query Server):做爲鏈接客戶端和worker池的中間橋樑而存在。查詢服務器會解析客戶端發送的查詢請求,進行SQL優化,而後將執行計劃發送給分佈式Worker池執行。
- 分佈式Worker池:做爲執行系統,它會根據查詢服務器生成的執行計劃運行MapReduce任務。Worker池包含master和worker兩種節點,其中,master對應MapReduce框架中的master進程,worker對應MapReduce框架中的map和reduce進程。
- 查詢流程 1)用戶經過Web UI、CLI或者API向查詢服務器提交查詢。 2)查詢服務器將查詢請求解析爲一箇中間語法樹。 3)查詢服務器從元數據服務器獲取相應的元數據,而後建立一個更加完整的中間格式。 4)優化器掃描該中間格式進行各類優化,生成物理查詢計劃。 5)優化後的物理查詢計劃由一個或多個MapReduce做業組成。對於每一個MapReduce做業,查詢服務器經過master監聽者找到一個可用的master,master將該做業劃分爲多個任務。 6)空閒的worker從master拉取已就緒的任務。Reduce進程會將它們的結果寫入到一箇中間存儲區域中。 7)查詢服務器監控這些中間存儲區域,收集中間結果,並流失地返回給客戶端。
- 查詢服務器負責將用戶的SQL操做轉化爲MapReduce做業
Google Pregel用於圖模型迭代計算,圖中的每一個節點對應一個任務,每一個圖節點會產生輸出消息給圖中與它關聯的後續節點,而每一個節點會對從其餘節點傳入的輸入消息進行處理。
流式計算同時具備存儲系統和計算系統的特色,常常應用在一些相似反做弊、交易異常監控等場景。
源數據寫入到流處理節點,流處理節點內部運行用戶自定義的鉤子函數對輸入流進行處理,處理完後根據必定的規則轉發給下游的流處理節點繼續處理。
典型的鉤子函數包括:聚合函數:計算最近一段時間窗口內數據的聚合值,如max、min、avg、sum、 count等。
流處理節點能夠經過主備同步(Master/Slave)的方式容錯,即將數據強同步到備機,若是主機出現故障,備機自動切換爲主機繼續提供服務。然而,這種方式的代價很高,且流式處理系統每每對錯誤有必定的容忍度,實際應用時常常選擇其餘代價更低的容錯方式。
Yahoo S4最初是Yahoo爲了提升搜索廣告有效點擊率而開發的一個流式處理系統。S4的主要設計目標是提供一種簡單的編程接口來處理數據流,使得用戶能夠定製流式計算的操做算子。在容錯設計上,S4作得比較簡單:一旦S4集羣中的某個節點故障,會自動切換到另一個備用節點,可是原節點的內存狀態將丟失。
S4中每一個流處理節點稱爲一個處理節點(Processing Node,PN),其主要工做是監聽事件,當事件到達時調用合適的處理元(Processing Elements,PE)處理事件。
事件監聽器(Event Listener)負責監聽事件並轉交給PE容器(Processing Element Container,PEC),由PEC交給合適的PE處理業務邏輯。配置文件中會配置PE原型(PE prototype),包括其功能、處理的事件類型(event type)、關心的key以及關心的key值。每一個PE只負責處理本身所關心的事件,也就是說,只有當事件類型、key類型和key值都匹配時,纔會交由該PE進行計算處理。PE處理完邏輯後根據其定義的輸出方法能夠輸出事件,事件交由分發器(Dispatcher)與通訊層(Communication Layer)進行交互並由輸出器(Emitter)輸出至下一個邏輯節點。
通訊層提供集羣路由(Routing)、負載均衡(Load Balancing)、故障恢復管理(Failover Management)、邏輯節點到物理節點的映射(存放在Zookeeper上)。當檢測到節點故障時,會切換到備用節點,並自動更新映射關係。通訊層隱藏的映射使得PN發送消息時只須要關心邏輯節點而不用關心物理節點。
Twitter Storm是目前普遍使用的流式計算系統,它創造性地引入了一種記錄級容錯的方法。
海量數據離線分析對於MapReduce這樣的批處理系統挑戰並不大,若是要求實時,又分爲兩種狀況:若是查詢模式單一,那麼,能夠經過MapReduce預處理後將最終結果導入到在線系統提供實時查詢;若是查詢模式複雜,例如涉及多個列任意組合查詢,那麼,只能經過實時分析系統解決。實時分析系統融合了並行數據庫和雲計算這兩類技術,可以從海量數據中快速分析出彙總結果。
並行數據庫每每採用MPP(Massively Parallel Processing,大規模並行處理)架構。MPP架構是一種不共享的結構,每一個節點能夠運行本身的操做系統、數據庫等。每一個節點內的CPU不能訪問另外一個節點的內存,節點之間的信息交互是經過節點互聯網絡實現的。
將數據分佈到多個節點,每一個節點掃描本地數據,並由Merge操做符執行結果彙總。
Merge操做符:系統中存在一個或者多個合併節點,它會發送命令給各個數據分片請求相應的數據,每一個數據分片所在的節點掃描本地數據,排序後回覆合併節點,由合併節點經過merge操做符執行數據彙總。Merge操做符是一個統稱,涉及的操做多是limit、order by、group by、join等。
若是Merge節點處理的數據量特別大,能夠經過Split操做符將數據劃分到多個節點,每一個節點對一部分數據執行group by、join等操做後再合併最終結果。如圖13-10,假如須要執行"select*from A,B where A.x=B.y",能夠分別根據A.x和B.x的哈希值將表A和B劃分爲A0、A1以及B0、B1。由兩個節點分別對A0、B0以及A一、B1執行join操做後再合併join結果。
Greenplum是EMC公司研發的一款採用MPP架構的OLAP產品,底層基於開源的PostgreSQL數據庫。
Vertica在架構上與OceanBase有類似之處。
Google Dremel是Google的實時分析系統,能夠擴展到上千臺機器規模,處理PB級別的數據。
Dremel系統融合了並行數據庫和Web搜索技術。首先,它借鑑了Web搜索中的「查詢樹」的概念,將一個巨大複雜的查詢,分割成大量較小的查詢,使其能併發地在大量節點上執行。其次,和並行數據庫相似,Dremel提供了一個SQL-like的接口,且支持列式存儲。
Dremel與MapReduce的比較 MapReduce的輸出結果直接由reduce任務寫入到分佈式文件系統,所以,只要reduce任務個數足夠多,輸出結果能夠很大;而Dremel中的最終數據匯聚到一個根節點,所以通常要求最終的結果集比較小,例如GB級別如下。 Dremel的優點在於實時性,只要服務器個數足夠多,大部分狀況下可以在3秒之內處理完成TB級別數據。