對於OLTP型數據庫梳理

從數據庫底層來看,數據庫到目前爲止,有這幾種數據結構

1.b樹,b+樹,(mysql,PostgreSQL)

2.lsm樹(LevelDB,RocksDB,TIDB,CockroachDB)

3.基於B+樹和LSM樹改良的樹,比如Fractal樹(TokuDB)

 

下面一一介紹每種樹的典型應用

B樹,B+樹

傳統的關係型數據將數據以B樹的形式存儲在磁盤上,它們也會在RAM上使用B樹維護這些數據的索引,來保證更快的訪問速度。插入的行存儲在B樹的葉子節點上,所有的中間節點用來存儲用於導航查詢語句的原數據。因此,當有數以百萬計的數據被插入到數據庫中時,索引和數據存儲會變得十分大。因此,爲了快速的訪問,需要從磁盤中加載所有數據到內存,但是RAM一般沒有這麼大的空間來存儲所有的數據。因此,數據庫必須從磁盤中讀取部分數據。這種加載數據的場景如下圖所示:

b+樹

圖片引自https://segmentfault.com/a/1190000015892186​​​​

B樹和B+樹區別在於B樹的內部節點有指向關鍵字具體信息的指針,而b+樹沒有,因此b+樹相對b樹,有如下優點

磁盤讀寫代價更低

B+樹的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。

B+樹的查詢效率更加穩定

由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。

 

InnoDB

mysql的InnoDB是大家工作中最常用的數據庫存儲引擎,B+樹,聚簇索引,行級鎖。聚簇索引數據的物理存放與索引都是有序的,它把所有的衛星數據都存儲在葉節點中,內部節點只存放關鍵字和孩子指針。

 

圖片引自https://blog.csdn.net/u010842515/article/details/68929687

InnoDB的所有輔助索引都引用主鍵作爲data域。InnoDB 不會壓縮索引,所以,如果主鍵定義的比較大,其他索引也將很大。如果想在表上定義很多索引,則爭取儘量把主鍵定義得小一些。輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然後用主鍵到主索引中檢索獲得記錄。

圖片引自https://blog.csdn.net/u010842515/article/details/68929687

頁是InnoDB存儲引擎的最小管理單位,每頁大小默認是16KB。以64位操作系統,long型主鍵爲例,一個索引頁可以裝下大概16k/(8+8)=1k個關鍵字,因爲每一級下級索引頁也可以裝下1k個關鍵字,而一級索引指向的二級索引有1k個,因此二級索引就有1k*1k=100萬個關鍵字。如果數據庫一行數據在100字節,那麼每一個數據頁最多可以裝下16*1024/100=160條數據(實際情況是mysql不會把每頁的數據都裝滿,否則再插入一條數據,當前頁就裝不下了,就得在頁間挪動數據了),假如這顆樹只有兩級索引,那麼每相鄰的二級索引指向的葉子節點就有160行數據。那麼這樣一顆二級索引的樹可以指向100萬*160=1.6億數據。

以64位操作系統,36位uuid做主鍵爲例,一個索引頁可以裝下大概16*1024/(36+8)= 372個下級索引,二級索引就有372*372=13萬個關鍵字,如果一行數據在1k字節,那麼每個數據頁可以裝下16行數據,那麼這樣一個二級索引樹可以指向13萬*16=208萬行數據。

綜上innodb的數據和索引都是順序排列的。innodb數據庫設計優化的重點在主鍵索引的長度控制,其次在於控制每行的數據量。設計併發比較高的系統的時候,可以採用冷熱分離的數據庫設計方法,對於熱數據,主鍵採用自增的方式,優先保證數據的插入速度。對於冷數據來說,主鍵可以採用用戶經常批量查詢的字段做主鍵(比如用戶id+熱數據id),可以充分利用聚簇索引的數據連續的特點。儘量減少讀取磁盤的次數。

 

 

MyISAM

mysql數據庫的MyISAM表也是基於B+Tree的,它的葉子節點上的data,並不是數據本身,而是數據存放的地址。主索引和輔助索引沒啥區別,只是主索引中的key一定得是唯一的。這裏的索引都是非聚簇索引。他的數據的物理地址是凌亂的,拿到這些物理地址,按照合適的算法進行I/O讀取,於是開始不停的尋道不停的旋轉。不過,如果涉及到大數據量的排序、全表掃描、count之類的操作的話,還是MyISAM佔優勢些,因爲索引所佔空間小,這些操作是需要在內存中完成的。MyISAM引擎由於更新的時候採用表鎖的方式,目前多應用在只讀數據的查詢方面。

圖片引自https://blog.csdn.net/u010842515/article/details/68929687

 

LSM樹

傳統數據庫的寫入是有瓶頸的,爲了迎合以寫爲主的系統的需要,數據庫需要能夠擁有快速插入數據的能力。因此LSM樹應運而生。

LSM的原理是有寫入請求的時候, 爲了保護內存中的數據,在磁盤上先記錄logfile(當內存中的數據flush到磁盤上時,就可以拋棄相應的Logfile),然後寫入到內存中(內存沒有尋道速度的問題,隨機寫的性能得到大幅提升),在內存中構建一顆有序小樹,隨着小樹越來越大,內存的小樹會flush到磁盤上。隨着小樹越來越多,讀的性能會越來越差,因此需要在適當的時候,對磁盤中的小樹進行merge,多棵小樹變成一顆大樹。當讀時,優先看內存中有沒有匹配的key,如果有則返回,沒有則遍歷所有的樹(RocksDB,Cassandra增加了Bloom Filter來判斷請求的key是否可能在樹中),但在每顆小樹內部數據是有序的。

圖片引自https://www.cnblogs.com/yanghuahui/p/3483754.html

 

LevelDB,RocksDB

LevelDB 是由 Google 開發的單機版 key-value存儲系統,是基於 LSM(Log-Structured-Merge Tree) 的典型實現,RocksDB是Facebook基於LevelDB優化的一種嵌入式單機版Key-value存儲系統,該數據庫能夠充分利用閃存的性能,大大提升應用服務器的速度,在其上基於一致性協議可以構建複雜的系統,比如TIDB,CockroachDB。

 

Fractal樹

Fractal樹是一種寫優化的磁盤索引數據結構,集合了LSM寫入速度快的優點和b+樹讀取快的優點。它索引維護了類似b+樹的結構,利用索引節點的MessageBuffer緩存更新操作,充分利用數據局部性原理, 將隨機寫轉換爲順序寫,這樣極大的提高了隨機寫的效率。從理論複雜度和測試性能兩個角度上看, Fractal樹的Insert/Delete/Update操作性能優於B+樹。 但是讀操作性能低於B+樹。Fractal樹支持在做DDL操作的同時(例如添加索引),用戶依然可以執行寫入操作, 這個特點是Fractal樹樹形結構天然支持的。Tokutek研發團隊的iiBench測試結果顯示: TokuDB(採用Fractal樹)的insert操作(隨機寫)的性能比InnoDB快很多,而Select操作(隨機讀)的性能低於InnoDB的性能,但是差距較小

在Fractal樹中,進行的添加列,刪除列,插入,更新等任何操作都會被當做操作消息存儲在非葉節點上。由於操作只是被簡單地存儲在緩存或者任何次級索引緩存(secondary index buffer)中,所有的操作都會被迅速執行結束。當某一個節點的緩存滿了之後,這些操作消息會依次從根節點,經過非葉節點,向葉節點進行傳遞。葉節點仍然存儲着真實數據。當進行讀時,讀操作會考慮查詢路徑節點上的所有操作消息來獲取真實的數據狀態。但是由於tokudb會盡力將所有非葉節點緩存在內存中,所以這一過程也很快。只是分形樹的範圍查詢基本等價於進行N次單條數據查詢操作,因此效率比b+樹低很多

在線更新表結構實現也是基於消息來實現的, 但和Insert/Delete/Update操作不同的是, 前者的消息下推方式是廣播式下推(父節點的一條消息,應用到所有的兒子節點), 後者的消息下推方式單播式下推(父節點的一條消息,應用到對應鍵值區間的兒子節點), 實現類似於Insert操作。

圖片引自https://segmentfault.com/a/1190000015892186

 

NewSQL

單機數據庫滿足不了互聯網線上數據規模,google Spanner/F1論文的發表,給大家指明瞭一個新的方向。出現了NewSQL這個概念,NewSQL是指這樣一類新式的關係型數據庫管理系統,針對OLTP(讀-寫)工作負載,追求提供和NoSQL系統相同的擴展性能,且仍然保持ACID和SQL等特性,衝破CAP的枷鎖,在三者之間完美平衡,開源領域以TIDB,CockroachDB爲代表

CAP理論:一個分佈式系統最多隻能同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。

圖片引自http://www.hollischuang.com/archives/666

 

TIDB

TiDB 是 PingCAP 公司受 Google Spanner / F1 論文啓發而設計的開源分佈式 HTAP (Hybrid Transactional and Analytical Processing) 數據庫,結合了傳統的 RDBMS 和 NoSQL 的最佳特性。TiDB 兼容 MySQL,支持無限的水平擴展,具備強一致性和高可用性。一個 TiDB 集羣擁有幾個 TiDB 服務、幾個 TiKV 服務和一組 Placement Deiver(PD)(通常 3-5 個節點)。TiDB 服務是無狀態 SQL 層,TiKV 服務是鍵值對存儲層,PD 則是管理組件,從頂層視角負責存儲元數據以及負載均衡,TiDB 可以進行在線 DDL

圖片引自https://www.oschina.net/translate/how-to-do-performance-tuning-on-tidb

假設我們使用如下 SQL 來插入一條數據到表 t

INSERT INTO t(id, name, address) values(1, “Jack”, “Sunnyvale”);

執行流程如下圖

圖片引自https://www.oschina.net/translate/how-to-do-performance-tuning-on-tidb

TiDB 只存儲鍵值對,那麼要如何實現諸如數據庫、表和索引等高層概念呢?在 TiDB 中,每個表都有一個關聯的全局唯一編號,被稱爲 “table-id”。特定表中的所有數據(包括記錄和索引)的鍵都是以 8 字節的 table-id 開頭的。對於每行表數據,它的 key 是一個 64 位整數,稱爲 Handle ID。如果一張表存在 int 類型的主鍵,會把主鍵的值當作表數據的 Handle ID,否則由系統自動生成 Handle ID。表數據的 value 由這一行的所有數據編碼而成。在讀取表數據的時候,可以按照 Handle ID 遞增的順序返回。

TiDB 的索引數據和表數據一樣,也存放在 TiKV 中。每個索引都有一個名爲 “index-id” 的表範圍的唯一編號。它的 key 是由索引列編碼的有序 bytes,value 是這一行索引數據對應的 Handle ID,通過 Handle ID 我們可以讀取這一行的非索引列。

在 TiDB 中,Region 表示一個連續的、左閉右開的鍵值範圍 [start_key,end_key)。每個 Region 有多個副本,並且每個副本稱爲一個 peer 。每個 Region 也歸屬於單獨的 Raft 組,以確保所有 peer 之間的數據一致性。同一表的臨近記錄很可能位於同一 Region 中。當集羣第一次初始化時,只存在一個 Region 。當 Region 達到特定大小(當前默認值爲96MB)時, Region 將動態分割爲兩個鄰近的 Region ,並自動將數據分佈到系統中以提供水平擴展。

3.0版本後,tidb增加了Range分區和Hash分區的方式,一下將調度的靈活性提高了,對分片的索引採用hash分區,這樣一方面讓數據庫避免了熱點的問題,另一方面對於數據的定位更快了,時間複雜度o(1)。對於大表來說設計好數據的分片就可以了,取數據的時候取到的數據就在一個分片上,避免了數據不在一臺機器上的大範圍網絡查詢。

TiDB支持數據導出功能,通過一個叫作 Pump 的小程序,彙總寫入到 Kafka 集羣。在下游有一個叫 Drainer 的組件來消費 Kafka 的數據,按照事務的順序還原成 SQL,同步到下游數據庫。TiDB支持多源多目的地的數據同步,通過Wormhole的工具實現。PingCAP 也在研發自己的 OLAP 的存儲引擎,應該是列式存儲引擎,如果能推出來,那麼對於實時分析數據來說就比較方便了

目前的new SQL底層普遍基於RocksDB,這是一個寫優化的key-value數據庫,但是讀效率沒有b+樹高,但是可以通過增加數據服務器數量來彌補這個缺陷,機器費用的增加相比人力的投入來說忽略不計,從理論上具備了代替分庫分表方案的條件。

 

參考文檔

https://segmentfault.com/a/1190000015892186

https://www.jianshu.com/p/1ed61b4cca12

http://www.cnblogs.com/yanghuahui/p/3483047.html

https://blog.csdn.net/u010842515/article/details/68929687

https://www.jianshu.com/p/6636e4671f83

https://www.jianshu.com/p/6f68d3c118d6

https://www.jianshu.com/p/3832ae37fac4

https://blog.csdn.net/doc_sgl/article/details/51068131

https://www.oschina.net/translate/how-to-do-performance-tuning-on-tidb

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章