TiDB MVCC 多版本保存機(jī)制及其對(duì)性能的影響

從接觸TiDB以來(lái),就看到過(guò)TiDB官方文檔上的提示竣况,gc_life_time設(shè)置過(guò)大吮螺,會(huì)因?yàn)闅v史版本過(guò)多,影響查詢效率帕翻,但是為什么SQL非要去掃描歷史版本呢鸠补?下面列舉一些知識(shí)點(diǎn)一步一步來(lái)解析這個(gè)問題

1. TiDB key的編碼方式

TiDB 會(huì)對(duì)每個(gè)表分配一個(gè)全局唯一的table_id,每一個(gè)索引都會(huì)分配一個(gè)表內(nèi)唯一的 index_id嘀掸,每一行分配一個(gè) row_id(如果表有整數(shù)型的 Primary Key紫岩,那么會(huì)用 Primary Key 的值當(dāng)做 row_id,如果沒有睬塌,那么TiDB會(huì)自動(dòng)生成一個(gè)隱式主鍵_tidb_rowid)
數(shù)據(jù)編碼方式:
t{table_id}_r{row_id}-->[col1,col2,col3,...]
索引編碼方式:
unique index
t{table_id}_i{index_id}_{index_column_value}-->[row_id]
非unique index
t{table_id}_i{index_id}_{index_column_value}_{row_id}-->null
舉個(gè)栗子:

CREATE TABLE `test_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `column1` varchar(10) DEFAULT NULL,
  `column2` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_column1` (`column1`)
id column1 column2
1 "a" "b"
2 "c" "d"

那么主鍵編碼可以抽象為
t10_r1-->[1,"a","b"]
t10_r2-->[2,"c","d"]
索引idx_column1編碼可以抽象為
t10_i1_a_1-->null
t10_i1_b_2-->null

2. MVCC多版本信息是如何保存的泉蝌?

TiDB使用基于Percolator的事務(wù)模型,將一行數(shù)據(jù)抽象為default揩晴、write 和 lock 3 個(gè) CF(column family)存儲(chǔ)勋陪,其中:

  • default CF存儲(chǔ)的真正數(shù)據(jù)
    ${key}_${start_ts} --> ${value}
  • write CF存儲(chǔ)數(shù)據(jù)的版本信息,commit_ts代表一行記錄的真正版本
    ${key}_${commit_ts}-->${start_ts}
  • lock CF存放鎖信息,提交中的事務(wù)會(huì)加lock硫兰,包含primary lock的位置
    ${key}-->${start_ts,primary_key,..etc}

一個(gè)讀取操作的過(guò)程如下:

  1. 事務(wù)begin,從PD獲取start_ts
  2. 讀取key诅愚,先判斷l(xiāng)ock CF有沒有鎖,如果
    a. 有鎖
    判斷primary key狀態(tài)是否超時(shí)
    - 若鎖未超時(shí)劫映,等待
    - 若鎖已超時(shí)违孝,根據(jù)primary key的狀態(tài)rollback或commit殘留事務(wù)
    b. 無(wú)鎖
    根據(jù)當(dāng)前事務(wù)獲取的start_ts對(duì)比數(shù)據(jù)的commit_ts(write CF)
    - start_ts大于commit_ts,返回這行數(shù)據(jù)
    - start_ts小于commit_ts泳赋,繼續(xù)查找當(dāng)前行的下一個(gè)(更早的)版本
  3. 根據(jù)步驟2得到的commit_ts雌桑,從default CF中獲取真正的數(shù)據(jù)

TiDB將一行記錄的多個(gè)版本按照從新到老的順序排列,這樣方便我們獲得滿足查詢條件的最新記錄祖今,TiKV默認(rèn)存儲(chǔ)引擎是RocksDB校坑,RocksDB一個(gè)seek操作要比next操作昂貴很多拣技,如下這個(gè)例子
假設(shè)key1,key2,key3都有多次更新,生成的mvcc版本從老到新分別為key1_v1,key1_v2,key1_v3,key1_v4...
幾個(gè)相鄰key的存放方式抽象為下圖:


連續(xù)的key排列

Rocksdb沒辦法精確去定位每一個(gè)key耍目,如果掃描每一個(gè)key都走seek接口过咬,這樣代價(jià)太大。所以如圖制妄,假設(shè)一個(gè)范圍查詢seek到第一個(gè)key掸绞,key1之后,就開始調(diào)用next函數(shù)獲取后面的key2耕捞、key3值衔掸,這樣需要遍歷key1甚至key2的所有歷史版本。如此俺抽,就能解釋為什么過(guò)多的歷史版本會(huì)讓查詢效率急劇下降了敞映。

我們?nèi)粘9ぷ鹘?jīng)常碰見的幾個(gè)問題:
一、SQL執(zhí)行時(shí)間不穩(wěn)定
慢日志中會(huì)發(fā)現(xiàn)這些SQL語(yǔ)句的total keys比process keys大很多磷斧,這就是典型的歷史版本過(guò)多振愿,導(dǎo)致掃描了大量歷史數(shù)據(jù)。
解決方法

  1. 減小gc_life_time弛饭,或者讓業(yè)務(wù)縮小查詢范圍冕末。
  2. 升級(jí)TiDB3.0版本
    TiDB3.0之前的版本,全局GC效率不高侣颂,容易積壓大量歷史版本數(shù)據(jù)档桃。3.0之后改成了分布式GC,能夠快速釋放大量已刪除的歷史版本憔晒,再加上更完善的region merge功能藻肄,會(huì)讓整個(gè)集群的性能提升一個(gè)很大的臺(tái)階。

二拒担、刪除&歸檔特定日期以前的記錄

while True:
    delete table where {$condition} limit n
    if affectrows==0:
        break

這個(gè)場(chǎng)景的現(xiàn)象是delete語(yǔ)句會(huì)越來(lái)越慢嘹屯。
因?yàn)閽呙璺秶鷞$condition}是固定不變的,delete刪除語(yǔ)句在TiDB處理方式是標(biāo)記刪除从撼,刪除本身實(shí)際上也是插入一條kv記錄州弟,只不過(guò)value變成了delete。所以谋逻,循環(huán)執(zhí)行delete 語(yǔ)句呆馁,每次刪除n條記錄,下一次delete語(yǔ)句要掃描的key就會(huì)+n毁兆,執(zhí)行時(shí)間越來(lái)越長(zhǎng)(大家可以去做個(gè)實(shí)驗(yàn),觀察慢日志文件阴挣,同樣的delete語(yǔ)句total keys會(huì)不斷增加)气堕。

那么,怎樣去刪除&歸檔特定日期前的記錄比較高效呢?

首先茎芭,我們知道TiDB對(duì)事務(wù)大小是有限制的

  1. 單個(gè)事務(wù)包含的SQL語(yǔ)句不超過(guò)5000條
  2. 操作的單條記錄不超過(guò) 6MB
  3. 事務(wù)操作的總keys不超過(guò) 30w
  4. 事務(wù)操作的所有記錄總大小不超過(guò) 100MB

由于TiDB的事務(wù)限制和TiDB mvcc的實(shí)現(xiàn)原理揖膜,想要?jiǎng)h除&歸檔一個(gè)特定范圍的數(shù)據(jù),目前沒有太好的方法梅桩,個(gè)人整理一些心得供大家參考:
第一種方式:
盡量縮小范圍刪除的粒度壹粟,比如提前按分鐘將數(shù)據(jù)分段,打開tidb_batch_delete宿百,提高并發(fā)去刪除趁仙。注意使用開閉區(qū)間,分段之間不要出現(xiàn)沖突垦页,TiDB解決事務(wù)沖突的代價(jià)比較大雀费。

set @@session.tidb_batch_delete=1;
delete from table where create_time > '$start_step' and create_time <= '$end_step';

如果分段內(nèi)的數(shù)據(jù)超出事務(wù)大小限制,TiDB會(huì)自動(dòng)將delete操作拆分成多個(gè)batch痊焊。
個(gè)人親測(cè)盏袄,這種方式刪除數(shù)據(jù)的速度還是比較快的。
第二種方式:
按照日期分表薄啥,刪除過(guò)期的表即可辕羽。TiDB刪表是秒級(jí)的,后續(xù)空間回收也比較快垄惧,缺點(diǎn)是侵入業(yè)務(wù)逛漫。
兩種方式各有利弊,大家各取所需吧赘艳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酌毡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蕾管,更是在濱河造成了極大的恐慌枷踏,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掰曾,死亡現(xiàn)場(chǎng)離奇詭異旭蠕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)旷坦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門掏熬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人秒梅,你說(shuō)我怎么就攤上這事旗芬。” “怎么了捆蜀?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵疮丛,是天一觀的道長(zhǎng)幔嫂。 經(jīng)常有香客問我,道長(zhǎng)誊薄,這世上最難降的妖魔是什么履恩? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮呢蔫,結(jié)果婚禮上切心,老公的妹妹穿的比我還像新娘。我一直安慰自己片吊,他們只是感情好绽昏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著定鸟,像睡著了一般而涉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上联予,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天啼县,我揣著相機(jī)與錄音,去河邊找鬼沸久。 笑死季眷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卷胯。 我是一名探鬼主播子刮,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窑睁!你這毒婦竟也來(lái)了挺峡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤担钮,失蹤者是張志新(化名)和其女友劉穎橱赠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箫津,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狭姨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苏遥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饼拍。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖田炭,靈堂內(nèi)的尸體忽然破棺而出师抄,到底是詐尸還是另有隱情,我是刑警寧澤诫肠,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布司澎,位于F島的核電站欺缘,受9級(jí)特大地震影響栋豫,放射性物質(zhì)發(fā)生泄漏挤安。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一丧鸯、第九天 我趴在偏房一處隱蔽的房頂上張望蛤铜。 院中可真熱鬧,春花似錦丛肢、人聲如沸围肥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)穆刻。三九已至,卻和暖如春杠步,著一層夾襖步出監(jiān)牢的瞬間氢伟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工幽歼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朵锣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓甸私,卻偏偏與公主長(zhǎng)得像诚些,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皇型,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354