使用TiDB把自己寫分庫(kù)分表方案推翻了

背景

在日益數(shù)據(jù)量增長(zhǎng)的情況下造烁,影響數(shù)據(jù)庫(kù)的讀寫性能午笛,我們一般會(huì)有分庫(kù)分表的方案和使用newSql方案,newSql如TIDB告组。那么為什么需要使用TiDB呢?有什么情況下才用TiDB呢惹谐?解決傳統(tǒng)分庫(kù)分表的什么問題呢?還會(huì)解釋一些關(guān)鍵點(diǎn)和踩坑點(diǎn)氨肌。下面我會(huì)用比較白話的形式解讀,當(dāng)做對(duì)TiDB進(jìn)行推廣怎囚。

目前痛點(diǎn)

目前分庫(kù)表無(wú)論使用原生JDBC+ThreadLocal方案,還是使用中間件proxy恳守、還是SDK嵌入代碼的形式,即使用sharding-jdbc催烘、zdal、mycat都存在著以下問題伊群。

  1. 分庫(kù)分表算法方案的選型
  2. 分庫(kù)分表后帶來的后續(xù)維護(hù)工作,每次增加節(jié)點(diǎn)舰始,都需要申請(qǐng)磁盤、機(jī)器
  3. 新增節(jié)點(diǎn)需要進(jìn)行停機(jī)丸卷、然后遷移數(shù)據(jù),停機(jī)遷移對(duì)線上用戶造成實(shí)時(shí)的讀寫影響谜嫉。遷移失敗還有代碼回滾。遷移前還要等mysql沒有binlog產(chǎn)生后才能遷移骄恶。
  4. 分庫(kù)分表后,跨庫(kù)一致性問題僧鲁,都是使用最終一致性,代碼維護(hù)繁瑣寞秃。
  5. 數(shù)據(jù)存儲(chǔ)壓力、數(shù)據(jù)存放量偏移于某個(gè)節(jié)點(diǎn)
  6. 數(shù)據(jù)索引查詢效率

目的

希望解決上述痛點(diǎn)

TiDB整體架構(gòu)

TiDB是一種分布式數(shù)據(jù)庫(kù)春寿。其實(shí)形式上來講比較像Hadoop的做法,把數(shù)據(jù)分布在不同的機(jī)器上绑改,并且有副本,有負(fù)責(zé)計(jì)算的機(jī)器厘线、也由負(fù)責(zé)存儲(chǔ)的機(jī)器。


image.png

入口層為tidb-server渡讼,圖中TiDB,是客戶端接入的入口成箫,負(fù)責(zé)處理請(qǐng)求接口,這一層對(duì)存儲(chǔ)要求不高蹬昌,用于計(jì)算所以對(duì)CPU要求高,還有記錄每個(gè)region的負(fù)責(zé)的范圍凳厢。
第二層是PD,負(fù)責(zé)調(diào)度先紫,如zookeeper的形式筹煮,負(fù)責(zé)數(shù)據(jù)遷移的調(diào)度、選舉的調(diào)度败潦。
第三層是tikv,也叫store劫扒,負(fù)責(zé)真實(shí)存儲(chǔ)數(shù)據(jù)的一層。其中tikv由1個(gè)或者多個(gè)region組成沟饥,Region為最小的存儲(chǔ)單元,就如JVM G1算法的Region的意思贤旷。每個(gè)Region將會(huì)打散分布在各個(gè)tikv下。

數(shù)據(jù)存儲(chǔ)模型

image.png
  1. 行數(shù)據(jù)(元數(shù)據(jù))
    一個(gè)表將會(huì)由一個(gè)或者多個(gè)Region存儲(chǔ)艾杏。不同的表將會(huì)在不同的Region,而不是如傳統(tǒng)分庫(kù)那樣每個(gè)庫(kù)里的表都是相同购桑。
    那么一個(gè)表下,每一行數(shù)據(jù)存儲(chǔ)在哪個(gè)Region下是如何確定呢勃蜘?
    首先,Region里面是一個(gè)Map元旬, key 由 table_id表id、rowid主鍵組成匀归。如:

t[table_id]_r[row_id]

map的value為表中每行數(shù)據(jù)的真實(shí)數(shù)據(jù)。

  1. 索引數(shù)據(jù)
    索引數(shù)據(jù)將會(huì)在另外一個(gè)Region存儲(chǔ)穆端,每建一個(gè)索引,就會(huì)有那個(gè)索引對(duì)應(yīng)的Region体啰。它的Map的 key 由 table_id、index_id 以及索引列的值編碼組成荒勇。如:

t[table_id]_i[index_id][index_value]

value為rowid,這樣就能用rowid來找到上面的表數(shù)據(jù)的位置沽翔。
就如mysql按索引查詢,會(huì)先去找索引記錄仅偎,再去找到主鍵聚簇索引來獲取真實(shí)數(shù)據(jù)一個(gè)邏輯。

數(shù)據(jù)切分

定位在哪個(gè)Region橘沥,就是靠Key來算出落在哪個(gè)Region里面。和分庫(kù)分表的根據(jù)某個(gè)字段來一致性hash算法方案不同座咆。
TiDB的負(fù)責(zé)行真實(shí)數(shù)據(jù)的Region是使用主鍵范圍來劃分的。
有索引情況下箫措,負(fù)責(zé)索引的Region會(huì)根據(jù)索引字段范圍來劃分。
基于Key通過計(jì)算斤蔓,將會(huì)得出一個(gè)數(shù)字,然后按范圍劃分多個(gè)區(qū)間弦牡,每個(gè)區(qū)間由一個(gè)Region管理。

如:一個(gè)表數(shù)據(jù)主鍵rowid落在3個(gè)Region驾锰。
[0,10000)
[10001,20000)
[20001,30000)

這個(gè)范圍需要數(shù)據(jù)入表前確定這個(gè)規(guī)則。

因?yàn)镽egion將會(huì)分布在所有TiKV上椭豫,也就有多個(gè)服務(wù)器去存數(shù)據(jù)旨指,所以利用多機(jī)器CPU和磁盤喳整,解決了痛點(diǎn)5存儲(chǔ)壓力,也解決了痛點(diǎn)1分庫(kù)分表用哪個(gè)算法方案框都,只需要確定主鍵范圍即可。

后續(xù)會(huì)說如何擴(kuò)容魏保。

提高索引效率

現(xiàn)有問題:
傳統(tǒng)分庫(kù)分表的索引都是在每個(gè)mysql實(shí)例里,跟著表走的谓罗。分庫(kù)分表規(guī)則,一般都是根據(jù)表中的userid用戶字段或組合性較高的字段來做切分庫(kù)或者表的鍵檩咱,相同的userid將會(huì)落在相同的庫(kù)或者表。

但是上述情況下税手,表中的索引字段假設(shè)為code芦倒,則code="aaa"的可能會(huì)因?yàn)椴煌膗serid落在不同的庫(kù)中,需要查詢?nèi)康膸?kù)和表后兵扬,再重新聚合,這樣就會(huì)增加CPU查詢的消耗口蝠、還有TCP連接握手的消耗。

TiDB解決:
然而TiKV的有專門用于存儲(chǔ)索引的Region妙蔗,它數(shù)據(jù)結(jié)構(gòu)的Key是由 表id+索引id+索引值id來決定的,value是rowid數(shù)據(jù)行主鍵眉反,并且一個(gè)Region管理一個(gè)范圍的Key,所以同一個(gè)索引同一個(gè)值都會(huì)在一個(gè)Region里面寸五,這樣就比較好快速定位相同的索引值的Region,得出對(duì)應(yīng)的rowid梳杏,再根據(jù)rowid去存儲(chǔ)表數(shù)據(jù)的Region中更快速找到表真實(shí)數(shù)據(jù)淹接。就不需要走全量庫(kù)的索引查找叛溢,因?yàn)閙ysql索引查找機(jī)制是先找到索引值,然后再找聚簇的主鍵后返回整行數(shù)據(jù)雇初,從而提高性能。

這種做法有點(diǎn)像elastic-search的倒排索引靖诗,先根據(jù)value值再定位數(shù)據(jù)原來位置。這里解決痛點(diǎn)6減少索引查詢壓力刊橘。

TIDB特性

1. 提供樂觀事務(wù)模型和悲觀事務(wù)模型

在3.0.8之前只有樂觀事務(wù)模型,都是通過2PC兩次提交的方式來進(jìn)行事務(wù)提交促绵。如果開啟悲觀事務(wù)模型,會(huì)比較像sharding-jdbc的柔性事務(wù)败晴,有重試的功能,但是依然重試過多次(256次)失敗仍然會(huì)丟失尖坤。

1.1 優(yōu)缺點(diǎn)分析

TiDB 事務(wù)有如下優(yōu)點(diǎn):

  • 實(shí)現(xiàn)原理簡(jiǎn)單,易于理解慢味。
  • 基于單實(shí)例事務(wù)實(shí)現(xiàn)了跨節(jié)點(diǎn)事務(wù)。
  • 鎖管理實(shí)現(xiàn)了去中心化纯路。
    但 TiDB 事務(wù)也存在以下缺點(diǎn):
  • 兩階段提交使網(wǎng)絡(luò)交互增多。
  • 需要一個(gè)中心化的版本管理服務(wù)驰唬。
  • 事務(wù)數(shù)據(jù)量過大時(shí)易導(dǎo)致內(nèi)存暴漲。

1.2 事務(wù)的重試

使用樂觀事務(wù)模型時(shí)定嗓,在高沖突率的場(chǎng)景中,事務(wù)很容易提交失敗宵溅。而 MySQL 內(nèi)部使用的是悲觀事務(wù)模型,在執(zhí)行 SQL 語(yǔ)句的過程中進(jìn)行沖突檢測(cè)恃逻,所以提交時(shí)很難出現(xiàn)異常藕施。為了兼容 MySQL 的悲觀事務(wù)行為,TiDB 提供了重試機(jī)制裳食。
這種加重試就是悲觀事務(wù)。

上述解決痛點(diǎn)4诲祸,不用再去自己維護(hù)跨庫(kù)處理的事務(wù)最終一致性的代碼,如A用戶轉(zhuǎn)賬到B用戶救氯,也如商家和買家的情況,商家比較多收入時(shí)的交易情況着憨。
雖然重試多次仍然會(huì)失敗,但是這部分由TiDB處理甲抖。如果跨庫(kù)事務(wù)以前的系統(tǒng)有框架處理,那現(xiàn)在就不需要如sharding-jdbc的sdk方式需要靠程序運(yùn)行時(shí)才能重試准谚,不然如果我們程序down機(jī)重試就沒了。

2. 自動(dòng)擴(kuò)容

2.1 Region分裂

Region為最小的存儲(chǔ)單元氛魁,當(dāng)數(shù)據(jù)進(jìn)入一個(gè)Region后達(dá)到一定數(shù)量,就會(huì)開始分裂(默認(rèn)是超過現(xiàn)有Region負(fù)責(zé)范圍的1/16)。
注意:數(shù)據(jù)表 Key 的 Range 范圍劃分捶码,需要提前設(shè)置好,TiKV 是根據(jù) Region 的大小動(dòng)態(tài)分裂的惫恼。

這里是解決痛點(diǎn)2的每次都需要申請(qǐng)資源,不再運(yùn)維來做上線前遷移數(shù)據(jù)祈纯,痛點(diǎn)3遷移時(shí)又要停機(jī)影響生成用戶

因?yàn)門iDB作為中間件腕窥,不帶任何業(yè)務(wù)屬性,所以就不能使用userid等字段來做分片規(guī)則的鍵和自定義算法簇爆,使用主鍵是最通用的選擇爽撒。(其實(shí)我覺得如果TiDB能做到就最好了)

2.2 新增存儲(chǔ)節(jié)點(diǎn)

  1. 新增節(jié)點(diǎn)或者分裂Region,都有可能會(huì)觸發(fā)遷移Region硕勿,由TiDB自動(dòng)完成。不再需要入侵代碼源武、或者使用中間件做分庫(kù)分表邏輯和數(shù)據(jù)遷移、上線演練粱栖,全程交給運(yùn)維(手動(dòng)甩鍋)。
  2. 并且不需要代碼服務(wù)停機(jī)查排,不需要等沒有新sql執(zhí)行后才能遷移,這個(gè)是運(yùn)行過程中實(shí)時(shí)遷移數(shù)據(jù)的跋核。

這里就解決了痛點(diǎn)3停機(jī)遷移數(shù)據(jù)、痛點(diǎn)5存儲(chǔ)壓力砂代。

3. 副本容災(zāi)

每個(gè) Region 負(fù)責(zé)維護(hù)集群的一段連續(xù)數(shù)據(jù)(默認(rèn)配置下平均約 96 MiB),每份數(shù)據(jù)會(huì)在不同的 Store 存儲(chǔ)多個(gè)副本(默認(rèn)配置是 3 副本)刻伊,每個(gè)副本稱為 Peer。同一個(gè) Region 的多個(gè) Peer 通過 raft 協(xié)議進(jìn)行數(shù)據(jù)同步捶箱,所以 Peer 也用來指代 raft 實(shí)例中的成員。

所以如果有1億數(shù)據(jù)动漾,將會(huì)由3億數(shù)據(jù)落在磁盤中,雖然消耗磁盤旱眯,但是提高了可靠性。

TIDB成本

  1. 官方推薦至少部署 3 個(gè) TiKV删豺, 3 個(gè) PD,2 個(gè) TiDB呀页。
  2. TiDB需要能使用線程數(shù)多的,PD需要CPU比較好的蓬蝶,TiKV需要SSD和CPU比較好的渴逻。
  3. 在論壇看到大家用的內(nèi)存都是100G的,磁盤都是2T 的SSD音诫。因?yàn)槊啃袛?shù)據(jù)都總共有3個(gè)副本惨奕,消耗磁盤多竭钝。所以一個(gè)系統(tǒng)使用一套TiDB需要不少的成本。
  4. 然而這只是一個(gè)系統(tǒng)所需香罐,一個(gè)項(xiàng)目中有多個(gè)系統(tǒng)組成情況下,就消耗更多資源了庇茫。并且隨著數(shù)據(jù)日益增多將會(huì)越來越多資源。

使用場(chǎng)景

  1. 數(shù)據(jù)量達(dá)到一定量級(jí)旦签,需要減少查詢壓力或者連接池不夠等等因素后才需要進(jìn)行。因?yàn)楣俜浇ㄗh需要有2個(gè)tidb-server宁炫、至少兩個(gè)PD、三個(gè)tikv羔巢,而且tikv需要都是SSD固態(tài)硬盤。所以在這種成本下竿秆,不一定所有項(xiàng)目都會(huì)使用,公司不一定愿意花成本去使用幽钢。而在一些數(shù)據(jù)量小的情況,建議還是使用mysql搅吁,等到數(shù)據(jù)量上來后落午,再做數(shù)據(jù)同步到TiDB。
  2. 已經(jīng)分庫(kù)分表后溃斋,希望改為使用TiDB,也能進(jìn)行合并梗劫,需要使用TiDB Data Migration截碴。
  3. 先在公司的架構(gòu)組的項(xiàng)目使用,再到不是核心業(yè)務(wù)的項(xiàng)目使用日丹,最后鋪開給核心項(xiàng)目使用。
  4. 入門成本高哲虾,實(shí)驗(yàn)起來需要成本,因?yàn)楣俜酵扑]的部署方式需要多臺(tái)好的機(jī)器束凑。

注意事項(xiàng)與坑點(diǎn)

  1. 建議使用3.0.4、3.0.8或者4.0.0 (現(xiàn)在是2020年4月2日)汪诉,不建議使用2.0版本,不然會(huì)出現(xiàn)升級(jí)不兼容的問題谈秫,需要去解決。
  2. 在增加節(jié)點(diǎn)擴(kuò)容時(shí)孝常,或者Region分裂時(shí),同時(shí)有SQL執(zhí)行insert或者更新數(shù)據(jù)构灸,如果命中到對(duì)應(yīng)的Region正在遷移,就可能會(huì)出現(xiàn)insert或者update出錯(cuò) 說“not leader”沒有找到對(duì)應(yīng)的位置的意思喜颁。但是會(huì)有重試的形式,把數(shù)據(jù)最終提交半开。
  3. 提前設(shè)置路由Region的分片范圍規(guī)則,不然導(dǎo)入數(shù)據(jù)時(shí)會(huì)都落在一個(gè)節(jié)點(diǎn)上寂拆。如果你以前的主鍵數(shù)據(jù)時(shí)雪花算法得出的,那就需要求出最大最小值自己算范圍手動(dòng)設(shè)置好范圍規(guī)則纠永。
  4. TiDB 不支持 SELECT LOCK IN SHARE MODE。使用這個(gè)語(yǔ)句執(zhí)行的時(shí)候尝江,效果和沒有加鎖是一樣的,不會(huì)阻塞其他事務(wù)的讀寫。
  5. 不要再使用Syncer同步數(shù)據(jù)或遷移到TiDB啤覆,因?yàn)槿绻谝呀?jīng)分庫(kù)分表的情況下,使用Syncer同步窗声,在某個(gè)帖子看的說會(huì)出問題。建議使用TiDB Data Migration
  6. TiDB無(wú)法修改字段類型

總結(jié)

其實(shí)有了上述功能嫌佑,就可以減少分庫(kù)分表的開發(fā)、運(yùn)維維護(hù)成本屋摇,主要是平常分庫(kù)分表到一定量要遷移,經(jīng)常需要監(jiān)控是否到遷移的量了炮温,遷移時(shí)需要演練,遷移時(shí)要更新代碼或者配置并且停業(yè)務(wù)是影響最大的柒啤。
雖然完成分庫(kù)分表好像解決了一些問題,但是帶來的后續(xù)還是很多的担巩,TiDB就給我們解決了上面的問題,這樣就可以更加專注的做業(yè)務(wù)了涛癌。


歡迎關(guān)注,文章更快一步

我的公眾號(hào) :地藏思維

掘金:地藏Kelvin

簡(jiǎn)書:地藏Kelvin

我的Gitee: 地藏Kelvin https://gitee.com/kelvin-cai

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拳话,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弃衍,更是在濱河造成了極大的恐慌,老刑警劉巖镜盯,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異速缆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)激涤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門倦踢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辱挥,你說我怎么就攤上這事∥畹猓” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵园爷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我童社,道長(zhǎng),這世上最難降的妖魔是什么扰楼? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮弦赖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹬竖。我一直安慰自己,他們只是感情好案腺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著劈榨,像睡著了一般访递。 火紅的嫁衣襯著肌膚如雪拷姿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天响巢,我揣著相機(jī)與錄音,去河邊找鬼踪古。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拘泞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陪腌,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了诗鸭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤强岸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后请唱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡十绑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年酷勺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脆诉。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖击胜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情偶摔,我是刑警寧澤暇唾,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布策州,位于F島的核電站,受9級(jí)特大地震影響宫仗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜藕夫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一枯冈、第九天 我趴在偏房一處隱蔽的房頂上張望办悟。 院中可真熱鬧,春花似錦誉尖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)探熔。三九已至,卻和暖如春诀艰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饮六。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卤橄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓窟扑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嚎货。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容