MySQL8 show processlist 最佳化

aoerqileng發表於2022-12-21

he new SHOW PROCESSLIST executes an internal query of a new table,  peformance_schema.processlist , rather than iterate across threads in the thread manager. 

8.0之前版本的show processlist 資料是在thread manager 那裡獲取,會獲取一個全域性的mutex,8.0後版本的使用新的方式直接使用非阻塞讀取表。


下面看下8.0之前的show processlist獲取mutex的方法,在mysql_execute_command中有處理該語句的分支

case SQLCOM_SHOW_PROCESSLIST:
if (!thd->security_context()->priv_user().str[0] &&
check_global_access(thd,PROCESS_ACL))
break;
mysqld_list_processes(
thd,
(thd->security_context()->check_access(PROCESS_ACL) ?
NullS :
thd->security_context()->priv_user().str),
lex->verbose);
break;


在獲取全部thread的時候,可以看見加了幾個mutex,

LOCK_thd_list 在複製執行緒列表的時候使用
void Global_THD_manager::do_for_all_thd_copy(Do_THD_Impl *func)
{
Do_THD doit(func);
mysql_mutex_lock(&LOCK_thd_remove);
mysql_mutex_lock(&LOCK_thd_list);
  /* Take copy of global_thread_list. */
THD_array thd_list_copy(thd_list);
  /*
    Allow inserts to global_thread_list. Newly added thd
    will not be accounted for when executing func.
  */
mysql_mutex_unlock(&LOCK_thd_list);
  /* Execute func for all existing threads. */
std::for_each(thd_list_copy.begin(), thd_list_copy.end(), doit);
DEBUG_SYNC_C("inside_do_for_all_thd_copy");
mysql_mutex_unlock(&LOCK_thd_remove);
}


對應的堆疊如下:

mysqld!Global_THD_manager::do_for_all_thd_copy(Do_THD_Impl*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/mysqld_thd_manager.cc:257)
mysqld!mysqld_list_processes(THD*, char const*, bool) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_show.cc:2390)
mysqld!mysql_execute_command(THD*, bool) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:3643)
mysqld!mysql_parse(THD*, Parser_state*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:5584)
mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1491)
mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/sql_parse.cc:1032)
mysqld!::handle_connection(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/sql/conn_handler/connection_handler_per_thread.cc:313)
mysqld!::pfs_spawn_thread(void *) (/Users/xiaoyu.bai/Downloads/mysql-5.7.29/storage/perfschema/pfs.cc:2197)
libsystem_pthread.dylib!_pthread_start (Unknown Source:0)
libsystem_pthread.dylib!thread_start (Unknown Source:0)


LOCK_thd_list 這個mutex 保護執行緒id集合,所有的執行緒操作都需要這個mutex,所以你執行show processlist會影響到執行緒的建立,消除。
導致系統qps 下降,應用連線緩慢。
void Global_THD_manager::add_thd(THD *thd)
{
DBUG_PRINT("info", ("Global_THD_manager::add_thd %p", thd));
  // Should have an assigned ID before adding to the list.
DBUG_ASSERT(thd->thread_id() != reserved_thread_id);
mysql_mutex_lock(&LOCK_thd_list);
  // Technically it is not supported to compare pointers, but it works.
std::pair<THD_array::iterator, bool> insert_result=
thd_list.insert_unique(thd);
if (insert_result.second)
{
++global_thd_count;
}
  // Adding the same THD twice is an error.
DBUG_ASSERT(insert_result.second);
mysql_mutex_unlock(&LOCK_thd_list);
}

8.0透過直接查詢表的方式避免這個問題,但是預設是沒有開啟的,需要設定performance_schema_show_processlist 這個變數開啟,不知道為什麼預設沒有開。


btw,8.0解決了太多的問題,也引發了太多問題。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25719946/viewspace-2928894/,如需轉載,請註明出處,否則將追究法律責任。

相關文章