TDDL思考總結
單機資料庫
分散式資料庫
TDDL原理與最佳實踐
1. 資料庫的結構
1.1. KV儲存(id是K)
1.2. B+樹與紅黑樹
B+樹的特點是葉子節點是塊狀,一個葉子裡面有多個資料,相鄰資料是存在一起的,123,456起等,
而磁碟也是按塊的,B+樹的資料是按塊儲存的正好和磁碟的塊的概念是相符的,
所以在資料庫裡面大多采用了B+樹或者類似的一種結構來儲存資料。
在java中實現treemap時選擇是紅黑樹而不是B+樹,B+面向的是磁碟的結構,
java的treemap面向的是記憶體,隨機讀寫資料快;
另外一個原因是,B+樹為了減少分裂的次數會在每個葉子結點中預留幾個空洞來存入未來的資料,
這個特點在磁碟中是可以的,因為磁碟都是白菜價,浪費一點沒有關係,但記憶體就不一樣了;
紅黑樹本質是一顆二叉樹,每個葉子只有一條資料,不需要預留任何的空間,
在記憶體中就不會造成空間的浪費,也就是這兩點,才選擇了紅黑樹來實現java中的treemap.
任何一種技術脫離了它的場景都是沒有意義的;
有些資料庫不是按行存的,是按列存的,這樣可對列的特點進行壓縮,減少儲存空間,
進行max/min等運算也快,但這種特點不適合更新;
沒有一種資料庫讀的快寫的也快,讀寫效能的差距也是由於背後所使用的儲存不同導致的,
如hbase使用的是lsm-tree這種儲存,它的特點是寫的很快,順序寫,但讀的稍微有點慢,
所以hbase經常用來存日誌,產生的量,對讀的效能要求不高。
要判斷讀的多還是寫的多,如果讀的多,還要判斷讀的特點,是隨機讀還是範圍的讀,寫的話,
是隻寫還是會有刪除和更新;B樹是面向磁碟的,紅黑樹是面向記憶體的;
2. 索引查詢優化器
主表和索引表都是對映,查詢如果使用到了索引,就會分為兩步,第一步先查索引,第二步通過索引再查主表,
這一步叫回表。如果查詢中的列(seletc a,b)都是索引中的列,那麼就只有一步,只要查索引表就可以了,
就不需要回表了,這叫索引覆蓋。 如果索引包含所有的列,也就是主鍵對記錄的索引,就是聚簇索引。
如果索引包含部分的列,就是非聚簇索引, 非聚簇索引在查詢的時候就可能需要做一個回表的操作才能查出所有的列來。
索引太多時有兩個缺點, 佔空間,對記錄進行寫操作時也要修改索引,寫入效能的下降。
沒有索引時就會全表掃描。
主表的每一條記錄都是一個KV對映,K就是主鍵,V就是整條記錄,而索引就是列對K的索引而已。
區分度比較高就比較適合做索引列。
從某種程度上說,索引也是一種關係型資料庫的表。
關係型的資料庫都有索引的概念,而NoSQL是沒有索引的概念的,比如hbase就沒有索引,只能按照rowkey來查,
不能按照其他欄位來查。
sql語句會經過解析器,經過解析變成一個資料結構, 查詢優化器會分析這個資料結構是什麼意思,怎樣執行會比較快,
會生成一個執行計劃,這個計劃就包括查字典的整個過程。
SQL->Optimizer->plan,底下的儲存按照plan就會得到高效而且準確的結果。
那麼查詢優化器會做哪些事情呢?
1.索引選擇
當where有兩個或者多個列都有索引時,就會涉及到索引選擇的問題。一般會根據區分度選擇合適的索引。
2.下推
select t1.name,t2.name from t1 join t2 on t1.id = t2.id
就是說會讓一些操作提前執行來減少中間過程的資料,也就是優化的過程。
3.join策略的選擇(自己瞭解)
index netxt roup、block next roup,
mysql語句前加上extern就會展示這條語句的執行計劃,能大概讀懂
事務也是區分關係型資料庫與nosql的指標
3. 分散式資料庫
產生分散式資料庫的原因,最重要的有兩個:
1.單機的硬碟容量(可能還包括記憶體容量、cpu容量、網路容量)不夠,需要儲存到多塊硬碟上
2.安全性原因,資料庫存到多個地方備份
RAID磁碟陣列的出現與分散式資料庫的出現相似,一個是空間,一個是安全,
RAID0的概念是把資料拆開儲存在兩塊硬碟上,比如C盤資料儲存在A上,D盤儲存在B上,RAID1的概念是把資料複製儲存在兩個地方,比如CD盤在A盤上存一份,也在B盤上存一份。
RAID01或者RAID10就是把兩者結合起來,資料既分塊,又對每塊資料進行備份。
對應到分散式資料庫裡面,就有了這樣的概念:
RAID0對應分散式資料庫裡的Partition(擴充套件性,一個分割槽不夠,繼續擴)
RAID1對應分散式資料庫裡的Replication(安全性,一個掛了,不會掉資料)
如何將資料複製到不同的地方去?
1.非同步?
2.同步?
假設有兩塊磁碟0和1(或者就是兩個資料庫),那如何保證兩個資料是完全一樣的?
一種方式是同時向兩個地方寫,寫完就是成功了;
另一種方式是隻寫0,讓0去寫1,這就產生了如何返回資料寫成功了?同步是0寫完1才返回成功,
非同步是寫完0就返回成功(如果此時就去讀1就會出現還沒有寫入的資料,就會出現延遲,好處是不用等所有的庫都寫完,它的寫入的延遲會低一些),這是兩個點的情況,如果有更多的點(就是把一個點的資料複製了好幾份),則就不能接受只有同步或者只有非同步(只寫一個點就返回)的情況了,就要把同步和非同步結合起來,即每次同步寫數個點後返回成功,剩下非同步寫剩下的點。
那在分散式資料庫中如何才能保證讀到的資料是一致或者最新的呢?
W+R>N,W代表同步寫的個數,N表示總結點個數,即寫的少,讀的就越多,寫的多,讀的就越少。
mysql是有主庫和備庫的區別的,主備庫資料是完全一樣的。內部的方案是讀寫都在主庫,備庫全部採用非同步的方式備份。這是犧牲了備庫的讀效能來換取的,可以講到同步的資料又不要同步的複製,來保證寫的效能的提升。
如果主庫掛掉的話,怎麼從剩下的備庫中選舉主庫呢?大多是用PAXOS演算法或者衍生的演算法來選舉主庫,主要原理是獲取多數支援的那一個才能是主庫。這樣就是自動的的過程,內部往往簡單粗暴的,當主庫掛掉的時候人工選擇一個備庫當主庫。
partition和replication在單機資料庫中也是存在的,在單機資料庫是也有分割槽表的概念,雖然是同一個機器,也會把表分成了好幾個部分, 在單機資料庫裡面也會用磁碟陳列的方式做一些冗餘,在單機資料庫裡也會這兩種概念,那在分散式資料庫要把這兩點單獨的拿出來說呢?最重要的是因為分散式資料庫多了網路,延遲變大了,在單機裡cpu匯流排的延遲是納秒級,走網路的話延遲可能是毫秒級的。正是因為有延遲在在分散式資料庫中才會把這兩個東西單獨拿出來說。
以上主要是replication的講解;
partition的講解在tddl裡;
4. Taobao Distributed Data Layer
TDDL產生背景:
單一資料庫無法滿足效能需求(資料切分 讀寫分離(只寫主庫只讀備庫))
容災(主備切換)
配置變更(動態資料來源(不需要資料庫的賬號資訊,哪天資料庫ip地址換了也沒關係 只需要依賴appname tddl會自動地讀取資料庫賬號使用者名稱密碼 當這些發生變更的時候會自動的通知到tddl,對使用者無感知))
切分有兩種水平切分和垂直切分
垂直切分不能無限切分, 因為列是有限的,而水平切分是可以無限擴充套件的, 只要行數是無限的。tddl能做的就是水平拆分,因為垂直拆分就是sql中的join操作
主備切換也是tddl的功能,當主庫掛掉的時候,會自動切換到備庫上。
水平拆分不一定按照id欄位來拆,也可以選擇其他欄位,比如某個欄位全是字串,可以先求出它的hash值,再對1024取模(假如拆了1024張表,此時也可以再對錶進行分庫,如0-155屬於庫1),總之要按照欄位本身的特點。
這就是所謂的拆分演算法。
分散式資料庫都會有兩個特點一個是partition,一個是replication.
那麼hbase使用了一種B樹的拆分方式,也就是說hbase各個存資料的節點(也就是分表的表)可以看作B樹裡面的一個節點,它在路由的時候就會根據樹的演算法來算出這條資料應該在哪一個節點裡面,因為它使用了樹,所以它繼承了樹的一些特點,所以在hbase中可以很方便來做一些範圍的查詢, 比如rowkey大於一個值或者小於一個值。但tddl預設使用的是一種hash演算法,就很難做一個範圍的查詢, 比如1-1000在hbase中可能也就跨了幾個分割槽佈局,但是如果在tddl中可能就跨了所有的分割槽,因為hash演算法是一種零散的演算法。但為什麼內部會預設使用hash演算法來分表呢,因為內部經常做的操作是根據買家id\賣家id\羊肉串id\定單id來查,這樣的話用hash演算法就比較快。
拆分欄位的選擇跟選索引差不多,選拆分欄位的時候基本會選查詢都會帶上的那種列,比如說買家id賣家id,還有就是區分度的概念,用這個欄位會路由到比較少的表中,而不是會路由1000張表。但如果像定單這種東西,它既有買家id又有賣家id,同時買家和賣家都會去關注,那選個欄位作為拆分欄位呢? 答案是兩個都選,資料複製一份,一份按買家id來路由分表,另一份按賣家id來進行路由分表,也就是資料會存兩份,相對應的我們就可以把買家和賣家理解為兩種索引,因為是兩種對映嘛。並且這種索引也可以做成聚簇,也可以做成非聚簇的,比如說在冗餘的時候按所有欄位進行冗餘一遍,這樣在查的時候就會查的比較快。
規則路由—擴容
怎樣擴容才能減少資料的移動,比如以前是模32,現在變成模40了,就要把以前的結果按40重新模一遍,怎樣選擇才能減少資料移動呢?
一般做法是一倍一倍的擴,比如以前是32,擴容後就變成64了。因為這種情況下只有一半的資料是需要移動的。
多維拆分實際是把資料按照兩維度冗餘了一份
組合索引就是先按一個列索引,再按另一個列索引
多個欄位同時作為拆分欄位,實際上資料只存了一份
兩個欄位就是二維,只提供一個欄位就會定位到好幾個張分表
三個欄位就是三維
tddl三層資料來源
最底層是atom層,對應的是一個資料庫,對應的就是一個ip使用者名稱密碼,一主一備就構成了第二層,就會變成一個group,同一個group會包含多個atom,但atom資料是一樣的,也就是說group會完成讀寫分離這樣一個操作,也可以完成主備切換,這兩層就是絕大數應用使用的模型,因為絕大多數應用是小應用不需要做拆分,只要做讀分離和主備切換這樣的功能。多個group之後會組成一個matrix層,當我們分庫之後,多個庫會組成一個matrix,matrix層負責來做切分這樣一個操作,就會有規則計算這樣一個功能,就會算出sql應該到哪個group去。這就是tddl三層資料來源的一個概念。
TDDL5分為三層資料來源結構
Matrix,主要負責資料的水平切分
Group,主要負責主備與讀寫分離
Atom,主要負責物理資料來源的管理
TDDL5中一個查詢操作在三層資料來源中的流程如下圖:
使用者通過JDBC,將SQL傳遞到TDDL5中,會按照以下流程進行執行:
SQL Parser會將SQL解析並生成關係查詢樹;
Query Optimizer對關係查詢樹進行優化,生成由KV查詢組成的執行計劃;
在這個過程中,還將根據切分規則,對條件id=2與id=3進行計算,得出資料所在的節點。如在此例中,根據id % 3,得出id=2的資料在Group1上,id=3的資料在Group0上;
Client會將執行計劃傳送給Matrix層,Matrix層會按照執行計劃中指定的Group,將執行計劃傳送給對應的Group,在Group層,由於非強一致的讀請求,會將讀操作隨機分配到資料節點Atom上;
最終資料在Matrix上進行合併之後,結果返回給Client。
matrix層:
Parser
Optimizer
語法解析
規則計算
查詢優化
Executor
聚合/Join/函式計算
Repo(儲存層)
Mysql
Group:主備切換,讀寫分離
Atom:動態資料來源
Oceanbase/Hbase/Skiplist/Search(支援多儲存)
TDDL的查詢優化器有一個最為核心的理念:offload,也是單機優化器裡面講到的一個基本的概念主是下推,下推的意思就是說盡量多的操作會讓mysql自己去執行,比如說一些條件的過濾,一些join能讓mysql去做的話就讓它先來做,比如說索引選擇,列的過濾,一些聚合函式的計算,一些排序,一些distinct去重這樣的操作,能讓mysql來做就讓它來做,為什麼呢?和單機資料庫一樣的道理,儘量減少中間資料,減少跨網路的延遲,offload的思想也是貫穿tddl基本的理念。也是tddl最佳實踐最基本的思想。
相關文章
- 架構演化思考總結(1)架構
- 架構演化思考總結(2)架構
- 資料中臺的思考與總結
- LAMP的思考:效能優化總結LAMP優化
- 自定義控制元件總結和思考控制元件
- 任務排程的思考和總結
- Java併發思考-導讀&總結篇Java
- Android螢幕適配總結和思考Android
- “粘連”footer佈局的思考和總結
- 關於Code Review的一些思考總結View
- 論一道面試題引起的思考(總結)面試題
- 有一點思考的2021年終總結!
- 關於JS的物件導向的思考和總結JS物件
- 【職場總結】由「 遊戲正式上線」產生的思考遊戲
- 總結與思考 :OOP課程PTA作業4 - 6OOP
- 對四種限流演算法的思考和總結演算法
- 幾次面試後,我的一些思考和總結面試
- 業務爬坑與總結–專案首頁重構的思考
- 做車載測試3年,我的思考與總結
- 關於介面測試自動化的總結與思考
- 2020年的一些思考和總結
- 關於Java併發程式設計的總結和思考Java程式設計
- MySQL高可用方案MHA的一些總結和思考MySql
- 業務爬坑與總結--專案首頁重構的思考
- 關於負載均衡的一切:總結與思考負載
- Python入門方法--簡單總結+學習方式思考Python
- 動作遊戲戰鬥系統總結歸納&思考(中)遊戲
- 關於DDD和COLA的一些總結和思考
- 對資料結構和演算法的總結和思考(三)--希爾排序資料結構演算法排序
- 連結的思考
- oracle事務transaction鎖lock一點兒小思考或總結Oracle
- Git常用命令總結及一些問題思考Git
- Android 開發軟體架構思考以及經驗總結Android架構
- 動作遊戲戰鬥系統框架總結歸納&思考(上)遊戲框架
- 對於api管理系統的一些總結和思考API
- 對資料結構和演算法的總結和思考(六)--計數排序資料結構演算法排序
- (資料結構程式碼,總結,自我思考)=> { return 個人學習筆記; } 【To be continued~】資料結構筆記
- 關於前端工程化(基建)的一些總結和思考前端