The total number of locks exceeds the lock table size 異常處理

線上一個實例報錯The total number of locks exceeds the lock table size異常,導(dǎo)致復(fù)制中斷,而當(dāng)時的SQL是一條insert into select xxx語句,結(jié)果集比較大缘眶,從提示信息看是當(dāng)前事務(wù)的lock size超過了lock table size,那么當(dāng)前事務(wù)需要多大的lock size,而系統(tǒng)的lock table size又是多大呢。

從show innodb status 可以看出當(dāng)前事務(wù)的lock size大忻嬷场:

---TRANSACTION 65CEAB, ACTIVE 5492 sec, process no 10782, OS thread id 140449790605056 inserting

mysql tables in use 2, locked 2

9339476 lock struct(s), heap size 831633848, 49142856 row lock(s), undo log entries 12491866

MySQL thread id 910089, query id 14148540 Sending data

INSERT IGNORE INTO

? ? ? ? T_XXX_TMP(

? ? ? ? FID,

? ? ? ? FSOURCE_NAME,

? ? ? ? FUNIQUE,

? ? ? ? FTITLE,

? ? ? ? FCONTENT,

? ? ? ? FLINK,

? ? ? ? FSOURCE_IMG_URL,

? ? ? ? FIMG_URL,

? ? ? ? FPUSH_PATH,

? ? ? ? FPUTDATE,

? ? ? ? FSTATUS,

? ? ? ? FTYPE,

? ? ? ? FAUTHOR,

? ? ? ? FLMODIFY,

? ? ? ? FPOSTTIME,

? ? ? ? FKEYWORDS,

? ? ? ? FPV,

? ? ? ? FRECOMMEND,

? ? ? ? FRESOURCE_TYPE,

? ? ? ? FLABEL,

? ? ? ? FCOMMENT_COUNT,

? ? ? ? FSHARE_COUNT,

? ? ? ? FCOLLECT_COUNT,

? ? ? ? FBIG_IMG_URL,

? ? ? ? FCATEGORY,

? ? ? ? FCP_CHANNEL_ID,

? ? ? ? FPIC_SHOW_TYPE,

? ? ? ? FTHUMBNAILS,

heap size831633848 ,800M之多,而當(dāng)前實例的buffer pool大小只有1191M哭廉。還要分配給各個block list脊僚。buffer pool不僅僅包含各個block list(free list,lru list,flush list...),還有adaptive hash index ,lock heap 等都是從buffer pool這種分配的遵绰。在事務(wù)執(zhí)行insert update,delete操作時,會先執(zhí)行下面函數(shù)檢查buffer pool用于block list的空間是否足夠(也就是檢查AHI,heap locksize是否占用過多的buffer pool空間)

/******************************************************************//**

Returns TRUE if less than 25 % of the buffer pool in any instance is

available. This can be used in heuristics to prevent huge transactions

eating up the whole buffer pool for their locks.?

@return TRUE if less than 25 % of buffer pool left */ ?

UNIV_INTERN

ibool

buf_LRU_buf_pool_running_out(void) ? 檢查各個buffer pool中可用的空間小于25%

/*==============================*/

{

? ? ? ? ulint ? i;

? ? ? ? ibool ? ret = FALSE;

? ? ? ? for (i = 0; i < srv_buf_pool_instances && !ret; i++) {

? ? ? ? ? ? ? ? buf_pool_t* ? ? buf_pool;

? ? ? ? ? ? ? ? buf_pool = buf_pool_from_array(i);

? ? ? ? ? ? ? ? buf_pool_mutex_enter(buf_pool);

? ? ? ? ? ? ? ? if (!recv_recovery_on

? ? ? ? ? ? ? ? ? ? && UT_LIST_GET_LEN(buf_pool->free) ? free list 長度

? ? ? ? ? ? ? ? ? ? ? ?+ UT_LIST_GET_LEN(buf_pool->LRU) ?lru list長度

? ? ? ? ? ? ? ? ? ? ? ?< buf_pool->curr_size / 4) { ?這里是判斷free list + lru list的長度是否小于buffer pool size 的 25%

? ? ? ? ? ? ? ? ? ? ? ? ret = TRUE;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? buf_pool_mutex_exit(buf_pool);

? ? ? ? }

? ? ? ? return(ret);

}

更新辽幌,插入記錄到索引中,或者插入記錄到一個已刪除的記錄位置都會調(diào)用該函數(shù)檢查buffer pool空間椿访,如果不足25%,則返回DB_LOCK_TABLE_FULL 乌企,在mysql層會檢測到該返回值,然后返回給客戶端對應(yīng)的異常信息成玫。也就是標(biāo)題的異常加酵。

同樣select在一些情況下也會調(diào)用該函數(shù),在查詢需要加鎖的情況下哭当,會調(diào)用該函數(shù)獲取buffer pool剩余空間:

Sets a lock on a record.

@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */

UNIV_INLINE

dberr_t

sel_set_rec_lock(

/*=============*/

? ? ? ? btr_pcur_t* ? ? ? ? ? ? pcur, ? /*!< in: cursor */

? ? ? ? const rec_t* ? ? ? ? ? ?rec, ? ?/*!< in: record */

? ? ? ? dict_index_t* ? ? ? ? ? index, ?/*!< in: index */

? ? ? ? const ulint* ? ? ? ? ? ?offsets,/*!< in: rec_get_offsets(rec, index) */

? ? ? ? ulint ? ? ? ? ? ? ? ? ? mode, ? /*!< in: lock mode */

? ? ? ? ulint ? ? ? ? ? ? ? ? ? type, ? /*!< in: LOCK_ORDINARY, LOCK_GAP, or

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? LOC_REC_NOT_GAP */

? ? ? ? que_thr_t* ? ? ? ? ? ? ?thr, ? ?/*!< in: query thread */

? ? ? ? mtr_t* ? ? ? ? ? ? ? ? ?mtr) ? ?/*!< in: mtr */

{

? ? ? ? trx_t* ? ? ? ? ? ? ? ? ?trx;

? ? ? ? dberr_t ? ? ? ? ? ? ? ? err = DB_SUCCESS;

? ? ? ? const buf_block_t* ? ? ?block;

? ? ? ? block = btr_pcur_get_block(pcur);

? ? ? ? trx = thr_get_trx(thr);

? ? ? ? if (UT_LIST_GET_LEN(trx->lock.trx_locks) > 10000) { ?如果該事務(wù)上鎖的數(shù)量比較多猪腕, 大于10000,則需要進(jìn)行判斷钦勘。

? ? ? ? ? ? ? ? if (buf_LRU_buf_pool_running_out()) { ?此時說明加鎖操作已經(jīng)消耗了很多buffer pool空間陋葡,剩余空間不足以支撐該事務(wù)繼續(xù)執(zhí)行下去。

? ? ? ? ? ? ? ? ? ? ? ? return(DB_LOCK_TABLE_FULL);

? ? ? ? ? ? ? ? }

? ? ? ? }

彻采。腐缤。朵栖。

}

在這個案例中,執(zhí)行的語句insert into ,xxxx select xxxx 操作柴梆,為例保持?jǐn)?shù)據(jù)的一致性陨溅,innodb會對select 語句中的記錄進(jìn)行x-lock操作,當(dāng)select的記錄比較多的時候绍在,加鎖所需的heap size越大门扇。從show engine innodb status可以看出:

9339476 lock struct(s), heap size 831633848, 49142856 row lock(s), undo log entries 12491866。

49142856 把行鎖偿渡,需要831633848 大小的內(nèi)存空間臼寄,當(dāng)然這還僅僅是語句執(zhí)行過程中的狀態(tài),實際上比這個還要多溜宽〖回到上面的問題,那么當(dāng)前事務(wù)需要多大的lock size适揉,而系統(tǒng)的lock table size又是多大呢留攒?

這里至少需要800M,而系統(tǒng)的lock table size 可以認(rèn)為是buffer pool的75%嫉嘀,對于可用的block list,需要大于buffer pool size的25%才能繼續(xù)執(zhí)行當(dāng)前事務(wù)炼邀。如果解決該問題,很簡單剪侮,調(diào)大innod buffer pool size即可拭宁,

這里從1191M調(diào)整到5191M,start slave sql_thread瓣俯,一段時間之后杰标,順利通過了。

還有哪些場景會導(dǎo)致該問題? delete一個大表彩匕,insert xxx select xxxx 記錄數(shù)較大腔剂,update 一個大表,select xxx for update推掸,select xxx in share mode 這些大事務(wù)都有可能導(dǎo)致該問題桶蝎,影響的記錄數(shù)越多,lock heap size約大谅畅。

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT count(*) FROM `test`.`T_XXX_ARTICLE_TMP` WHERE (`FID` >= 168666823 AND `FID` < 172310087) for update?;

+----------+

| count(*) |

+----------+

| ?3112193 |

+----------+

1 row in set (3 min 1.56 sec)

show engine innodb status:

---TRANSACTION 691281, ACTIVE 226 sec, process no 1249, OS thread id 140670129358592

746334 lock struct(s), heap size 66468280, 3858526 row lock(s)

MySQL thread id 5802, query id 367184 localhost root?

可以看出300W記錄登渣,需要heap size66468280 bytes = 63M。線上故障影響的記錄是5kw毡泻,需要800M heap size胜茧。其實也能看出,加鎖所需的內(nèi)存和記錄數(shù)有直接關(guān)系。

那么我們可以將大事務(wù)拆小呻顽,來降低每次事務(wù)加鎖需要的heap size大小雹顺。

這同時也說明,如果一個實例中有大表廊遍,那么buffer pool應(yīng)當(dāng)盡可能大一下嬉愧,buffer pool太小,則一旦遇上大事務(wù)就會導(dǎo)致該問題出現(xiàn)喉前。我們線上是單機跑了多個實例没酣,每個實例的buffer pool設(shè)置有限,

而該實例的數(shù)據(jù)大小達(dá)到了700G卵迂,出問題的大表有117G裕便,遇到大事務(wù)碰到該問題則是必然的。解決辦法:

1.調(diào)大innodb buffer pool size?

2.將大事務(wù)拆小

如果僅僅是查詢大表见咒,即使影響的記錄數(shù)很多偿衰,也是不會加鎖的,也就不存在上面的問題改览。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末下翎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恃疯,更是在濱河造成了極大的恐慌漏设,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件今妄,死亡現(xiàn)場離奇詭異,居然都是意外死亡鸳碧,警方通過查閱死者的電腦和手機盾鳞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞻离,“玉大人腾仅,你說我怎么就攤上這事√桌” “怎么了推励?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肉迫。 經(jīng)常有香客問我验辞,道長,這世上最難降的妖魔是什么喊衫? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任跌造,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘壳贪。我一直安慰自己陵珍,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布违施。 她就那樣靜靜地躺著互纯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪磕蒲。 梳的紋絲不亂的頭發(fā)上伟姐,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機與錄音亿卤,去河邊找鬼愤兵。 笑死,一個胖子當(dāng)著我的面吹牛排吴,可吹牛的內(nèi)容都是我干的秆乳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼钻哩,長吁一口氣:“原來是場噩夢啊……” “哼屹堰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起街氢,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤扯键,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后珊肃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荣刑,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年伦乔,在試婚紗的時候發(fā)現(xiàn)自己被綠了厉亏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡烈和,死狀恐怖爱只,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情招刹,我是刑警寧澤恬试,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站疯暑,受9級特大地震影響训柴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缰儿,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一畦粮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦宣赔、人聲如沸预麸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吏祸。三九已至,卻和暖如春钩蚊,著一層夾襖步出監(jiān)牢的瞬間贡翘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工砰逻, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留员舵,地道東北人竭业。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瞭郑。 傳聞我的和親對象是個殘疾皇子纹因,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,492評論 2 348

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