自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文帶你了解TiDB

數(shù)據(jù)庫 MySQL
通過本篇文章的介紹,希望讀者對TiDB有一個大致的了解,可以擴充知識點??偨Y(jié)一句話,MySQL可以無縫切換到TiDB,但僅限于查詢使用,事務支持上兩者其實還有著細微的差別,并不建議從業(yè)務上直接完全替換。

一、簡介

TiDB并不陌生,很多團隊都在使用,我們?yōu)槭裁匆怯盟?,它有哪些特點呢?

TiDB 是一款開源分布式關(guān)系型數(shù)據(jù)庫,可以同時支持在線事務處理與在線分析處理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布式數(shù)據(jù)庫產(chǎn)品,具備水平擴容或者縮容、金融級高可用、實時 HTAP、云原生的分布式數(shù)據(jù)庫、兼容 MySQL 5.7 協(xié)議和 MySQL 生態(tài)等重要特性,支持在本地和云上部署。

從中可以看到TiDB有如下特性:

  • 同時支持OLTP和OLAP
  • 分布式數(shù)據(jù)庫,金融級別高可用
  • 完全兼容MySQL,無縫切換

二、TiDB結(jié)構(gòu)介紹

整體架構(gòu)圖(以下用圖來自TiDB官方文檔&借鑒知乎)

圖片

2.1 TiDB Server

SQL 層,對外暴露 MySQL 協(xié)議的連接 endpoint,負責接受客戶端的連接,執(zhí)行鑒權(quán)、 SQL 解析和優(yōu)化,最終生成分布式執(zhí)行計劃。TiDB 層本身是無狀態(tài)的,實踐中可以啟動多個 TiDB 實例,通過負載均衡組件(如 LVS、HAProxy 或 F5)對外提供統(tǒng)一的接入地址,客戶端的連接可以均勻地分攤在多個 TiDB 實例上以達到負載均衡的效果。TiDB Server 本身并不存儲數(shù)據(jù),只是解析 SQL,將實際的數(shù)據(jù)讀取請求轉(zhuǎn)發(fā)給底層的存儲節(jié)點 TiKV(或 TiFlash)。

2.2 PD (Placement Driver) Server

整個 TiDB 集群的元信息管理模塊,負責存儲每個 TiKV 節(jié)點實時的數(shù)據(jù)分布情況和集群的整體拓撲結(jié)構(gòu),提供 TiDB Dashboard 管控界面,并為分布式事務分配事務 ID。PD 不僅存儲元信息,同時還會根據(jù) TiKV 節(jié)點實時上報的數(shù)據(jù)分布狀態(tài),下發(fā)數(shù)據(jù)調(diào)度命令給具體的 TiKV 節(jié)點,可以說是整個集群的“大腦”。此外,PD是無狀態(tài)的,通過raft一致性協(xié)議完成數(shù)據(jù)同步, 本身也是由至少 3 個節(jié)點構(gòu)成,擁有高可用的能力,建議部署奇數(shù)個 PD 節(jié)點。

2.3 存儲節(jié)點(TiKV&TiFLASH)

  • TiKV Server

TiDB的存儲方式皆為KV(key-value)存儲,一切皆KV。

負責存儲數(shù)據(jù),從外部看 TiKV 是一個分布式的提供事務的 Key-Value 存儲引擎。存儲數(shù)據(jù)的基本單位是 Region,每個 Region 負責存儲一個 Key Range(從 StartKey 到 EndKey 的左閉右開區(qū)間)的數(shù)據(jù),每個 TiKV 節(jié)點會負責多個 Region。TiKV 的 API 在 KV 鍵值對層面提供對分布式事務的原生支持,默認提供了 SI (Snapshot Isolation) 的隔離級別,這也是 TiDB 在 SQL 層面支持分布式事務的核心。TiDB 的 SQL 層做完 SQL 解析后,會將 SQL 的執(zhí)行計劃轉(zhuǎn)換為對 TiKV API 的實際調(diào)用。所以,數(shù)據(jù)都存儲在 TiKV 中。另外,TiKV 中的數(shù)據(jù)都會自動維護多副本(默認為三副本),天然支持高可用和自動故障轉(zhuǎn)移,副本質(zhì)檢也是通過raft協(xié)議維持數(shù)據(jù)一致。

  • TiFlash

TiFlash 是一類特殊的存儲節(jié)點。和普通 TiKV 節(jié)點不一樣的是,在 TiFlash 內(nèi)部數(shù)據(jù)是以列式的形式進行存儲,主要的功能是為分析型即OLAP場景加速。一般TiDB作數(shù)據(jù)庫使用OLTP功能,無需部署該節(jié)點。

圖片

  • TiDB與MySQL差異

截止到TiDB4.0版本,與MySQL有如下差異(圖片引自知乎)

圖片

三、TiDB存儲介紹

作為保存數(shù)據(jù)的系統(tǒng),首先要決定的是數(shù)據(jù)的存儲模型,也就是數(shù)據(jù)以什么樣的形式保存下來。TiKV 的選擇是 Key-Value 模型,并且提供有序遍歷方法。

TiKV 數(shù)據(jù)存儲的兩個關(guān)鍵點:

這是一個巨大的 Map,也就是存儲的是 Key-Value Pairs(鍵值對)

這個 Map 中的 Key-Value pair 按照 Key 的二進制順序有序,也就是可以 Seek 到某一個 Key 的位置,然后不斷地調(diào)用 Next 方法以遞增的順序獲取比這個 Key 大的 Key-Value。

3.1 持久化使用RocksDB

任何持久化的存儲引擎,數(shù)據(jù)終歸要保存在磁盤上,TiKV 也不例外。但是 TiKV 沒有選擇直接向磁盤上寫數(shù)據(jù),而是把數(shù)據(jù)保存在 RocksDB 中,具體的數(shù)據(jù)落地由 RocksDB 負責。這個選擇的原因是開發(fā)一個單機存儲引擎工作量很大,特別是要做一個高性能的單機引擎,需要做各種細致的優(yōu)化,而 RocksDB 是由 Facebook 開源的一個非常優(yōu)秀的單機 KV 存儲引擎,可以滿足 TiKV 對單機引擎的各種要求。這里可以簡單的認為 RocksDB 是一個單機的持久化 Key-Value Map。

  • Region

為了實現(xiàn)存儲的水平擴展,數(shù)據(jù)將被分散在多臺機器上。對于一個 KV 系統(tǒng),將數(shù)據(jù)分散在多臺機器上有兩種比較典型的方案:

Hash:按照 Key 做 Hash,根據(jù) Hash 值選擇對應的存儲節(jié)點。

Range:按照 Key 分 Range,某一段連續(xù)的 Key 都保存在一個存儲節(jié)點上。

TiKV 選擇了第二種方式,將整個 Key-Value 空間分成很多段,每一段是一系列連續(xù)的 Key,將每一段叫做一個 Region,并且會盡量保持每個 Region 中保存的數(shù)據(jù)不超過一定的大小,目前在 TiKV 中默認是 96MB。每一個 Region 都可以用 [StartKey,EndKey) 這樣一個左閉右開區(qū)間來描述。

圖片

將數(shù)據(jù)劃分成 Region 后,TiKV 將會做兩件重要的事情:

  • 以 Region 為單位,將數(shù)據(jù)分散在集群中所有的節(jié)點上,并且盡量保證每個節(jié)點上服務的 Region 數(shù)量差不多。
  • 以 Region 為單位做 Raft 的復制和成員管理。

以 Region 為單位做數(shù)據(jù)的分散和復制,TiKV 就成為了一個分布式的具備一定容災能力的 KeyValue 系統(tǒng),不用再擔心數(shù)據(jù)存不下,或者是磁盤故障丟失數(shù)據(jù)的問題。

圖片

3.2 TiDB索引介紹

  • 表數(shù)據(jù)與key-value的映射

TiDB的存儲方式key-value的鍵值對,為了方便查找在設(shè)計上做了如下優(yōu)化:

為同一張表設(shè)計一個表id,用TableID表示,整數(shù)且全局唯一

為每一張表的每一行設(shè)計一個行id,用RowId表示,整數(shù)且同一張表內(nèi)唯一。這里還有個小優(yōu)化,如果這張表有主鍵,則TiDB把主鍵作為RowId,否則自行分配一個。

映射結(jié)構(gòu)示例:

Key:   tablePrefix{TableID}_recordPrefixSep{RowID} 

Value: [col1, col2, col3, col4]

其中,tablePrefix、recordPrefixSep都是固定的常量,為了在key空間內(nèi)區(qū)分其他數(shù)據(jù)。

  • 索引與key-value的映射

TiDB索引支持主鍵索引(MySQL主鍵索引)和二級索引(MySQL平臺非聚簇索引,分唯一索引和非唯一索引),它和表與key-value的映射方式相似,也會分配一個全局唯一整數(shù)索引id,使用IndexId表示。

對于主鍵索引和唯一索引,由于列的數(shù)據(jù)是唯一的,因此對應的key-value的結(jié)構(gòu)如下:

Key:tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue Value:RowID 

其中indexedColumnsValue表示查詢列的值,最終是列值對應一個RowId

對于非唯一索引,由于列的數(shù)據(jù)不唯一,一個鍵值可能對應多行,需要根據(jù)鍵值范圍查詢對應的 RowID。因此,按照如下規(guī)則編碼成 (Key, Value) 鍵值對:

Key:tablePrefix{TableID}_indexPrefixSep{IndexID}_indexedColumnsValue_{RowID} Value:null 

這里需要注意的是,value是null,并不是RowID,而RowID是拼接在key的結(jié)尾的。這里為什么不把value設(shè)計為RowID呢?猜測是因為key是不能夠重復的,要全局唯一,而且要均勻分布在TiKV的各個節(jié)點,只能把RowID拼接在key的結(jié)尾處,而且查詢的時候是根據(jù)鍵值RowID前面的范圍來查詢。

  • 索引示例

上述所有編碼規(guī)則中的 tablePrefix、recordPrefixSep? 和 indexPrefixSep 都是字符串常量,用于在 Key 空間內(nèi)區(qū)分其他數(shù)據(jù),定義如下:

tablePrefix     = []byte{'t'}recordPrefixSep = []byte{'r'}indexPrefixSep  = []byte{'i'}

另外請注意,上述方案中,無論是表數(shù)據(jù)還是索引數(shù)據(jù)的 Key 編碼方案,一個表內(nèi)所有的行都有相同的 Key 前綴,一個索引的所有數(shù)據(jù)也都有相同的前綴。這樣具有相同的前綴的數(shù)據(jù),在 TiKV 的 Key 空間內(nèi),是排列在一起的。因此只要小心地設(shè)計后綴部分的編碼方案,保證編碼前和編碼后的比較關(guān)系不變,就可以將表數(shù)據(jù)或者索引數(shù)據(jù)有序地保存在 TiKV 中。采用這種編碼后,一個表的所有行數(shù)據(jù)會按照 RowID? 順序地排列在 TiKV 的 Key 空間中,某一個索引的數(shù)據(jù)也會按照索引數(shù)據(jù)的具體的值(編碼方案中的 indexedColumnsValue)順序地排列在 Key 空間內(nèi)。

通過一個簡單的例子,來理解 TiDB 的 Key-Value 映射關(guān)系。假設(shè) TiDB 中有如下這個表:

CREATE TABLE User (    ID int,    Name varchar(20),    Role varchar(20),    Age int,    PRIMARY KEY (ID),    KEY idxAge (Age));

假設(shè)該表中有4行數(shù)據(jù):

1, "TiDB", "SQL Layer", 102, "TiKV", "KV Engine", 203, "PD", "Manager", 30,4, "TiFLASH", "STORAGE", 30

首先每行數(shù)據(jù)都會映射為一個 (Key, Value) 鍵值對,同時該表有一個 int? 類型的主鍵,所以 RowID? 的值即為該主鍵的值。假設(shè)該表的 TableID 為 10,則其存儲在 TiKV 上的表數(shù)據(jù)為:

t10_r1 --> ["TiDB", "SQL Layer", 10]t10_r2 --> ["TiKV", "KV Engine", 20]t10_r3 --> ["PD", "Manager", 30]t10_r4 --> ["TiFLASH", "STORAGE", 30]

除了主鍵外,該表還有一個非唯一的普通二級索引 idxAge?,假設(shè)這個索引的 IndexID 為 1,則其存儲在 TiKV 上的索引數(shù)據(jù)為:

t10_i1_10_1 --> nullt10_i1_20_2 --> nullt10_i1_30_3 --> nullt10_i1_30_4 --> null
如按照age=30查詢,則是根據(jù)t10_i1_30去做前綴匹配,可以匹配到t10_i1_30_3與t10_i1_30_4,取最后3和4便是RowID

四、TiDB執(zhí)行計劃查看

4.1 概覽

由于TiDB除了協(xié)議上與MySQL兼容之外,其余的林林總總都有著自己獨特的實現(xiàn),尤其是最核心的存儲實現(xiàn)方式更是天差地別,因此查看執(zhí)行計劃也是完全不一樣的,以一個簡單SQL為例來解析說明TiDB執(zhí)行計劃的含義。

SQL:

圖片

執(zhí)行計劃(SQL1):

圖片

執(zhí)行計劃(SQL3):

圖片

首先,create_time列上加了普通二級索引。先介紹各個列的含義:

  • id 為算子名,或執(zhí)行 SQL 語句需要執(zhí)行的子任務。
  • estRows 為顯示 TiDB 預計會處理的行數(shù)。該預估數(shù)可能基于字典信息(例如訪問方法基于主鍵或唯一鍵),或基于 CMSketch 或直方圖等統(tǒng)計信息估算而來(說了這么多,其實就是和MySQL執(zhí)行計劃的rows類似)。
  • task 顯示算子在執(zhí)行語句時的所在位置。
  • access object 顯示被訪問的表、分區(qū)和索引。顯示的索引為部分索引。以上示例中 TiDB 使用了 a 列的索引。尤其是在有組合索引的情況下,該字段顯示的信息很有參考意義。
  • operator info 顯示訪問表、分區(qū)和索引的其他信息。

4.2 詳細介紹

4.2.1 算子

算子是為返回查詢結(jié)果而執(zhí)行的特定步驟。真正執(zhí)行掃表(讀盤或者讀 TiKV Block Cache)操作的算子有如下幾類:

  • TableFullScan:全表掃描。
  • TableRangeScan:帶有范圍的表數(shù)據(jù)掃描。
  • TableRowIDScan:根據(jù)上層傳遞下來的 RowID 掃描表數(shù)據(jù)。時常在索引讀操作后檢索符合條件的行。
  • IndexFullScan:另一種“全表掃描”,掃的是索引數(shù)據(jù),不是表數(shù)據(jù)。
  • IndexRangeScan:帶有范圍的索引數(shù)據(jù)掃描操作。

TiDB 會匯聚 TiKV/TiFlash 上掃描的數(shù)據(jù)或者計算結(jié)果,這種“數(shù)據(jù)匯聚”算子目前有如下幾類:

  • TableReader:將 TiKV 上底層掃表算子 TableFullScan 或 TableRangeScan 得到的數(shù)據(jù)進行匯總。
  • IndexReader:將 TiKV 上底層掃表算子 IndexFullScan 或 IndexRangeScan 得到的數(shù)據(jù)進行匯總。
  • IndexLookUp:先匯總 Build 端 TiKV 掃描上來的 RowID,再去 Probe 端上根據(jù)這些RowID? 精確地讀取 TiKV 上的數(shù)據(jù)。Build 端是IndexFullScan? 或IndexRangeScan? 類型的算子,Probe 端是TableRowIDScan 類型的算子。
  • IndexMerge:和IndexLookupReader? 類似,可以看做是它的擴展,可以同時讀取多個索引的數(shù)據(jù),有多個 Build 端,一個 Probe 端。執(zhí)行過程也很類似,先匯總所有 Build 端 TiKV 掃描上來的 RowID,再去 Probe 端上根據(jù)這些 RowID 精確地讀取 TiKV 上的數(shù)據(jù)。Build 端是IndexFullScan? 或IndexRangeScan? 類型的算子,Probe 端是TableRowIDScan 類型的算子。

  • 算子的執(zhí)行順序

算子的結(jié)構(gòu)是樹狀的,但在查詢執(zhí)行過程中,并不嚴格要求子節(jié)點任務在父節(jié)點之前完成。TiDB 支持同一查詢內(nèi)的并行處理,即子節(jié)點“流入”父節(jié)點。父節(jié)點、子節(jié)點和同級節(jié)點可能并行執(zhí)行查詢的一部分。

在SQL1示例中,│ └─IndexFullScan_15 算子為 idx_create_time(create_time) 索引中掃描并降序排序取出RowID,├─Limit_17(Build)算子拿出前10個RowID,└─TableRowIDScan_16(Probe) 算子隨后拿上面返回的RowID從表中檢索出數(shù)據(jù)。

Build 總是先于 Probe 執(zhí)行,并且 Build 總是出現(xiàn)在 Probe 前面。即如果一個算子有多個子節(jié)點,子節(jié)點 ID 后面有 Build 關(guān)鍵字的算子總是先于有 Probe 關(guān)鍵字的算子執(zhí)行。TiDB 在展現(xiàn)執(zhí)行計劃的時候,Build 端總是第一個出現(xiàn),接著才是 Probe 端。

  • 范圍查詢

在 WHERE/HAVING/ON? 條件中,TiDB 優(yōu)化器會分析主鍵或索引鍵的查詢返回。如數(shù)字、日期類型的比較符,如大于、小于、等于以及大于等于、小于等于,字符類型的 LIKE 符號等。

若要使用索引,條件必須是 "Sargable" (Search ARGument ABLE) 的。例如條件 YEAR(date_column) < 1992? 不能使用索引,但 date_column < '1992-01-01 就可以使用索引。

推薦使用同一類型的數(shù)據(jù)以及同一類型的字符串和排序規(guī)則進行比較,以避免引入額外的 cast 操作而導致不能利用索引。

可以在范圍查詢條件中使用 AND?(求交集)和 OR?(求并集)進行組合。對于多維組合索引,可以對多個列使用條件。例如對組合索引 (a, b, c):

  • 當 a? 為等值查詢時,可以繼續(xù)求 b 的查詢范圍。
  • 當 b? 也為等值查詢時,可以繼續(xù)求 c 的查詢范圍。
  • 反之,如果 a? 為非等值查詢,則只能求 a 的范圍。

4.2.2 task簡介

目前 TiDB 的計算任務分為兩種不同的 task:cop task 和 root task。Cop task 是指使用 TiKV 中的 Coprocessor 執(zhí)行的計算任務,root task 是指在 TiDB 中執(zhí)行的計算任務。

SQL 優(yōu)化的目標之一是將計算盡可能地下推到 TiKV 中執(zhí)行。TiKV 中的 Coprocessor 能支持大部分 SQL 內(nèi)建函數(shù)(包括聚合函數(shù)和標量函數(shù))、SQL LIMIT 操作、索引掃描和表掃描。但是,所有的 Join 操作都只能作為 root task 在 TiDB 上執(zhí)行。

4.2.3 operator info簡介

EXPLAIN? 返回結(jié)果中 operator info? 列可顯示諸如條件下推等信息。本文以上示例中,operator info 結(jié)果各字段解釋如下:

  • range: [1,1]? 表示查詢的 WHERE? 字句 (a = 1?) 被下推到了 TiKV,對應的 task 為 cop[tikv]。
  • keep order:false? 表示該查詢的語義不需要 TiKV 按順序返回結(jié)果。如果查詢指定了排序(例如 SELECT * FROM t WHERE a = 1 ORDER BY id?),該字段的返回結(jié)果為 keep order:true。
  • stats:pseudo? 表示 estRows? 顯示的預估數(shù)可能不準確。TiDB 定期在后臺更新統(tǒng)計信息。也可以通過執(zhí)行 ANALYZE TABLE t 來手動更新統(tǒng)計信息。

EXPLAIN? 執(zhí)行后,不同算子返回不同的信息。你可以使用 Optimizer Hints 來控制優(yōu)化器的行為,以此控制物理算子的選擇。例如 /*+ HASH_JOIN(t1, t2) */ 表示優(yōu)化器將使用 Hash Join 算法。

4.2.4 索引總結(jié)

SQL1中的執(zhí)行計劃:

  • 算子│ └─IndexFullScan_15在TiKV操作掃描索引idx_create_time(create_time)并降序排序(operator info表明)
  • 算子├─Limit_17(Build)獲取前10條(根據(jù)operator info的offset:0, count:10得知)數(shù)據(jù)的RowID
  • 算子└─TableRowIDScan_16(Probe)在TiKV根據(jù)上面拿到的RowID去表中查詢數(shù)據(jù)
  • 算子IndexLookUp_18在TiDB匯總結(jié)果├─Limit_17(Build)上的RowID,之后使用RowID從算子└─TableRowIDScan_16(Probe)精確查找數(shù)據(jù)

其實IndexLookUp_18這個算子作用就是匯聚作用,匯總從TableRowIDScan或TableRangeScan和 IndexFullScan 或 IndexRangeScan的數(shù)據(jù)。

SQL3中的執(zhí)行計劃:

  • 算子└─IndexFullScan_19在TiKV從索引create_time索引降序排序讀取10條RowID
  • 算子└─IndexReader_21在TiDB匯總數(shù)據(jù)直接返回,無需再去讀表,因為SELECT的字段就是索引上的
  • 算子Limit_10為根算子,把結(jié)果返回客戶端

寫在最后,以上是執(zhí)行計劃,是相對粗略的結(jié)果,如果要獲取詳細的結(jié)果(帶有性能、執(zhí)行時間等),需要查看性能分析結(jié)果,方法為SQL語句前加上EXPLAIN ANALYZE,以下為SQL1的性能分析示例:

圖片

分析結(jié)果:

圖片

圖片

由于execution_info信息比較長,分開兩次截取。性能分析計劃相比執(zhí)行計劃多出了actRows和execution_info兩個比較重要需要常去關(guān)注的信息。actRows為實際掃描行數(shù),execution_info表明了各種執(zhí)行的細節(jié)。

五、總結(jié)

TiDB目前的使用還是很廣泛的,在很多家知名企業(yè)都有著非常成功的實踐。本文介紹了TiDB的架構(gòu)、使用的場景、與MySQL的兼容性、數(shù)據(jù)以及索引的存儲原理、執(zhí)行計劃的查看,基本涵蓋了TiDB使用的所有基礎(chǔ)性東西。當然TiDB的復雜度遠遠高于文中所介紹的,其內(nèi)部的設(shè)計以及各種實現(xiàn)是相當復雜的,非常值得細究。

通過本篇文章的介紹,希望讀者對TiDB有一個大致的了解,可以擴充知識點??偨Y(jié)一句話,MySQL可以無縫切換到TiDB,但僅限于查詢使用,事務支持上兩者其實還有著細微的差別,并不建議從業(yè)務上直接完全替換。

參考文獻:

TiDB 簡介 | PingCAP Docs https://docs.pingcap.com/zh/tidb/stable/overview

TiDB介紹 - 知乎https://zhuanlan.zhihu.com/p/494715695

責任編輯:武曉燕 來源: 得物技術(shù)
相關(guān)推薦

2023-11-06 08:16:19

APM系統(tǒng)運維

2023-11-20 08:18:49

Netty服務器

2023-10-27 08:15:45

2022-02-24 07:34:10

SSL協(xié)議加密

2023-11-08 08:15:48

服務監(jiān)控Zipkin

2020-10-08 14:32:57

大數(shù)據(jù)工具技術(shù)

2022-04-28 09:22:46

Vue灰度發(fā)布代碼

2025-01-15 09:06:57

servlet服務器Java

2022-09-29 13:09:38

DataClassPython代碼

2020-02-02 15:14:24

HTTP黑科技前端

2024-05-07 08:49:36

Hadoop數(shù)據(jù)存儲-分布式存儲

2019-08-06 09:00:00

JavaScript函數(shù)式編程前端

2023-05-17 11:33:45

梯度下降機器學習

2024-05-27 00:00:00

.NET游戲引擎C#

2024-02-04 09:44:41

量子計算量子量子物理

2022-03-14 08:01:06

LRU算法線程池

2023-03-31 08:16:53

Flutter優(yōu)化內(nèi)存管理

2018-10-22 08:14:04

2023-12-06 16:28:56

2022-02-18 10:13:07

SolrElasticSea開源
點贊
收藏

51CTO技術(shù)棧公眾號