ClickHouse問題分析刪除系統表時卡住,長時間不恢復

      網友投稿 2900 2022-05-29

      問題現象

      使用drop table system.query_log sync時,發現客戶端一直卡住,長時間無法恢復。日志打印如下:

      ClickHouse問題分析:刪除系統表時卡住,長時間不恢復

      DatabaseCatalog: Waiting for table bd5888b9-a84c-41a8-bc7e-cefadf81cc43 to be finally dropped

      進一步試驗發現,如果我在卡住期間通過http連接后執行新的sql,卡住的命令就能正常執行了。但是,如果沒有新的sql執行,會一直卡住。

      問題分析

      1、先了解下drop table xxx sync的流程。

      # drop table system.query_log sync InterpreterDropQuery::execute executeToTable executeToTableImpl checkTableCanBeDropped StorageMergeTree::shutdown DatabaseAtomic::dropTable detachTableUnlocked tryRemoveSymlink enqueueDroppedTableCleanup if no delay tables_marked_dropped.push_front // 放在list的開頭 else tables_marked_dropped.push_back // 默認8min后刪除 tables_marked_dropped_ids.insert // 在set中存入需要刪除的表 (*drop_task)->schedule() // dropTableDataTask 在DatabaseCatalog::loadDatabases中初始化 if no delay // 有sync或者no delay或者database_atomic_wait_for_drop_and_detach_synchronously為true waitForTableToBeActuallyDroppedOrDetached // 等待table被實際刪除 waitTableFinallyDropped // wait_table_finally_dropped.wait // wait_table_finally_dropped 被通知,且 tables_marked_dropped_ids 中沒有此表 # drop table的后臺線程 DatabaseCatalog::dropTableDataTask // 只有不再使用且drop時間早于當前時間的table,才能被刪除 if table 可以被刪 tables_marked_dropped.erase dropTableFinally StorageMergeTree::drop // 刪數據 shutdown // 直接就return dropAllData // 真正開始刪除了 clearPartsFromFilesystem // 文件系統 disk->removeRecursive // 磁盤 remove // 刪元數據 removeUUIDMappingFinally // 刪uuid映射 tables_marked_dropped_ids.erase wait_table_finally_dropped.notify_all() // 通知不再wait if 還有表需要被刪 dropTableDataTask // 繼續刪表,否則不再調度

      從流程上可以知道:

      (1)如果不加sync(即no delay),則默認是至少8min后才會真正刪除數據。而在添加了sync后,則將需要刪除的表放在list的開頭,也不用等待8min。

      (2)drop的主流程,也不會真正刪除表,而是存入一個tables_marked_dropped中,由后臺線程dropTableDataTask來操刀。如果設置了sync,drop的主流程,會等待后臺線程的通知,然后才會返回客戶端刪除成功。

      (3)真正刪除時,需要保證該table沒有流程在使用,通過查看該table的shared_ptr是否是unique來確定。

      (4)每次只會刪除一張表。如果還有待刪除的表,則會繼續,不需再等待。如果沒有表需要刪除,則不在觸發此任務。

      (5)每次執行完drop table后,其實都會觸發query_log的記錄,進而重建該表,因此,刪除query_log是沒有意義的。

      2、再了解下query_log的流程

      # query_log的機制 # query_log建立過程 Server::main global_context->initializeSystemLogs SystemLogs::SystemLogs // 初始化各個system log,包括query log createSystemLog // 根據config中的配置生成 SystemLog::SystemLog logs.emplace_back log->startup() // 啟動log的后臺線程 savingThreadFunction # query log的添加 SystemLog::add // 一般用法,context.getQueryLog; query_log->add queue.push_back # query log的監控線程 SystemLog::savingThreadFunction flush_event.wait_for // 等待超時,一定時間刷新一次 flushImpl // queue中的log寫到query_log表 prepareTable // 有表,則要比較列信息是否有變,變化了則需要重建,舊表重命名為query_log_N。沒有表,則新建 write // 數據寫入

      這里比較特別的地方是:

      (1)query_log在有log記錄的時候,如果發現沒有表的話,會走創建表的流程。如果已經有表了,則會比較列的結構是否一致,不一致的話,需要重建表,并將舊表重命名。

      (2)如果在config.xml中修改表級的TTL,即使重啟server,query_log也是不會變化的,因為已經存在該表,且表的列信息是一樣的。如要讓它生效,則需要刪除query_log(會自動重建),或者采用ALTER TABLE的方式。這也是為什么第一次在config.xml中配置query_log時可以生效,而后續修改或者配置時又無法生效的原因。

      3、問題分析

      結合刪除表時會卡住的時候報錯以及正常流程時應該要有的日志(Removing metadata {} of dropped table),可知,是在dropTableDataTask中判斷table是否沒有地方在使用時出現了問題。

      auto it = std::find_if(tables_marked_dropped.begin(), tables_marked_dropped.end(), [&](const auto & elem) { bool not_in_use = !elem.table || elem.table.unique(); bool old_enough = elem.drop_time <= current_time; min_drop_time = std::min(min_drop_time, elem.drop_time); tables_in_use_count += !not_in_use; return not_in_use && old_enough; });

      即elem.table.unique()不滿足。

      然后,梳理整個流程和現象(在卡住期間通過http連接后執行新的sql,卡住的命令就能正常執行了)可以推理出,應該去看添加新log的流程。

      template void SystemLog::prepareTable() { String description = table_id.getNameForLogs(); table = DatabaseCatalog::instance().tryGetTable(table_id, context); if (table) { ... } if (!table) { /// Create the table. ... table = DatabaseCatalog::instance().getTable(table_id, context); } }

      在prepareTable中,得到了table的副本,而且一直沒有釋放,elem.table.unique()就一直無法滿足。只有在新添加日志的時候,table變量被覆蓋,原來的query_log的智能指針就被釋放了,從而卡住的流程可以繼續。

      ClickHouse

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:有興趣學學MAXScript-1
      下一篇:UML類圖常用用法
      相關文章
      伊人久久大香线蕉亚洲| 国产乱辈通伦影片在线播放亚洲| 国产精品亚洲а∨无码播放| 亚洲无码高清在线观看| 亚洲A∨精品一区二区三区| 亚洲爆乳精品无码一区二区| 亚洲国产成人久久精品软件 | 亚洲乱码一二三四区乱码| 亚洲成a人片77777群色| 亚洲国产精品成人久久久| 亚洲性69影院在线观看| 亚洲天堂电影在线观看| 亚洲一级免费视频| 国产v亚洲v天堂a无| 日韩亚洲国产高清免费视频| 亚洲成人激情小说| 亚洲人成色777777老人头| 亚洲另类无码专区首页| 国产精品久久久久久亚洲影视| jizzjizz亚洲日本少妇| 亚洲国产免费综合| 国产成人精品日本亚洲专区61| 亚洲午夜久久久影院| 亚洲高清国产AV拍精品青青草原| 亚洲av永久无码制服河南实里| 亚洲AV福利天堂一区二区三| 亚洲精品在线播放视频| 亚洲欧洲国产综合| 亚洲色一区二区三区四区| 老子影院午夜伦不卡亚洲| 亚洲精品一级无码中文字幕| 色噜噜亚洲精品中文字幕| 亚洲va久久久噜噜噜久久狠狠| 精品亚洲麻豆1区2区3区| 亚洲国产精品成人精品软件 | 自拍偷自拍亚洲精品被多人伦好爽| 亚洲国产日韩在线视频| 亚洲日韩图片专区第1页| 亚洲伊人久久大香线焦| 亚洲人成色777777精品| 亚洲А∨精品天堂在线|