TiDB new feature max_execution_time

max_execution_time的作用

據(jù)說max_execution_time是mysql5.7.8(沒有實際的驗證過)提供的一個feature棠耕,能夠有效地控制慢查詢响驴,尤其對于數(shù)據(jù)庫性能要求比較高的業(yè)務(wù)場景非常有用。我在mysql和TiDB的生產(chǎn)環(huán)境下,之前都遇到過因為慢查詢消耗過多的機器資源,從而影響生產(chǎn)環(huán)境可用性的情況:

  • mysql遇到問題的場景是:我們豐巢的一個基礎(chǔ)服務(wù)采用的mycat分庫分表,有個字段是字符串類型徒恋,但是開發(fā)小哥哥在查詢數(shù)據(jù)的時候傳的值是數(shù)值,造成索引失效欢伏,從而全表掃描入挣。當(dāng)時對于io等資源消耗非常嚴(yán)重,直接影響了生產(chǎn)環(huán)境的使用硝拧;
  • TiDB的問題也是一樣的径筏,如果column是字符串,但傳的值是數(shù)值類型障陶,它的執(zhí)行計劃會不斷的讀取TiKV的返回值并在TiDB做運算cast滋恬,當(dāng)時我們用的是千兆網(wǎng)卡,網(wǎng)絡(luò)直接打滿抱究;

雖然我們豐巢針對生產(chǎn)環(huán)境的數(shù)據(jù)庫做了很多的限制恢氯,但總是難免會出現(xiàn)類似于上面提到的問題。在我們之前使用的TiDB版本(2.1.4)是沒有max_execution_time這個特性的鼓寺,當(dāng)時我們?yōu)榱朔乐股厦娴膯栴}再次出現(xiàn)勋拟,還專門的寫了一個TiDB的監(jiān)控模塊,當(dāng)出現(xiàn)高消耗的慢sql時妈候,監(jiān)控程序可以直接kill tidb session來完成「颐遥現(xiàn)在有了max_execution_time,一切都變得簡單了苦银,我們可以在系統(tǒng)變量的級別來設(shè)置max_execution_time的值啸胧,從而限定了query sql的最大執(zhí)行毫秒數(shù)赶站,避免災(zāi)難的發(fā)生。

TiDB max_execution_time初見

我記得TiDB在2.1的某一個小版本里面便引入了max_execution_time的hint語法纺念,但那時沒有實際的作用,看release的介紹烙博,max_execution_time可以在實際環(huán)境中使用焙格,是在2.1.14版本才開始的。如圖:


max_execution_time

global 變量方式測試

我只進行了global級別的系統(tǒng)變量的測試,沒有測試hint的方式,因為hint的方式在我們豐巢使用的概率比較低氯窍,兩方面的原因:一是hint的對于sql的改動較大;二是很難完成所有的sql添加此hint,一旦出現(xiàn)漏網(wǎng)之魚并且出了問題布隔,那前面做的工作都沒有啥意義。測試的準(zhǔn)備環(huán)境如下:

  • TiDB版本 2.1.15
  • TiDB節(jié)點數(shù)量:3
  • TiDB開啟binlog服務(wù)pump
  • TiKV節(jié)點數(shù)量:12(3臺物理機计济,每臺4個實例)
  • PD情況:與TiDB淘衙、pump服務(wù)部署在相同的3臺物理機上毯侦,3個節(jié)點
  • 硬件條件:全部是SSD的磁盤
  • 負載均衡:nginx1.17.1+stream

測試用例

我的測試用例都比較簡單筝蚕,首先使用數(shù)據(jù)同步工具和豐巢自研的流量錄制和實時回放工具起宽,將生產(chǎn)環(huán)境的實際數(shù)據(jù)實時同步到測試環(huán)境绿映,單表最大行數(shù)在幾十億這個級別叉弦。主要是想測試3種實際的情況:

  • 變量max_execution_time的測試:多次設(shè)置global max_execution_time 的值,測試它在不同session的情況下是否實時生效;
  • 測試在TiDB端和TiKV端都有大量計算的查詢語句情況,這個測試用例比較容易就可以實現(xiàn),就用上面說的那個把網(wǎng)絡(luò)打滿的生產(chǎn)問題用例即可袱饭,使用傳遞的值為數(shù)字,但是列為字符串的sql語句晾虑,像這樣:select user_id,user_name from test where user_name = 18612345678;
  • 測試計算主要是在TiKV端執(zhí)行的語句疹味,其中列user_content沒有索引:select user_id,user_name,user_content from test where user_content = '123456';

測試結(jié)果

變量實時生效結(jié)果測試

我在一開始測試的時候,變量在1秒和10秒之間來回設(shè)置帜篇,如下:

set GLOBAL MAX_EXECUTION_TIME = 10000 //10秒
set GLOBAL MAX_EXECUTION_TIME = 1000 //1秒

發(fā)現(xiàn)我在把最大執(zhí)行時間從1秒切到10秒時糙捺,query被中斷的時間卻還是1秒。經(jīng)過深入的分析笙隙,發(fā)現(xiàn)是global和session級別的原因洪灯,當(dāng)我們設(shè)置了global的變量后,已經(jīng)啟動的session實際用到的變量值逃沿,還是之前的session變量值婴渡,也就是舊值幻锁。這個時候凯亮,如果我們重新打開一個session,MAX_EXECUTION_TIME是生效的哄尔,也就是說新的session會讀取最新的global變量的值假消。那么,這里就需要我們在實際的生產(chǎn)環(huán)境使用的時候要注意岭接,因為大部分的生產(chǎn)環(huán)境都是使用的長連接富拗,session很長時間都不會被關(guān)閉的,因為和我們的預(yù)期值不一致鸣戴,很有可能會帶來生產(chǎn)問題啃沪。關(guān)于TiDB和mysql的session和global的詳細細節(jié),我也沒有深入了解過窄锅,后面有時間會對這塊做個分析创千,我覺得類似于MAX_EXECUTION_TIME這種變量,最好是只有g(shù)lobal和hint兩種級別入偷,否則很容易帶來理解上的混淆以及潛在的生產(chǎn)環(huán)境問題追驴。我猜測TiDB這樣做,是為了要兼容mysql的原因疏之。

TiDB端和TiKV端都有大量計算測試結(jié)果

首先設(shè)置MAX_EXECUTION_TIME為10秒

set GLOBAL MAX_EXECUTION_TIME = 10000

再啟動一個新的連接殿雪,執(zhí)行類似于下面的語句,user_name為字符串類型變量锋爪,test表行數(shù)有一億以上的數(shù)據(jù)

select user_id,user_name from test where user_name = 18612345678;

測試結(jié)果為

> 1317 - Query execution was interrupted
> 時間: 12.31s

從結(jié)果上看丙曙,此種慢查詢的語句爸业,在超過最大執(zhí)行時間后,是可以被TiDB正常的結(jié)束掉的亏镰。

計算主要是在TiKV端執(zhí)行的語句測試結(jié)果

這個測試用例的目的是想看看沃呢,計算已經(jīng)下推導(dǎo)TiKV上的query語句,能不能在超過最大執(zhí)行時間后正常的結(jié)束掉拆挥,還是在超時時間為10秒的情況下薄霜,執(zhí)行下面的語句,如前面說的纸兔,user_content是沒有索引的

select user_id,user_name,user_content  from test where user_content = '123456';

測試結(jié)果如下:

> OK
> 時間: 75.91s

測試結(jié)果說明惰瓜,TiDB是無法正常結(jié)束這種計算都是在TiKV上做的語句的,在TiDB判斷了超時時間過后汉矿,是無法通知到TiKV去結(jié)束掉這次計算的崎坊,只能等待TiKV返回結(jié)果后,再做決定洲拇。

源碼分析

大家有興趣奈揍,可以跟隨這個PR,Add support for MAX_EXECUTION_TIME赋续,去詳細的分析源碼男翰,在這里我們來簡單的看一下相關(guān)的源碼。TiDB里面有一個processinfo的存儲空間纽乱,主要是存儲所有session的當(dāng)前執(zhí)行sql的情況蛾绎,我之前還寫過一篇源碼分析show processlist的源碼里面有講到過processinfo的情況。

  • 首先我們來看看max_execution_time是如何存儲到processinfo中的:
        maxExecutionTime := getMaxExecutionTime(sctx, a.StmtNode)
        // Update processinfo, ShowProcess() will use it.
        pi.SetProcessInfo(sql, time.Now(), cmd, maxExecutionTime)
        a.Ctx.GetSessionVars().StmtCtx.StmtType = GetStmtLabel(a.StmtNode)

代碼在adapter.go的Exec方法中鸦列,主要就是在sql執(zhí)行前租冠,先獲取max_execution_time的實際值,然后存到當(dāng)前session的processinfo存儲空間里面薯嗤。

  • getMaxExecutionTime
    那么maxExecutionTime的具體值的到底是怎么來的呢顽爹?當(dāng)hint和session同時存在時,優(yōu)先級是如何計算的呢骆姐?
func getMaxExecutionTime(sctx sessionctx.Context, stmtNode ast.StmtNode) uint64 {
    ret := sctx.GetSessionVars().MaxExecutionTime
    if sel, ok := stmtNode.(*ast.SelectStmt); ok {
        for _, hint := range sel.TableHints {
            if hint.HintName.L == variable.MaxExecutionTime {
                ret = hint.MaxExecutionTime
                break
            }
        }
    }
    return ret
}

由上面的代碼可知镜粤,hint的優(yōu)先級會高于session的優(yōu)先級,這也符合我們正常的思維方式诲锹。

  • 如何kill掉超時的query
    最后我們來看看繁仁,TiDB是如何判斷query超時了,并kill掉它的归园,在expensivequery.go中有一個goroutine會不斷的check黄虱,主要邏輯如下:
for {
        select {
        case <-ticker.C:
            processInfo := eqh.sm.ShowProcessList()
            for _, info := range processInfo {
                if info.Info == nil || info.ExceedExpensiveTimeThresh {
                    continue
                }
                costTime := time.Since(info.Time)
                if costTime >= time.Second*time.Duration(threshold) && log.GetLevel() <= zapcore.WarnLevel {
                    logExpensiveQuery(costTime, info)
                    info.ExceedExpensiveTimeThresh = true

                } else if info.MaxExecutionTime > 0 && costTime > time.Duration(info.MaxExecutionTime)*time.Millisecond {
                    eqh.sm.Kill(info.ID, true)
                }
            }
            threshold = atomic.LoadUint64(&variable.ExpensiveQueryTimeThreshold)
        case <-eqh.exitCh:
            return
        }
    }

這個goroutine會通過ShowProcessList不斷的讀取當(dāng)前正在執(zhí)行的sql語句,并判斷costTime是否已經(jīng)超過了之前設(shè)置到processinfo中的MaxExecutionTime庸诱,如果超過了捻浦,則kill掉這條query晤揣。其中的time.Millisecond 也表明了MaxExecutionTime的單位是毫秒。

最后

我個人覺得這個feature對于高并發(fā)的交易型業(yè)務(wù)是非常有必要的朱灿,它是可以作為一個最后的兜底策略昧识。希望pingcap公司后面能在TiKV層面也能支持這個feature,真正的將風(fēng)險降到最低盗扒,我本人對于TiDB是充滿了無限期待的跪楞,希望它能越來越NB。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侣灶,一起剝皮案震驚了整個濱河市甸祭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌褥影,老刑警劉巖池户,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凡怎,居然都是意外死亡校焦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門统倒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寨典,“玉大人,你說我怎么就攤上這事檐薯∧” “怎么了注暗?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵坛缕,是天一觀的道長。 經(jīng)常有香客問我捆昏,道長赚楚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任骗卜,我火速辦了婚禮宠页,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寇仓。我一直安慰自己举户,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布遍烦。 她就那樣靜靜地躺著俭嘁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪服猪。 梳的紋絲不亂的頭發(fā)上供填,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天拐云,我揣著相機與錄音,去河邊找鬼近她。 笑死叉瘩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的粘捎。 我是一名探鬼主播薇缅,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼攒磨!你這毒婦竟也來了捅暴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咧纠,失蹤者是張志新(化名)和其女友劉穎蓬痒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漆羔,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡梧奢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了演痒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亲轨。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鸟顺,靈堂內(nèi)的尸體忽然破棺而出惦蚊,到底是詐尸還是另有隱情,我是刑警寧澤讯嫂,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布蹦锋,位于F島的核電站,受9級特大地震影響欧芽,放射性物質(zhì)發(fā)生泄漏莉掂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一千扔、第九天 我趴在偏房一處隱蔽的房頂上張望憎妙。 院中可真熱鬧,春花似錦曲楚、人聲如沸厘唾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抚垃。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讯柔,已是汗流浹背抡蛙。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留魂迄,地道東北人粗截。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像捣炬,于是被迫代替她去往敵國和親熊昌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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

  • 一湿酸、了解TiDB 1.1 TiDB整體架構(gòu) 要深入了解 TiDB 的水平擴展和高可用特點婿屹,首先需要了解 TiDB ...
    什錦小沐閱讀 1,482評論 0 6
  • 一、分布式數(shù)據(jù)庫誕生背景 隨著互聯(lián)網(wǎng)的飛速發(fā)展推溃,業(yè)務(wù)量可能在短短的時間內(nèi)爆發(fā)式地增長昂利,對應(yīng)的數(shù)據(jù)量可能快速地從幾百...
    nightwish夜愿閱讀 3,522評論 0 12
  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,793評論 0 38
  • 現(xiàn)在躺在床上,已經(jīng)不想再動一下铁坎,感覺骨頭已經(jīng)撐不住身體蜂奸。但是心里是開心的。 Ta越來越愛我硬萍,是近乎接近完美的愛扩所,不...
    一年后的自己2019年1月28閱讀 49評論 0 0
  • 截止至4月12日,小桔租車目前正式登陸了深圳朴乖、長沙祖屏、株洲和湘潭。并且實施無押金租車模式买羞。 小桔租車現(xiàn)在已經(jīng)分布10...
    于Mango閱讀 906評論 0 0