传世的关系模型,巧夺天工的分布式数据库设计
Hadoop生態的分布式數據庫
1、什么是分布式數據庫?
從狹義的理解就是分布式關系型數據庫,主要特指目前熱門的NewSQL。
從廣義的理解,分庫分表的傳統關系型數據庫,傳統關系型數據庫集群,關系型數據庫的主從架構,分布式KV數據庫(例如:HBase),分布式文檔數據庫(例如:MongoDB),分布式關系數據庫(例如:TiDB)等,統稱為分布式數據庫。
本文主要講Google一脈相承的Hadoop生態下的分布式數據庫架構設計,以及傳統RDBMS與NoSQL的分布式環境下的一致性對比。
2、Hadoop HDFS的數據存儲模型
最早Google發明了GFS分布式文件系統,之后對應的開源項目就是鼎鼎大名的Hadoop HDFS。
GFS/HDFS的特點表現在順序的、成塊的、無索引的向文件塊中寫入數據,并在集群環境中按塊(block)均勻分布存儲,使用時再根據MapReduce、Spark的并行任務,按塊批次的讀取分析。這樣就把寫入和并行讀取的性能發揮到了極致,具備了任何建立索引的數據庫都無法比擬的讀寫速度。
HDFS的數據寫入結構示意圖
上圖是一個寫入HDFS數據的例子,我們需要知道HDFS這些事情:
需要寫入HDFS的文件會被分成數據塊,一個數據塊通常是64M或者128M。
數據塊在HDFS集群中默認有三個副本,平均分配在不同的DataNode數據節點上。
由于HDFS的分布式架構是中心化管理,因此并沒有數據節點主副的概念,只有順序的概念,所有數據節點都是存儲數據塊副本的,全部通過namenode節點安排數據節點的寫入順序。
數據節點的寫入過程就像一個數據管道,根據客戶端就近原則,形成數據節點的排隊,當第一個節點寫入數據包后,然后再向數據管道的下一個數據節點復制,以此類推,并得到完成確認。
3、HBase的架構設計
為了更好的理解HBase/Bigtable,一定需要先鋪陳一下它們所依賴的分布式文件系統基礎環境,然后再看看這些巧奪天工的分布式數據庫設計如何形成的。
由于GFS/HDFS集群的高性能設計是建立在放棄隨機查找的基礎之上。那么如何既能擁有隨機查找的特性,又能充分利用好HDFS/GFS的集群優勢,而且還能在分布式環境下,具備數據寫入的強一致性呢?這才涌現出了HBase/Bigtable這類基于分布式文件系統的分布式數據庫。
但大家要注意了,實際上HBase/Bigtable的隨機查找設計目標并不是解決復雜的join關聯查找或二次索引范圍查找,而是實現簡單的一個K-V查詢模型,滿足海量數據的存放條件下,通過主鍵查找結果,能達到毫秒級響應的數據庫。
HBase的數據寫入結構示意圖
上圖就是HBase的寫入過程以及HDFS作為物理層支撐的架構示意圖。
HBase按照LSM-Tree索引加上SSTable數據結構建立了NoSQL常用的數據存儲模型。寫入過程分成了下面幾個部分:
客戶端向HBase的Region Server寫入數據,會首先進入到WAL(Write-Ahead-Log)預寫日志中,然后再進入到選擇的Region的MemStore中,那這個WAL的目的是什么呢?保命用的!因為一旦Region Server斷電或異常崩潰,MemStore的數據是在內存里,肯定就丟了,MemStore恢復的時候就靠WAL存的日志數據了。MemStore真正同步數據后,WAL才會從本地寫入HDFS,否則回滾。
Region的MemStore是一個放在內存里的高速操作區,MVCC事務操作,最近寫入記錄讀取都可以在此處快速完成,當數據在MemStore寫滿后,就會刷入到Store File磁盤存儲區。
Store File存儲區就是不斷通過memstore刷盤而形成的HFile,每個HFile默認分配128M,大小正好與HDFS的一個數據塊(block)一致,HFile的物理位置就是存儲在HDFS的每個數據塊中,HFile就是不可更改的了,并通過HDFS的副本機制,形成三副本保證數據的可靠性。
3、HDFS與HBase的協作配合
從上述的HDFS和HBase系統的配合中(GFS與BigTable同理)我們可以看到Hadoop生態體系設計的巧妙結構:
HDFS對于大文件塊的順序寫入,批量分析,HDFS的無索引、順序寫入、管道復制機制充分體現了Google的暴力美學~解決問題的方式務實、簡單、直接、高效。
HBase作為列簇設計的K-V數據庫,又實現了細膩入微的設計思想,通過LSM-Tree索引和SSTable數據結構建立起原生數據庫存儲層。
HBase機制上WAL、MemStore、StoreFile形成數據操作的多元素協作。
HBase架構上HRegion Server、HRegion、HLog、HStore層層嵌套,形成分布式數據庫的集群化能力。
最關鍵的就是HBase與HDFS的分工思想,HBase解決業務數據記錄寫入,K-V隨機查找(毫秒級),由Region Server控制的行級事務等一些列分布式數據庫特征;而HDFS解決小文件匯聚成大文件的高性能處理,分布式文件系統的海量存儲,數據多副本的可靠性,以及成為Mapreduce、Spark、Hive等其他框架與HBase之間協作的基礎平臺。
?
分布式環境下數據庫的一致性
首先數據庫的一致性,從傳統的關系型數據庫講,就是指在一個庫中一次業務操作,無論涉及多少張表,多少行集,要么都失敗,要么都成功,不能出現結果和預想的不一致,就是所謂的事務ACID特性中最重要的強一致性。
事務具有4個特征,分別是原子性、一致性、隔離性和持久性,簡稱事務的ACID特性;
(一)、原子性(atomicity)
一個事務要么全部提交成功,要么全部失敗回滾,不能只執行其中的一部分操作,這就是事務的原子性
(二)、一致性(consistency)
事務的執行不能破壞數據庫數據的完整性和一致性,一個事務在執行之前和執行之后,數據庫都必須處于一致性狀態。
(三)、隔離性(isolation)
事務的隔離性是指在并發環境中,并發的事務相互隔離的,一個事務的執行不能不被其他事務干擾。
我們重點說說分布式環境下數據庫的一致性(consistency)特點:
1、MySQL的分布式一致性
一個特別典型的例子就是MySQL的主從復制架構:異步,半同步,全同步。
異步:盡管主庫保證了數據的強一致性,但是數據一旦寫給binlog,主庫就無視了從庫的一致性,繼續忙自己的事情,那么這個過程就是異步的,從庫從binlog中拿到結果再重放保證與主庫的一致性,我們把這個過程叫做最終一致性。
半同步:MySQL 主庫寫入binlog后,至少集群中任意一個MySQL從庫反饋主庫,它同步成功了,那么主庫就繼續忙自己的事了,我們可以把這個過程稱為弱一致性。
全同步:自然不用想了,MySQL主庫寫入binlog,集群其他節點都要重放后,報告同步成功了,主庫才會忙其他事情,這就是分布式環境的強一致性了!
弱一致性是在強一致性和最終一致性中尋找一個平衡,至少有一個備份點是必須與主保持一致的,那么數據的可靠性是不是就提升了,同時性能上也不至于太差了。
2、NoSQL的分布式一致性
其次糾正一個錯誤的觀點,NoSQL不能都視之為弱一致性。得具體看是哪個NoSQL框架,例如:MongoDB我們認為是NoSQL,它在副本集模式下,可以靈活地設置一致性規則,其中majority選項的意思是主庫寫入oplog后,大多數成員需要確認才行。
這個夠撓頭吧,怎么又來了個大多數,這豈不是在弱一致性和強一致性之間又出現了一種一致性模式,可實際就是這樣。
我們再回來談本文重點提到的一個NoSQL:HBase,它可的確是分布式環境下的強一致性啦,是不是顛覆了你對NoSQL的認知了!
因為HBase的是基于行級的事務,也就是說當一次寫入記錄的過程,一定是一個Region只分配一個Region Server寫入,而且對于行級數據的操作要不寫入成功,要不失敗。如果一個節點掛了,恢復節點在沒有恢復完數據之前就是不可用了。
HBase在CAP定理中保證了CP,舍棄了A:一致性C(HBase同一時間寫入不同節點的數據必須一致),容錯性P(即便有節點出錯,系統還能正常運行),但是這個可靠性A就有問題(必須等待節點恢復完成,對請求就不能立刻有響應了)
最后再說說有些NoSQL的弱一致性為什么就可以被接受??
回顧一下最開始的MySQL的異步模式復制,它為什么是MySQL的默認復制模式??
若滿足最終一致性,那么這類分布式系統選擇了CAP定理中的AP,就是說為了保證系統內部無論是否出錯,都會給客戶響應。代價就是分布式各節點的數據副本有可能不一致,但這個問題不是此類系統業務最在乎的事情,往往系統的高性能,并能為客戶端提供快速響應力才是關鍵目標,MySQL的默認主從復制如此,有些NoSQL亦如此。
?
傳世的關系模型
首先從數據庫的表達力來講,并不是NoSQL要強于關系模型,事實上SQL的表達力是無出其右的,否則就不會興盛四十年而不衰,就不會有Hive SQL、Spark SQL、Presto、Impala這些以支持SQL交互為起點的NoSQL上層框架存在的必須性。
看吧,還沒到NewSQL這一代的時候,返祖的現象就已經出現了!
1、我們再溫故知新一下什么是關系模型:
關系型模型之父Edgar F. Codd,在1970年Communications of ACM 上發表了《大型共享數據庫數據的關系模型》這就是永恒的經典,關系模型的語義設計達到了40年來普世的易于理解,語法的嵌套,閉環,完整。
關系型模型之父Edgar F. Codd
原始的關系模型:
結構(structure)結構的主要特征就是關系(relation),表格就是實現形式關系定義在類型(type or domain)的基礎上,屬性(attribute)就是類型的實際值,N個屬性就是描述了N元關系每個關系都至少有一個候選鍵(唯一標識符),它是屬性的組合,通常只有一個屬性。元組(tuple)就是屬性的集合
完整性(integrity)實體完整性規則:主鍵屬性不允許null,不能存在任何不匹配的外鍵取值。
操作(manipulation)關系的運算符集合(限制、投影、積、交、并、差、連接),關系表達式賦值關系(例如:關系1 并 關系2賦值給關系3),操作的輸入關系和輸出關系,形成了閉包(closure)性質,就可以寫出嵌套表達式
原始理論具體到實現再翻譯成我們好理解的描述:結構、完整性、操作就構成了現在傳統數據庫的關系模型。
結構:就是我們經常要先對數據庫預先定義的表名和字段(名稱、類型)
完整性:就是表的主鍵不能為空,表與表之間的主外鍵關聯必須保證是完整的,外鍵一定是能找到主鍵的。
操作:那就是SQL表達式啦,SQL的子查詢就是典型的閉包(Closure),可以形成嵌套表達式。
2、雖然NoSQL很火,但我們這個世界沒法 NO SQL
HBase/Bigtable可以認為是NoSQL的典型代表
恰恰NoSQL發展至今,出現了Hive SQL,Spark SQL,Presto,Impala,直到基于Google Spanner論文的TIDB,CockroachDB等NewSQL的不斷涌現,才讓我們用實踐證明,無論是NoSQL也好,NewSQL也罷,它們的查詢語言客戶端又回到了SQL。
我們只是在大數據領域需要替換關系型數據庫的存儲邏輯,使得數據庫更分布式化,更容易實現擴展。這是符合單機性能到了天花板后,必須橫向擴展的硬需求,但這也并不是說關系模型就過時了!
像HBase/Bigtable這樣的NoSQL,大多數采用了LSM-Tree的索引機制,來替換RDBMS的B-Tree機制,這么做都是為了能實現內存與磁盤,寫入與查找的更平衡利用。
它們又用數據分片的水平切分替換RDBMS的分庫分表的垂直切分,讓節點與集群的水平伸縮性更為自動化,而不是像分庫分表那樣進行人工復雜的介入。
TiDB這些NewSQL的出現恰恰是在縫合關系模型和分布式存儲之間的裂縫,面向客戶端依然是關系模型,強化分布式業務更新的強一致性(分布式事務,這是最難的最復雜的地方),面向存儲則堅定的選擇K-V模型。
例如TIDB的TIKV集群采用的就是rocksdb,rocksdb的底層索引機制又和HBase/Bigtable采用相同設計機制的又一個nosql成員。
因此并不是Google的Spanner論文以及F1,TiDB這些實現技術開了歷史的倒車,恰恰是對狂熱的nosql運動的一種反思,對成為經典的SQL關系模型理論的一種認真思考和融合。
任何新技術都是站在前輩的基礎上開啟的,我們總要回頭望望,反思新技術的運用到底我們得到了什么,又失去了什么!
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
?
?
?
?
總結
以上是生活随笔為你收集整理的传世的关系模型,巧夺天工的分布式数据库设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: list dict 性能测试
- 下一篇: ORA-07445 [kxsxsi()+