精品国产乱码久久久久久_精品人妻人人做人人爽夜夜爽_再深点灬舒服灬太大了少妇_偷偷色噜狠狠狠狠的777米奇





技術人生系列——MySQL:8.0中關于file_system的重大改進和8.0.23存在的問題

日期:2022-07-25


最(zui)近一(yi)個和file_system有(you)關的(de)(de)問題(ti),因此將這部分(fen)數據(ju)結構和重要的(de)(de)函數簡單看了一(yi)下,好在(zai)數據(ju)結構不(bu)(bu)多,成員(yuan)變量也(ye)不(bu)(bu)多。但是這部分(fen)的(de)(de)知(zhi)識和IO子(zi)(zi)系(xi)統(tong)聯系(xi)太緊密了,因為IO子(zi)(zi)系(xi)統(tong)不(bu)(bu)熟,所以(yi)難免有(you)錯誤。但是也(ye)為學習IO子(zi)(zi)系(xi)統(tong)做了一(yi)層鋪(pu)墊。并且不(bu)(bu)管錯誤與否必須(xu)要記(ji)錄一(yi)下否則很容(rong)易忘(wang)記(ji),現記(ji)錄如下(包含代(dai)碼,文章(zhang)稍(shao)顯(xian)混亂),代(dai)碼來自(zi)8.0.23。

僅供參(can)考。


一、前言

在(zai)(zai)我們(men)數據(ju)庫啟動(dong)的(de)時候,實際上很多表都(dou)是(shi)沒(mei)有(you)打開(kai)的(de),當然除了(le)一些(xie)redo/undo等系統空(kong)間會(hui)(hui)常駐(zhu)打開(kai),其(qi)(qi)他的(de)用戶的(de)innodb表示沒(mei)有(you)打開(kai),當遇到(dao)(dao)真(zhen)正(zheng)(zheng)的(de)IO操作后(hou)才會(hui)(hui)打開(kai)文(wen)(wen)件,這些(xie)文(wen)(wen)件會(hui)(hui)存在(zai)(zai)于file_system中(zhong)(zhong),主(zhu)要包含的(de)就是(shi)fil_space_t結(jie)構(gou),一個(ge)fil_space_t對(dui)于單表或(huo)者(zhe)分(fen)(fen)(fen)區表的(de)一個(ge)分(fen)(fen)(fen)區來(lai)(lai)講(jiang)就對(dui)應(ying)一個(ge)fil_node_t,但(dan)是(shi)對(dui)于redo或(huo)者(zhe)undo這些(xie)來(lai)(lai)講(jiang)一個(ge)fil_space_t對(dui)應(ying)了(le)多個(ge)file_node_t,因(yin)為有(you)多個(ge)相關文(wen)(wen)件,真(zhen)正(zheng)(zheng)的(de)io handler存儲在(zai)(zai)fil_node_t上。在(zai)(zai)5.7中(zhong)(zhong)打開(kai)的(de)文(wen)(wen)件都(dou)整體存在(zai)(zai)于一個(ge)file_system下(xia),但(dan)是(shi)最近遇到(dao)(dao)了(le)一個(ge)問題(ti),稍微(wei)看了(le)下(xia)8.0發現做了(le)拆分(fen)(fen)(fen),將一個(ge)file_system查分(fen)(fen)(fen)為 69個(ge)(8.0.19是(shi)65個(ge))這個(ge)是(shi)個(ge)硬編碼。這樣(yang)如(ru)果我們(men)需要打開(kai)文(wen)(wen)件或(huo)者(zhe)關閉文(wen)(wen)件那么拆分(fen)(fen)(fen)后(hou)鎖的(de)代價就更小(xiao)了(le),其(qi)(qi)中(zhong)(zhong)每一個(ge)拆分(fen)(fen)(fen)出(chu)來(lai)(lai)的(de)結(jie)構(gou)叫做shard(內部結(jie)構(gou)叫做Fil_shard)。

二、總體示意圖

注(zhu)意這(zhe)里我們只(zhi)討論一個fil_space_t對(dui)應一個fil_node_t的情況,也(ye)就是普通表(biao)(分區(qu)表(biao)的分區(qu)),這(zhe)往往也(ye)是和用(yong)戶關系(xi)較(jiao)大的。

三、file_system(Fil_system)的重點變量

圖中包含(han)另(ling)一些(xie)重點的數據結構(gou),其中 file_system中包含(han):

  • m_shards:這是一個vecoter數組,包含了69個shard。

  • m_max_n_open:這個是我們的參數Innodb_open_files設置的值。

  • m_max_assigned_id:是我們當前分配的最大的space_id。

四、shard的重點變量

  • m_id:當前shard的序號,從0開始

  • m_spaces:一個std map結構,在數據庫初始化的時候就建立好了,其主要是space_id和fil_space_t做的一個map結構

  • m_names:一個std map結構,在數據庫初始化的時候就建立好了,其主要是space_name和fil_space_t做的一個map結構

m_spaces和m_names變量的初始(shi)化可以(yi)查(cha)看函數(shu)Fil_shard::space_add,如下:

void Fil_shard::space_add(fil_space_t *space) {  ut_ad(mutex_owned());  {    auto it = m_spaces.insert(Spaces::value_type(space->id, space));    ut_a(it.second);  }  {    auto name = space->name;    auto it = m_names.insert(Names::value_type(name, space));    ut_a(it.second);  }}

我們通(tong)常在進行物理(li)IO的(de)時(shi)候需要打(da)開(kai)文件,這個時(shi)候拿(na)到的(de)一般為page的(de)space_id,這樣通(tong)過(guo)Fil_shard::get_space_by_id就快速拿(na)了fil_space_t的(de)結(jie)構,而不用去遍歷鏈(lian)表。

但是(shi)(shi)(shi)需要注意的(de)(de)(de)一(yi)點是(shi)(shi)(shi),我們(men)首先還需要判定(ding)是(shi)(shi)(shi)的(de)(de)(de)這(zhe)個space_id到(dao)(dao)(dao)底到(dao)(dao)(dao)哪個shard上建立或者到(dao)(dao)(dao)哪個shard上查(cha)找(zhao),是(shi)(shi)(shi)需要定(ding)位到(dao)(dao)(dao)相關的(de)(de)(de)shard上的(de)(de)(de),這(zhe)個是(shi)(shi)(shi)通過space_id取余(yu)來做到(dao)(dao)(dao)的(de)(de)(de),函(han)數(shu) Fil_system::shard_by_id(FIL_system 就是(shi)(shi)(shi)我們(men)的(de)(de)(de)file_system的(de)(de)(de)數(shu)據結(jie)構)函(han)數(shu)完(wan)成這(zhe)個功能(neng),計(ji)算取余(yu)如下:

  Fil_shard *shard_by_id(space_id_t space_id) const      MY_ATTRIBUTE((warn_unused_result)) {#ifndef UNIV_HOTBACKUP    if (space_id == dict_sys_t::s_log_space_first_id) {      return m_shards[REDO_SHARD];    } else if (fsp_is_undo_tablespace(space_id)) {      const size_t limit = space_id % UNDO_SHARDS;      return m_shards[UNDO_SHARDS_START + limit];    }    ut_ad(m_shards.size() == MAX_SHARDS);     return m_shards[space_id % UNDO_SHARDS_START]; //取余,將各個space分布到不同的shard上#else  /* !UNIV_HOTBACKUP */    ut_ad(m_shards.size() == 1);    return m_shards[0];#endif /* !UNIV_HOTBACKUP */  }

因為我們的(de)undo,redo會獨占末(mo)尾的(de)幾個shard,因此這里用了宏來減去(qu)了這部分然后取余,相關宏定義如下。

/** Maximum number of shards supported. */static const size_t MAX_SHARDS = 69; //69個shard/** The redo log is in its own shard. */static const size_t REDO_SHARD = MAX_SHARDS - 1; //末尾第1個為redo的shard/** Number of undo shards to reserve. */static const size_t UNDO_SHARDS = 4;//倒數第2到第5為undo的shard/** The UNDO logs have their own shards (4). */static const size_t UNDO_SHARDS_START = REDO_SHARD - UNDO_SHARDS;#else  /* !UNIV_HOTBACKUP */
  • m_LRU:這個玩意是一個最重要的數據結構了,如果一個文件剛剛打開或者io complete讀操作就會將其以頭插法加入到這個鏈表,這就形成了一個LRU鏈表,如果超過參數Innodb_open_files的設置就會在這里面進行尾部淘汰。打開文件函數如下:

Fil_shard::prepare_file_for_io 調入為物理IO準備好文件:void Fil_shard::file_opened(fil_node_t *file) {   ut_ad(m_id == REDO_SHARD || mutex_owned());  if (Fil_system::space_belongs_in_LRU(file->space)) {    /* Put the file to the LRU list */    UT_LIST_ADD_FIRST(m_LRU, file); //頭插法  }  ++s_n_open;  file->is_open = true;  fil_n_file_opened = s_n_open;}

IO COMPLETE如下:

void Fil_shard::complete_io(fil_node_t *file, const IORequest &type) {  ut_ad(m_id == REDO_SHARD || mutex_owned());  ut_a(file->n_pending > 0);  --file->n_pending;  ut_ad(type.validate());  if (type.is_write()) { //如果是寫操作    ut_ad(!srv_read_only_mode || fsp_is_system_temporary(file->space->id));    write_completed(file); //需要加入flush  而不是 LRU 鏈表  }  if (file->n_pending == 0 && Fil_system::space_belongs_in_LRU(file->space)) { //是否為 tablespace    /* The file must be put back to the LRU list */    UT_LIST_ADD_FIRST(m_LRU, file); //如果是讀操作直接加入 LRU鏈表  }}

當(dang)(dang)調用(yong)Fil_shard::close_file關(guan)閉文件時(shi)(shi)候會(hui)從LRU的末尾去掉,見后文分析。這個結構就是我們最(zui)為熟悉的file system(下shard)的LRU鏈表(biao),當(dang)(dang)然如果數據庫當(dang)(dang)時(shi)(shi)打開了很多文件超過了參(can)數Innodb_open_files的設置 ,并且做了大量的IO操作(zuo),那么這個LRU鏈表(biao)可能(neng)找不(bu)到相應的能(neng)夠關(guan)閉的文件。

  • m_unflushed_spaces:如其名,主要是進行寫操作的IO可能涉及到需要進行flush data file,因此都放在這個鏈表里面。加入調用也是Fil_shard::write_completed ,但是需要判定是否文件打開用的SRV_UNIX_O_DIRECT_NO_FSYNC,當然一般都不是的,如下:

Fil_shard::write_completed     ->add_to_unflushed_list(file->space); //寫入完成,還沒有flush          UT_LIST_ADD_FIRST(m_unflushed_spaces, space);//頭插法

去(qu)掉時機:

Fil_shard::space_flush   ->remove_from_unflushed_list(space)      UT_LIST_REMOVE(m_unflushed_spaces, space);//尾部去除

看起來就是space進(jin)行(xing)flush刷盤過后。那(nei)么需要注意的(de)(de)打開的(de)(de)文件并不(bu)一定在(zai)m_unflushed_spaces或者(zhe)m_LRU,如果(guo)正(zheng)在(zai)進(jin)行(xing)讀IO可能兩個(ge)鏈表中都沒有這個(ge)打開的(de)(de)文件,但是問題不(bu)大,因為本來就不(bu)能淘汰(tai)。

  • static原子變量s_n_open:顯然這個屬性不是某個shard特有的,是全部shard一起持有的,那么它代表的實際上就是當前打開的innodb文件總數,使用原子變量避免加鎖,這樣在比較是否超過最大打開數的時候就可以通過file_system的m_max_n_open(也就是參數Innodb_open_files)和其比較即可。

  • static原子變量s_open_slot:顯然這個屬性不是某個shard特有的,是全部shard一起持有的,它用處是保護(The number of open file descriptors is a shard resource),使用一個原子變量的比較/交換操作compare_exchange_weak并且附加while循環,來保證共享資源file descriptors ,這是無鎖化編程一種方式。

四、關于文件的關閉

如果文件(jian)(jian)沒有(you)保存在(zai)file_system中(zhong)(zhong)(zhong),進(jin)行物理(li)IO的(de)時候需(xu)(xu)要(yao)打開它(ta)(Fil_shard::do_io),也(ye)(ye)就是(shi)(shi)(shi)Fil_shard::prepare_file_for_io調(diao)用(yong)準備打開文件(jian)(jian)之(zhi)前,需(xu)(xu)要(yao)當前打開的(de)innodb文件(jian)(jian)數量是(shi)(shi)(shi)否大(da)于(yu)(yu)了(le)參(can)數Innodb_open_files的(de)設(she)置,如果大(da)于(yu)(yu)了(le)那么(me)就需(xu)(xu)要(yao)做淘汰文件(jian)(jian)出來,代碼在(zai)Fil_shard::mutex_acquire_and_get_space中(zhong)(zhong)(zhong),當然Fil_shard::mutex_acquire_and_get_space的(de)調(diao)用(yong)在(zai)Fil_shard::prepare_file_for_io調(diao)用(yong)之(zhi)前,且都(dou)在(zai)Fil_shard::do_io下(xia)面。這里有(you)一(yi)個(ge)重點,就是(shi)(shi)(shi)參(can)數Innodb_open_files設(she)置是(shi)(shi)(shi)總的(de)大(da)小,因(yin)此不管從哪(na)個(ge)shard中(zhong)(zhong)(zhong)淘汰一(yi)個(ge),那么(me)這個(ge)文件(jian)(jian)就能打開,而不是(shi)(shi)(shi)一(yi)定(ding)要(yao)在(zai)本space所在(zai)的(de)shard中(zhong)(zhong)(zhong)關(guan)閉(bi),比如我(wo)們在(zai)shard 4中(zhong)(zhong)(zhong)關(guan)閉(bi)了(le)一(yi)個(ge)文件(jian)(jian),我(wo)需(xu)(xu)要(yao)打開的(de)文件(jian)(jian)映(ying)射到了(le)shard 10,那么(me)打開文件(jian)(jian)總是(shi)(shi)(shi)還是(shi)(shi)(shi)相等的(de),沒有(you)問題。這也(ye)(ye)是(shi)(shi)(shi)我(wo)開始疑惑的(de)地方。來看(kan)看(kan)主要(yao)流程,也(ye)(ye)是(shi)(shi)(shi)很簡(jian)單:

Fil_shard::mutex_acquire_and_get_space  ->Fil_system::close_file_in_all_LRU(循環每個shard)    ->Fil_shard::close_files_in_LRU(判斷LRU上是否有可以close文件)      ->Fil_shard::close_file(關閉文件)Fil_shard::mutex_acquire_and_get_space //mutex只是本shard的mutex本函數有1個嵌套循環for (size_t i = 0; i < 3; ++i){ //嘗試清理3次,每次都必須清理出一個文件(壓力過大剛清理又滿了?) while (fil_system->m_max_n_open <= s_n_open && //如果s_n_open static變量大于了fil_system設置m_max_n_open(也就是參數Innodb_open_files設置的大小)           !fil_system->close_file_in_all_LRU(i > 1)) {  //根據LRU 關閉 打開的文件如果清理嘗試來到第2次開始輸出note級別的日志,如果清理失敗可能繼續      if (ut_time_monotonic() - start_time >= PRINT_INTERVAL_SECS) { //如果本次清理時間大于了PRINT_INTERVAL_SECS 設置就報警        start_time = ut_time_monotonic();        ib::warn(ER_IB_MSG_279) << "Trying to close a file for "                                << start_time - begin_time << " seconds"                                << ". Configuration only allows for "                                << fil_system->m_max_n_open << " open files.";      }    }Fil_system::close_file_in_all_LRU函數bool Fil_system::close_file_in_all_LRU(bool print_info) {  for (auto shard : m_shards) {//m_shards 為一個 數組循環每個shard    shard->mutex_acquire();    if (print_info) {      ib::info(ER_IB_MSG_277, shard->id(),               ulonglong{UT_LIST_GET_LEN(shard->m_LRU)}); //如果是第2次嘗試會打印日志    }    bool success = shard->close_files_in_LRU(print_info);    shard->mutex_release();    if (success) { //如果成功關閉了一個文件success為true      return true; //返回成功    }  }  return false;//返回失敗}Fil_shard::close_files_in_LRU函數bool Fil_shard::close_files_in_LRU(bool print_info) {  for (auto file = UT_LIST_GET_LAST(m_LRU); file != nullptr;       file = UT_LIST_GET_PREV(LRU, file)) { //循環LRU鏈表,如果鏈表沒有元素即可返回    if (file->modification_counter == file->flush_counter &&        file->n_pending_flushes == 0 && file->in_use == 0) {//繼續額外的判斷,尚不清楚為什么。      close_file(file, true); //關閉1個文件,并且會從LRU中取下來      return true; //關閉一個則成功    }    if (!print_info) {//如果不需要打印日志,也就是是第1次嘗試清理,不需要打印日志      continue;    }...//關閉失敗的note日志省略  return false;//如果本shard沒有可以關閉的則返回flase

這里的(de)(de)流(liu)程如果出現文件較多,并且同(tong)時打開(kai)進(jin)行IO文件較多(顯著的(de)(de)就(jiu)是包含大量(liang)分區的(de)(de)分區表)的(de)(de)情(qing)況超過了參數Innodb_open_files的(de)(de)大小情(qing)況,可能出現日志:

圖片

也就(jiu)是(shi)(shi)ER_IB_MSG_277的(de)(de)(de)(de)note日志(zhi)輸(shu)出,第一個(ge)為(wei)(wei)shard的(de)(de)(de)(de)id,第二(er)個(ge)0代(dai)表(biao)是(shi)(shi)LRU元素的(de)(de)(de)(de)個(ge)數(shu)(shu),但(dan)(dan)是(shi)(shi)從上(shang)面的(de)(de)(de)(de)邏輯來(lai)(lai)看,雖然循(xun)環次數(shu)(shu)比較多,但(dan)(dan)是(shi)(shi)每次循(xun)環的(de)(de)(de)(de)元素很(hen)少或(huo)者(zhe)為(wei)(wei)0個(ge)元素,因此代(dai)價(jia)也就(jiu)不(bu)那(nei)么(me)高了。另外從這個(ge)算法來(lai)(lai)看因為(wei)(wei)是(shi)(shi)從頭遍歷shard 1-69 個(ge)shard,如果要淘汰打開的(de)(de)(de)(de)文件,理論(lun)上(shang)前面的(de)(de)(de)(de)shard相關(guan)的(de)(de)(de)(de)fil_space_t(可簡(jian)單(dan)理解為(wei)(wei)表(biao)或(huo)者(zhe)分區)更容(rong)易淘汰和關(guan)閉掉。此處代(dai)碼來(lai)(lai)自8.0.23,不(bu)知道過后(hou)是(shi)(shi)否會改(gai)進(隨機算法取shard是(shi)(shi)不(bu)是(shi)(shi)更好?),測試情況下(xia)我設置參數(shu)(shu)Innodb_open_files為(wei)(wei)400,建(jian)立了2000個(ge)表(biao),全部打開后(hou),發現(xian)前面很(hen)多shard的(de)(de)(de)(de)m_LRU為(wei)(wei)空如下(xia):

(gdb) p ((Fil_shard*)(0x7fffe0044c90))->m_LRU$15 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e0f90))->m_LRU$16 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02ea480))->m_LRU$17 = {count = 17, start = 0x7fffe3267240, end = 0x7fffe2a9f1f0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e19d0))->m_LRU$18 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e1f30))->m_LRU$19 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e49c0))->m_LRU$20 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e6ec0))->m_LRU$21 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e7170))->m_LRU$22 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e5480))->m_LRU$23 = {count = 0, start = 0x0, end = 0x0, node = &fil_node_t::LRU, init = 51966}//前面好多shard的m_LRU長度都是0//到這里才開m_LRU有值(gdb) p ((Fil_shard*)(0x7fffe02e7ee0))->m_LRU$24 = {count = 1, start = 0x7fffe3279530, end = 0x7fffe3279530, node = &fil_node_t::LRU, init = 51966}$25 = {count = 18, start = 0x7fffe327b290, end = 0x7fffe2a9c670, node = &fil_node_t::LRU, init = 51966}(gdb) p ((Fil_shard*)(0x7fffe02e8190))->m_LRU$26 = {count = 17, start = 0x7fffe3279ae0, end = 0x7fffe30974d0, node = &fil_node_t::LRU, init = 51966}

我大概數了一(yi)下,就(jiu)是(shi)(shi)后面20來(lai)個(ge)(ge)shard才有(you)(you)值,差不多(duo)一(yi)個(ge)(ge)有(you)(you)17 18個(ge)(ge)表,這樣算起(qi)來(lai)差不多(duo)是(shi)(shi)參數Innodb_open_files設(she)置(zhi)的(de)400大小。這樣分布(bu)不均勻(yun)直接導致(zhi)的(de)問(wen)題(ti)就(jiu)是(shi)(shi)拆分效果大打折扣(kou)。

隨后查(cha)看(kan)8.0.28的代碼(ma)似乎進行更改,具體的提交就(jiu)不去查(cha)了(le),看(kan)來官(guan)方是發(fa)現了(le)這個(ge)問題:

bool Fil_system::close_file_in_all_LRU() {  const auto n_shards = m_shards.size();  const auto index = m_next_shard_to_close_from_LRU++;//原子變量  for (size_t i = 0; i < n_shards; ++i) {    auto shard = m_shards[(index + i) % n_shards]; //跳躍性查找,不在數循序的    if (shard->id() == REDO_SHARD) {      /* Redo shard don't ever have any spaces on LRU. It is not guarded by a      mutex so we can't continue the execution of the for block. */      continue;    }    shard->mutex_acquire();    bool success = shard->close_files_in_LRU();    shard->mutex_release();    if (success) {      return true;    }  }  return false;}

五、最后

最(zui)后我們來(lai)看(kan)看(kan)如(ru)(ru)果debug這(zhe)些元素其(qi)實很(hen)簡(jian)單,因為file_system是一個(ge)全局變量,直接就(jiu)能(neng)拿(na)到比如(ru)(ru),我想查看(kan)這(zhe)69個(ge)shard如(ru)(ru)下:

(gdb) p fil_system->m_shards$2 = std::vector of length 69, capacity 128 = {0x7fffe0044c90, 0x7fffe02e0f90, 0x7fffe02e1120, 0x7fffe02e13d0, 0x7fffe02e1680, 0x7fffe02e19d0, 0x7fffe02e1c80, 0x7fffe02e1f30,   0x7fffe02e21e0, 0x7fffe02e25b0, 0x7fffe02e2860, 0x7fffe02e2b10, 0x7fffe02e2dc0, 0x7fffe02e3070, 0x7fffe02e3320, 0x7fffe02e35d0, 0x7fffe02e3880, 0x7fffe02e3cd0, 0x7fffe02e3f00,   0x7fffe02e41b0, 0x7fffe02e4460, 0x7fffe02e4710, 0x7fffe02e49c0, 0x7fffe02e4c70, 0x7fffe02e4f20, 0x7fffe02e51d0, 0x7fffe02e5480, 0x7fffe02e5730, 0x7fffe02e59e0, 0x7fffe02e5c90,   0x7fffe02e5f40, 0x7fffe02e61f0, 0x7fffe02e64a0, 0x7fffe02e3b30, 0x7fffe02e6c10, 0x7fffe02e6ec0, 0x7fffe02e7170, 0x7fffe02e7420, 0x7fffe02e76d0, 0x7fffe02e7980, 0x7fffe02e7c30,   0x7fffe02e7ee0, 0x7fffe02e8190, 0x7fffe02e8440, 0x7fffe02e86f0, 0x7fffe02e89a0, 0x7fffe02e8c50, 0x7fffe02e8f00, 0x7fffe02e91b0, 0x7fffe02e9460, 0x7fffe02e9710, 0x7fffe02e99c0,   0x7fffe02e9c70, 0x7fffe02e9f20, 0x7fffe02ea1d0, 0x7fffe02ea480, 0x7fffe02ea730, 0x7fffe02ea9e0, 0x7fffe02eac90, 0x7fffe02eaf40, 0x7fffe02eb1f0, 0x7fffe02eb4a0, 0x7fffe02eb750,   0x7fffe02eba00, 0x7fffe02ebcb0, 0x7fffe02e6750, 0x7fffe02ec700, 0x7fffe02ec910, 0x7fffe02ecbc0}(gdb)

如果我想看(kan)每個shard里面包含哪些表的fil_space_t如下即可:

(gdb) p ((Fil_shard*)(0x7fffe0044c90))->m_names$6 = std::unordered_map with 18 elements = {[0x7fffe32513c0 "t10/t883"] = 0x7fffe32511e0, [0x7fffe323a2d0 "t10/t819"] = 0x7fffe323a0f0, [0x7fffe3223630 "t10/t755"] = 0x7fffe3223450,   [0x7fffe320cc60 "t10/t691"] = 0x7fffe320ca80, [0x7fffe31c51b0 "t10/t499"] = 0x7fffe31c4fd0, [0x7fffe309e2c0 "testpri/t1"] = 0x7fffe309e0e0, [0x7fffe31954b0 "t10/t371"] = 0x7fffe31952d0,   [0x7fffe308c620 "t10/ERPDB_TEST"] = 0x7fffe308c440, [0x7fffe31dcca0 "t10/t563"] = 0x7fffe31dcac0, [0x7fffe3104ee0 "t10/t115"] = 0x7fffe3121620,   [0x7fffe043eb40 "innodb_system"] = 0x7fffe0437280, [0x7fffe31511c0 "t10/t243"] = 0x7fffe3150fe0, [0x7fffe317e750 "t10/t307"] = 0x7fffe317e570,   [0x7fffe326a450 "t10/t947"] = 0x7fffe326a270, [0x7fffe31f4c10 "t10/t627"] = 0x7fffe31f4a30, [0x7fffe2b7bee0 "t10/t51"] = 0x7fffe310b9e0, [0x7fffe3139a90 "t10/t179"] = 0x7fffe31398b0,   [0x7fffe31adc40 "t10/t435"] = 0x7fffe31ada60}(這里就是names和fil_space_t的map映射,當然fil_space_t是指針類型)(gdb) p ((Fil_shard*)(0x7fffe0044c90))->m_id$7 = 0(這里是share id 我取的第1個元素 1 id就是0)

也可以查看shard的(de)其他元素,當然可以繼續debug各個(ge)fil_space_t,fil_node_t 數(shu)據結(jie)構的(de)數(shu)據。

另(ling)外除了(le)8.0.28代碼看(kan)到的問題(ti)修復,還(huan)有(you)2個和這部分相關(guan)的BUG供參考如下(xia),當然這幾個BUG沒(mei)仔細看(kan),在新版(ban)(8.0.27)都修復了(le):

  • InnoDB: “Too many open files” errors were encountered when creating a large number of tables. (Bug #32634620)

  • InnoDB: An excessive number of notes were written to the error log when the innodb_open_files limit was temporarily exceeded. (Bug #33343690)

其(qi)實說了這么多和(he)貌似和(he)我們運維相關的只(zhi)有1個variable和(he)1個status如(ru)下,略顯尷尬:

  • variable Innodb_open_files:innodb能夠打開的最大文件,自適應算法可參考官方文檔,體現在Fil_system::m_max_n_open上。

  • status Innodb_num_open_files:顯然這個就是Innodb當前打開的文件數量,和static原子變量shard::s_n_open是一個值( fil_n_file_opened = s_n_open;)。

 
 
 

   文章來源于MySQL學習,作者高鵬(八怪)

《深(shen)入(ru)理解MySQL主從原(yuan)理》作者

中亦科技數據庫團(tuan)隊MySQL二線工程師(shi) 

十余(yu)年數據(ju)庫(ku)運維經(jing)驗\擅長故(gu)障診(zhen)斷,性(xing)能調(diao)優


鍛造凝煉IT服務 助推用戶事業發展
地址:北京市西城區百萬莊大街11號糧科大廈3層
電話:(010)58523737
傳真:(010)58523739