1、從單機數據庫說起(Mysql、Oracle、PostgreSQL)
關系型數據庫起源自1970年代,其最基本的功能有兩個:
-
把數據存下來;
-
滿足用戶對數據的計算需求。
第一點是最基本的要求,如果一個數據庫沒辦法把數據安全完整存下來,那么后續的任何功能都沒有意義。當滿足第一點后,用戶緊接着就會要求能夠使用數據,可能是簡單的查詢,比如按照某個Key來查找Value;也可能是復雜的查詢,比如要對數據做復雜的聚合操作、連表操作、分組操作。往往第二點是一個比第一點更難滿足的需求。
在數據庫發展早期階段,這兩個需求其實不難滿足,比如有很多優秀的商業數據庫產品,如Oracle/DB2。在1990年之后,出現了開源數據庫MySQL和PostgreSQL。這些數據庫不斷地提升單機實例性能,再加上遵循摩爾定律的硬件提升速度,往往能夠很好地支撐業務發展。
接下來,隨着互聯網的不斷普及特別是移動互聯網的興起,數據規模爆炸式增長,而硬件這些年的進步速度卻在逐漸減慢,人們也在擔心摩爾定律會失效。在此消彼長的情況下,單機數據庫越來越難以滿足用戶需求,即使是將數據保存下來這個最基本的需求。
2、分布式數據庫之Nosql的進擊(HBase/Cassadra/MongoDB)
HBase是其中的典型代表。HBase是Hadoop生態中的重要產品,Google BigTable的開源實現。
HBase本身並不存儲數據,這里的Region僅是邏輯上的概念,數據還是以文件的形式存儲在HDFS上,HBase並不關心副本個數、位置以及水平擴展問題,這些都依賴於HDFS實現。和BigTable一樣,HBase提供行級的一致性,從CAP理論的角度來看,它是一個CP的系統,並且沒有更進一步提供 ACID 的跨行事務,也是很遺憾。
HBase的優勢在於通過擴展Region Server可以幾乎線性提升系統的吞吐,及HDFS本身就具有的水平擴展能力,且整個系統成熟穩定。
但HBase依然有一些不足
- 首先,Hadoop使用Java開發,GC延遲是一個無法避免問題,這對系統的延遲造成一些影響。
- 另外,由於HBase本身並不存儲數據,和HDFS之間的交互會多一層性能損耗。
- 第三,HBase和BigTable一樣,並不支持跨行事務,所以在Google內部有團隊開發了MegaStore、Percolator這些基於BigTable的事務層。Jeff Dean承認很后悔沒有在BigTable中加入跨行事務,這也是Spanner出現的一個原因。
3、分布式數據庫之RDMS的救贖(Cobar、Zebra、Atlas、Vitess)
RDMS系統做了不少努力來適應業務的變化,也就是關系型數據庫的中間件和分庫分表方案。做一款中間件需要考慮很多,比如解析 SQL,解析出ShardKey,然后根據ShardKey分發請求,再合並結果。另外在中間件這層還需要維護Session及事務狀態,而且大多數方案並不支持跨shard的事務。還有動態的擴容縮容和自動的故障恢復,在集群規模越來越大的情況下,運維和DDL的復雜度是指數級上升。
4、NewSQL的發展
2012~2013年Google 相繼發表了Spanner和F1兩套系統的論文,讓業界第一次看到了關系模型和NoSQL的擴展性在一個大規模生產系統上融合的可能性。
Spanner 通過使用硬件設備(GPS時鍾+原子鍾)巧妙地解決時鍾同步的問題,而在分布式系統里,時鍾正是最讓人頭痛的問題。Spanner的強大之處在於即使兩個數據中心隔得非常遠,也能保證通過TrueTime API獲取的時間誤差在一個很小的范圍內(10ms),並且不需要通訊。Spanner的底層仍然基於分布式文件系統,不過論文里也說是可以未來優化的點。
Google的內部的數據庫存儲業務,大多是3~5副本,重要的數據需要7副本,且這些副本遍布全球各大洲的數據中心,由於普遍使用了Paxos,延遲是可以縮短到一個可以接受的范圍(寫入延遲100ms以上),另外由Paxos帶來的Auto-Failover能力,更是讓整個集群即使數據中心癱瘓,業務層都是透明無感知的。F1是構建在Spanner之上,對外提供了SQL接口,F1是一個分布式MPP SQL層,其本身並不存儲數據,而是將客戶端的SQL翻譯成對KV的操作,調用Spanner來完成請求。
5、Spanner和F1的追隨者
Spanner/F1論文引起了社區的廣泛的關注,很快開始出現了追隨者。第一個團隊是CockroachLabs做的CockroachDB。CockroachDB的設計和Spanner很像,但是沒有選擇TrueTime API ,而是使用HLC(Hybrid logical clock),也就是NTP +邏輯時鍾來代替TrueTime時間戳,另外CockroachDB選用Raft做數據復制協議,底層存儲落地在RocksDB中,對外的接口選擇了PG協議。
另一個追隨者就是我們做的TiDB。TiDB本質上是一個更加正統的Spanner和F1實現,並不CockroachDB那樣選擇將SQL和KV融合,而是像Spanner和F1一樣選擇分離。
和 Spanner一樣,TiDB是一個無狀態的MPP SQL Layer,整個系統的底層是依賴 TiKV 來提供分布式存儲和分布式事務的支持,TiKV的分布式事務模型采用的是Google Percolator的模型,但是在此之上做了很多優化,Percolator的優點是去中心化程度非常高,整個繼續不需要一個獨立的事務管理模塊,事務提交狀態這些信息其實是均勻分散在系統的各個key的meta中,整個模型唯一依賴的是一個授時服務器,在我們的系統上,極限情況這個授時服務器每秒能分配 400w以上個單調遞增的時間戳,大多數情況基本夠用了(畢竟有Google量級的場景並不多見),同時在TiKV中,這個授時服務本身是高可用的,也不存在單點故障的問題。
TiKV和CockroachDB一樣也是選擇了Raft作為整個數據庫的基礎,不一樣的是,TiKV整體采用Rust語言開發,作為一個沒有GC和 Runtime的語言,在性能上可以挖掘的潛力會更大。不同TiKV實例上的多個副本一起構成了一個Raft Group,PD負責對副本的位置進行調度,通過配置調度策略,可以保證一個Raft Group的多個副本不會保存在同一台機器/機架/機房中。
6、未來趨勢
1、數據庫會隨着業務雲化,未來一切的業務都會跑在雲端,不管是私有雲或者公有雲,運維團隊接觸的可能再也不是真實的物理機,而是一個個隔離的容器或者「計算資源」
2、多租戶技術會成為標配,一個大數據庫承載一切的業務,數據在底層打通,上層通過權限,容器等技術進行隔離
3、OLAP和OLTP業務會融合,用戶將數據存儲進去后,需要比較方便高效的方式訪問這塊數據,但是OLTP和OLAP在SQL優化器/執行器這層的實現一定是千差萬別的。以往的實現中,用戶往往是通過ETL工具將數據從OLTP數據庫同步到OLAP數據庫,這一方面造成了資源的浪費,另一方面也降低了OLAP的實時性。對於用戶而言,如果能使用同一套標准的語法和規則來進行數據的讀寫和分析,會有更好的體驗。
4、在未來分布式數據庫系統上,主從日志同步這樣落后的備份方式會被Multi-Paxos / Raft這樣更強的分布式一致性算法替代,人工的數據庫運維在管理大規模數據庫集群時是不可能的,所有的故障恢復和高可用都將是高度自動化的。
7、知識拓展
7.1、GPS同步時鍾工作原理
在最初的同步通信系統中,我們會找到一個時鍾源,然后把所有的收發子系統都接到這個時鍾源上。小型的同步通信系統完全可以這樣做,比如一台電腦中的一個同步通信的系統,他們就用電纜線接到一個共同的時鍾源上,再來收發信號。
可是一旦同步通信的系統變大到全國性的呢?如果還用電纜或者光纜接到同一個時鍾源上,會發生很多問題。首先,建設的成本太大了,要在全國范圍內鋪設線路,只為傳輸一個時鍾信號,不划算。其次,如果收發信機分別在黑龍江和廣東,時鍾信號即使以光速傳過去,還會產生一定的延時。
每個GPS衛星上都有2~3個高精度的原子鍾,這幾塊原子鍾互為備份的同時,也互相糾正。另外地面的控制站會定期發送時鍾信號,和每一顆衛星進行時鍾校准。
當然你可能會擔心衛星信號傳送到地面的延遲問題。GPS信號中自帶了誤差糾正碼,接收端可以很容易的把延遲的這段傳輸延遲去掉。另外,由於衛星信號很微弱,只有在室外才能接受的到,因此每個GPS授時系統都應當有室外天線,否則就不能用了。
這樣一來上面列出的兩個問題都解決了。用來鋪設全國性電纜並不是每家公司都有資金實力的,而且鋪設的成本用來買GPS接收器,那肯定可以買到無數個了。而延時的問題,也被GPS出色的編碼系統所解決了。真的是太完美了。
Spanner是如何保證每個事務最后得到的commit timestamp介於這個事務的start和commit之間?
在事務開始階段調用一次TrueTime,返回[t-ε1,t1+ε1],在事務commit階段時再調用一次TrueTime,返回[t2-ε2,t2+ε2],根據TrueTime的定義,顯然,只要t1+ε1<t2-ε2,那么commit timestamp肯定位於start和commit之間。等待的時間大概為2ε,大約14ms左右。可以說,這個延時基本上還可以接受。
7.2、Hybrid Logical Clock(HLC)
每個Cockroach節點都維持了一個混合邏輯時鍾(HLC) ,相關的論文見 HybridLogical Clock paper。HLC時間使用的時間戳由一個物理部件(看作總是接近本地物理時鍾)和一個邏輯部件(用於區分相同物理部件上的事件)組成。它使我們能夠以較少的開銷跟蹤相關聯事件的因果性,類似於向量時鍾(譯注:vector clock,可參考Leslie Lamport在1978年發表的一篇論文《Time, Clocks, and the Ordering of Events in aDistributed System》)。在實踐中,它工作起來更像一個邏輯時鍾:當一個節點收到事件時,它通知本地邏輯HLC由發送者提供的事件時間戳,而當事件被發送時會附加一個由本地HLC生成的時間戳。
Cockroach使用HLC時間為事務選取時間戳。本文中,所有 時間戳 都是指HLC時間,HLC時鍾在每個節點上是都是單一實例的(譯注:也就是說每個節點上只有唯一一個HLC時鍾,不會有兩個時鍾,產生兩個時間的問題)。HLC時鍾由節點上的每個讀/寫事件來更新,並且HLC 時間大於等於( >= )系統時間(wall time)。從來自其他節點的Cockroach請求里接收到的讀/寫時間戳不僅僅用來標識操作的版本,也會更新本節點上的HLC時鍾。這用於保證在一個節點上的所有數據讀寫時間戳都小於下一次HLC時間。
參考:
https://www.oschina.net/news/84386/about-distributed-database?utm_source=tuicool