一形葬、TiKV存儲(chǔ)
簡(jiǎn)述
- 通過(guò)單機(jī)的 RocksDB,TiKV 可以將數(shù)據(jù)快速地存儲(chǔ)在磁盤(pán)上奇昙;通過(guò) Raft纤控,將數(shù)據(jù)復(fù)制到多臺(tái)機(jī)器上,以防單機(jī)失效活烙。數(shù)據(jù)的寫(xiě)入是通過(guò) Raft 這一層的接口寫(xiě)入徐裸,而不是直接寫(xiě) RocksDB。通過(guò)實(shí)現(xiàn) Raft瓣颅,TiKV 變成了一個(gè)分布式的 Key-Value 存儲(chǔ)倦逐,少數(shù)幾臺(tái)機(jī)器宕機(jī)也能通過(guò)原生的 Raft 協(xié)議自動(dòng)把副本補(bǔ)全,繼續(xù)讓業(yè)務(wù)無(wú)感知的對(duì)外服務(wù)宫补。
Region
將整個(gè) Key-Value 空間分成很多段檬姥,每一段是一系列連續(xù)的 Key,將每一段叫做一個(gè) Region粉怕,并且會(huì)盡量保持每個(gè) Region 中保存的數(shù)據(jù)不超過(guò)一定的大小健民,目前在 TiKV 中默認(rèn)是 96MB。每一個(gè) Region 都可以用 [StartKey贫贝,EndKey) 這樣一個(gè)左閉右開(kāi)區(qū)間來(lái)描述秉犹。
- 以 Region 為單位,將數(shù)據(jù)分散在集群中所有的節(jié)點(diǎn)上稚晚,并且盡量保證每個(gè)節(jié)點(diǎn)上服務(wù)的 Region 數(shù)量差不多
- 以 Region 為單位做 Raft(數(shù)據(jù)) 的復(fù)制和成員管理:一個(gè) Region 的多個(gè) Replica 會(huì)保存在不同的節(jié)點(diǎn)上崇堵,構(gòu)成一個(gè) Raft Group。其中一個(gè) Replica 會(huì)作為這個(gè) Group 的 Leader客燕,其他的 Replica 作為 Follower鸳劳。所有的讀和寫(xiě)都是通過(guò) Leader 進(jìn)行,(寫(xiě))再由 Leader 復(fù)制給 Follower也搓。
MVCC(多版本并發(fā)控制)
TiKV 的 MVCC 實(shí)現(xiàn)是通過(guò)在 Key 后面添加版本號(hào)來(lái)實(shí)現(xiàn)赏廓『桑可以直接通過(guò) RocksDB 的 API: SeekPrefix(Key-Version),定位到第一個(gè)大于等于這個(gè) Key_Version 的位置幔摸。
分布式 ACID 事務(wù)
TiKV 的事務(wù)采用的是 Google 在 BigTable 中使用的事務(wù)模型:Percolator
能保證要么全部成功摸柄,要么全部失敗,不會(huì)出現(xiàn)的中間狀態(tài)和臟數(shù)據(jù)既忆。
二驱负、TiDB如何使用TiKV
問(wèn)題:如何存儲(chǔ)數(shù)據(jù)?哪些作為key尿贫,哪些作為value电媳?
對(duì)于一個(gè) Table 來(lái)說(shuō),需要存儲(chǔ)的數(shù)據(jù)包括三部分:
- 表中每一行的數(shù)據(jù)庆亡,以下簡(jiǎn)稱表數(shù)據(jù)
- 表中所有索引的數(shù)據(jù)匾乓,以下簡(jiǎn)稱索引數(shù)據(jù)
- 表的元信息
對(duì)于表中每一行的數(shù)據(jù),既可以選擇行存也可以選擇列存又谋,兩者各有優(yōu)缺點(diǎn)拼缝,適用不同場(chǎng)景。
TiDB 的首要目標(biāo)是 OLTP 業(yè)務(wù)彰亥,要滿足這類(lèi)業(yè)務(wù)的需求咧七,數(shù)據(jù)庫(kù)需要支持快速的針對(duì)單行或者某些行的增、刪任斋、改继阻、查等操作,所以 TiKV 的行存是比較合適該場(chǎng)景的废酷。
從 TiDB 3.1 開(kāi)始(包括 TiDB 4.0)瘟檩,為了能夠滿足用戶復(fù)雜的實(shí)時(shí)分析場(chǎng)景(OLAP?)澈蟆,TiDB 提供了一個(gè)叫做** TiFlash 的列存引擎**墨辛,它提供了列式的存儲(chǔ)模式和快速的分析能力。列存的映射關(guān)系比較簡(jiǎn)單趴俘,這里暫且不表睹簇。
2.1 索引
索引數(shù)據(jù),TiDB 同時(shí)支持主鍵和二級(jí)索引(包括唯一索引和非唯一索引)寥闪。在 OLTP 場(chǎng)景下太惠,好的索引能夠極大的提升 SQL 查詢的性能,降低集群的整體負(fù)載疲憋。
- 對(duì)于 Insert 語(yǔ)句凿渊,既需要將表數(shù)據(jù)寫(xiě)入 KV 存儲(chǔ),也需要構(gòu)造和存儲(chǔ)對(duì)應(yīng)的索引數(shù)據(jù)。
- 對(duì)于 Update 語(yǔ)句嗽元,需要在更新表數(shù)據(jù)的同時(shí),也更新對(duì)應(yīng)的索引數(shù)據(jù)(如果有必要的話)喂击。
- 對(duì)于 Delete 語(yǔ)句剂癌,需要在刪除表數(shù)據(jù)的同時(shí),也刪除對(duì)應(yīng)的索引數(shù)據(jù)(如果有必要的話)翰绊。
- 對(duì)于 Select 語(yǔ)句佩谷,情況會(huì)復(fù)雜一些。用戶希望數(shù)據(jù)庫(kù)提供快速讀取一行數(shù)據(jù)的能力监嗜,所以每行表數(shù)據(jù)最好有一個(gè)唯一 ID (顯示或隱式的 ID)方便快速讀取谐檀。其次用戶也可能會(huì)連續(xù)地讀取多行數(shù)據(jù),比如 select * from user裁奇。最后還有通過(guò)索引讀取數(shù)據(jù)的需求桐猬,對(duì)索引的使用可能是基于唯一索引或者主鍵的等值查詢(業(yè)界常說(shuō)的“點(diǎn)查”)或者是范圍查詢。
當(dāng)然刽肠,在有了 TiFlash 以后溃肪,全表掃更適合在 TiFlash 上進(jìn)行,因?yàn)榱惺酱鎯?chǔ)的優(yōu)勢(shì)音五,這種場(chǎng)景中它能提供更快的讀取性能惫撰。
2.1.1 行數(shù)據(jù)的key設(shè)計(jì)
TiDB會(huì)為全集群生成唯一表ID,為表內(nèi)數(shù)據(jù)生成唯一的行ID(有整型主鍵則是主鍵作為行ID)躺涝,則數(shù)據(jù)如下:
Key: tablePrefix{TableID}_recordPrefixSep{RowID}
Value: [col1, col2, col3, col4]
2.1.2 索引數(shù)據(jù)的 Key-Value 映射關(guān)系
TiDB 為表中每個(gè)索引分配了一個(gè)索引 ID厨钻,其中:
對(duì)于需要滿足唯一性約束的主鍵或者唯一索引,按照如下規(guī)則編碼成 (Key, Value) 鍵值對(duì):
Key: tablePrefix{tableID}_indexPrefixSep{indexID}_indexedColumnsValue
Value: RowID
對(duì)于不需要滿足唯一性約束的普通二級(jí)索引坚嗜,按照如下規(guī)則編碼成 (Key, Value) 鍵值對(duì):
Key: tablePrefix{TableID}_indexPrefixSep{IndexID}_indexedColumnsValue_{RowID}
Value: null
2.2 元數(shù)據(jù)
另外存儲(chǔ)于某個(gè)key中夯膀,將元信息編碼后存儲(chǔ)
2.3 SQL 層簡(jiǎn)介
TiDB 的 SQL層,即tidb-server惶傻,負(fù)責(zé)將 SQL 翻譯成 KV 操作棍郎,轉(zhuǎn)發(fā)給共享的分布式 KV 存儲(chǔ)層 TiKV,并組裝返回結(jié)果银室,最終返回查詢結(jié)果涂佃。
舉例:select count(*) from user where name='test'
,像這樣一句語(yǔ)句蜈敢,如果將數(shù)據(jù)返回到tiDB進(jìn)行過(guò)濾辜荠、計(jì)數(shù)會(huì)浪費(fèi)網(wǎng)絡(luò)IO和無(wú)意義計(jì)算∽ハ粒可以將這類(lèi)操作下放到tiKV伯病,粗略描述如下圖:
實(shí)際流程較復(fù)雜:
用戶的 SQL 請(qǐng)求會(huì)直接或者通過(guò)Load Balancer發(fā)送到 tidb-server,tidb-server 會(huì)解析MySQL Protocol Packet,獲取請(qǐng)求內(nèi)容午笛,然后做語(yǔ)法解析惭蟋、查詢計(jì)劃制定和優(yōu)化、執(zhí)行查詢計(jì)劃獲取和處理數(shù)據(jù)药磺。數(shù)據(jù)全部存儲(chǔ)在 TiKV 集群中告组,所以在這個(gè)過(guò)程中 tidb-server 需要和 TiKV 交互,獲取數(shù)據(jù)癌佩。最后 tidb-server 需要將查詢結(jié)果返回給用戶木缝。
三、關(guān)于調(diào)度
在這兩個(gè)組件的后面围辙,還有一個(gè)叫做 PD(Placement Driver)的組件我碟,雖然不直接和業(yè)務(wù)接觸,但是這個(gè)組件是整個(gè)集群的核心姚建,負(fù)責(zé)全局元信息的存儲(chǔ)以及 TiKV 集群負(fù)載均衡調(diào)度矫俺。
3.1 為什么要進(jìn)行調(diào)度
整個(gè)系統(tǒng)是在動(dòng)態(tài)變化,Region 分裂掸冤、節(jié)點(diǎn)加入恳守、節(jié)點(diǎn)失效、訪問(wèn)熱點(diǎn)變化等情況會(huì)不斷發(fā)生贩虾,整個(gè)調(diào)度系統(tǒng)也需要在動(dòng)態(tài)中不斷向最優(yōu)狀態(tài)前進(jìn)催烘,因此我們需要一個(gè)中心節(jié)點(diǎn),來(lái)對(duì)系統(tǒng)的整體狀況進(jìn)行把控和調(diào)整缎罢,所以有了 PD 這個(gè)模塊伊群。
3.2 調(diào)度的需求整理
作為一個(gè)分布式高可用存儲(chǔ)系統(tǒng),必須滿足:副本數(shù)量不能多也不能少策精、副本需要分布在不同的機(jī)器上舰始、新加節(jié)點(diǎn)后可以將其他節(jié)點(diǎn)上的副本遷移過(guò)來(lái)、節(jié)點(diǎn)下線后需要將數(shù)據(jù)遷移走咽袜。
作為一個(gè)良好的分布式系統(tǒng)丸卷,需要優(yōu)化:維持整個(gè)集群的 Leader 分布均勻、維持每個(gè)節(jié)點(diǎn)的儲(chǔ)存容量均勻询刹、維持訪問(wèn)熱點(diǎn)分布均勻控制 Balance 的速度谜嫉,避免影響在線服務(wù);管理節(jié)點(diǎn)狀態(tài)凹联,包括手動(dòng)上線/下線節(jié)點(diǎn)沐兰,以及自動(dòng)下線失效節(jié)點(diǎn)。
上述調(diào)度需求看似復(fù)雜蔽挠,但是整理下來(lái)最終落地的無(wú)非是下面三件事:
- 增加一個(gè) Replica
- 刪除一個(gè) Replica
- 將 Leader 角色在一個(gè) Raft Group 的不同 Replica 之間 transfer住闯。
剛好 Raft 協(xié)議能夠滿足這三種需求,通過(guò) AddReplica、RemoveReplica比原、TransferLeader 這三個(gè)命令插佛,可以支撐上述三種基本操作。
3.3 信息收集
- 每個(gè) TiKV 節(jié)點(diǎn)(Store)會(huì)定期向 PD 匯報(bào)節(jié)點(diǎn)的整體信息量窘。
- 每個(gè) Raft Group 的 Leader 會(huì)定期向 PD 匯報(bào)信息朗涩。
3.4 調(diào)度的策略
- 保障一個(gè) Region 的 Replica 數(shù)量正確:在掉節(jié)點(diǎn)或恢復(fù)節(jié)點(diǎn)時(shí),增刪replica
- 保障一個(gè) Raft Group 中的多個(gè) Replica 不在同一個(gè)位置: 位置包括物理機(jī)器绑改、單個(gè)機(jī)架、單個(gè)機(jī)房兄一±逑撸可以給節(jié)點(diǎn)配置 lables,需要在 Replica 分配的時(shí)候盡量保證不會(huì)有一個(gè) Region 的多個(gè) Replica 所在結(jié)點(diǎn)有相同的位置標(biāo)識(shí)出革。
- 副本在 Store 之間的分布均勻分配:維持每個(gè)節(jié)點(diǎn)上面造壮,副本數(shù)量的均衡,會(huì)使得總體的負(fù)載更均衡骂束。
- Leader 數(shù)量在 Store 之間均勻分配: Raft 協(xié)議要讀取核寫(xiě)入都通過(guò) Leader 進(jìn)行耳璧,所以計(jì)算的負(fù)載主要在 Leader 上面,PD 會(huì)盡可能將 Leader 在節(jié)點(diǎn)間分散開(kāi)展箱。
- 訪問(wèn)熱點(diǎn)數(shù)量在 Store 之間均勻分配:每個(gè) Store 以及 Region Leader 在上報(bào)信息時(shí)攜帶了當(dāng)前訪問(wèn)負(fù)載的信息旨枯,比如 Key 的讀取/寫(xiě)入速度。PD 會(huì)檢測(cè)出訪問(wèn)熱點(diǎn)混驰,且將其在節(jié)點(diǎn)之間分散開(kāi)攀隔。
- 各個(gè) Store 的存儲(chǔ)空間占用大致相等
- 控制調(diào)度速度,避免影響在線服務(wù)
3.5 自動(dòng)伸縮
TiDB 借助 TiDB Operator 和 PD 來(lái)實(shí)現(xiàn) Auto-Scale栖榨。目前由 TiDB Operator 組件定期獲取 TiDB / TiKV 的 metrics 信息后昆汹,通過(guò) API 的方式暴露出期望的 TiDB/TiKV numbers,然后由 TiDB Operator 定期拉取 PD API 信息后婴栽,通過(guò)內(nèi)部的 Auto-scaling 算法對(duì) TidbCluster.Spec.Replicas 進(jìn)行調(diào)整满粗,從而實(shí)現(xiàn)Auto-scaling。
3.6 動(dòng)態(tài)調(diào)度
3.7 根據(jù)負(fù)載動(dòng)態(tài)分裂 ( Load Base Splitting)
3.8 熱點(diǎn)隔離 (Isolate Frequently Access Region)
四愚争、TiDB 和 MySQL 的區(qū)別
TiDB 作為開(kāi)源 NewSQL 數(shù)據(jù)庫(kù)的典型代表之一映皆,同樣支持 SQL,支持事務(wù) ACID 特性轰枝。
在通訊協(xié)議上劫扒,TiDB 選擇與 MySQL 完全兼容,并盡可能兼容 MySQL 的語(yǔ)法狸膏。
因此沟饥,基于 MySQL 數(shù)據(jù)庫(kù)開(kāi)發(fā)的系統(tǒng),大多數(shù)可以平滑遷移至 TiDB,而幾乎不用修改代碼贤旷。對(duì)用戶來(lái)說(shuō)广料,遷移成本極低,過(guò)渡自然幼驶。
但仍有少量不兼容艾杏。