TDDL思考總結

單機數據庫
分佈式數據庫
TDDL原理與最佳實踐java

1. 數據庫的結構

1.1. KV存儲(id是K)

1.2. B+樹與紅黑樹

B+樹的特色是葉子節點是塊狀,一個葉子裏面有多個數據,相鄰數據是存在一塊兒的,123,456起等,
而磁盤也是按塊的,B+樹的數據是按塊存儲的正好和磁盤的塊的概念是相符的,
因此在數據庫裏面大多采用了B+樹或者相似的一種結構來存儲數據。
在java中實現treemap時選擇是紅黑樹而不是B+樹,B+面向的是磁盤的結構,
java的treemap面向的是內存,隨機讀寫數據快;
另一個緣由是,B+樹爲了減小分裂的次數會在每一個葉子結點中預留幾個空洞來存入將來的數據,
這個特色在磁盤中是能夠的,由於磁盤都是白菜價,浪費一點沒有關係,但內存就不同了;
紅黑樹本質是一顆二叉樹,每一個葉子只有一條數據,不須要預留任何的空間,
在內存中就不會形成空間的浪費,也就是這兩點,才選擇了紅黑樹來實現java中的treemap.
任何一種技術脫離了它的場景都是沒有意義的;mysql

有些數據庫不是按行存的,是按列存的,這樣可對列的特色進行壓縮,減小存儲空間,
進行max/min等運算也快,但這種特色不適合更新;
沒有一種數據庫讀的快寫的也快,讀寫性能的差距也是因爲背後所使用的存儲不一樣致使的,
如hbase使用的是lsm-tree這種存儲,它的特色是寫的很快,順序寫,但讀的稍微有點慢,
因此hbase常常用來存日誌,產生的量,對讀的性能要求不高。
要判斷讀的多仍是寫的多,若是讀的多,還要判斷讀的特色,是隨機讀仍是範圍的讀,寫的話,
是隻寫仍是會有刪除和更新;B樹是面向磁盤的,紅黑樹是面向內存的;web

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,sql

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是有主庫和備庫的區別的,主備庫數據是徹底同樣的。內部的方案是讀寫都在主庫,備庫所有采用異步的方式備份。這是犧牲了備庫的讀性能來換取的,能夠講到同步的數據又不要同步的複製,來保證寫的性能的提高。app

若是主庫掛掉的話,怎麼從剩下的備庫中選舉主庫呢?大可能是用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最佳實踐最基本的思想。

相關文章
相關標籤/搜索