共計 11577 個字符,預計需要花費 29 分鐘才能閱讀完成。
本篇內容介紹了“Mysql 5.7 中 mysql.gtid_executed 表及其他變量更改時機是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓丸趣 TV 小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
一、主庫修改時機
(2) binlog 打開
mysql.gtid_executed 表修改時機
在 binlog 發生切換 (rotate) 的時候保存直到上一個 binlog 文件執行過的全部 Gtid,它不是實時更新的。
棧幀如下:
#0 Gtid_table_persistor::save (this=0x2f9f9c0, gtid_set=0x7ffff03595a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:425
#1 0x0000000001803dbe in Gtid_state::save (this=0x2ff8bb0, gtid_set=0x7ffff03595a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:796
#2 0x0000000001803f62 in Gtid_state::save_gtids_of_last_binlog_into_table (this=0x2ff8bb0, on_rotation=true)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:835
#3 0x000000000185266d in MYSQL_BIN_LOG::new_file_impl (this=0x2dffc80, need_lock_log=false, extra_description_event=0x0)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:6751
#4 0x00000000018520a7 in MYSQL_BIN_LOG::new_file_without_locking (this=0x2dffc80, extra_description_event=0x0)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:6636
#5 0x0000000001853e67 in MYSQL_BIN_LOG::rotate (this=0x2dffc80, force_rotate=true, check_purge=0x7ffff0359c4b)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:7292
其主要邏輯在 Gtid_state::save_gtids_of_last_binlog_into_table 中我們在隨后的部分討論這個函數邏輯。
gtid_executed 變量修改時機
如前文所述 ordered_commit flush 階段生成 Gtid,在 commit 階段才計入 gtid_executed 變量,它是實時更新的。
棧幀如下:
#0 Gtid_set::_add_gtid (this=0x2ff8d38, sidno=1, gno=16) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid.h:1135
#1 0x0000000001804576 in Gtid_set::_add_gtid (this=0x2ff8d38, gtid=...) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid.h:1166
#2 0x00000000018024ba in Gtid_state::update_gtids_impl (this=0x2ff8bb0, thd=0x7fff2c000b70, is_commit=true)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:304
#3 0x00000000018020df in Gtid_state::update_on_commit (this=0x2ff8bb0, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:148
#4 0x00000000018573d4 in MYSQL_BIN_LOG::process_commit_stage_queue (this=0x2dffc80, thd=0x7fff2c000b70, first=0x7fff2c000b70)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8646
#5 0x0000000001858b51 in MYSQL_BIN_LOG::ordered_commit (this=0x2dffc80, thd=0x7fff2c000b70, all=false, skip_commit=false)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:9304
其主要邏輯在 Gtid_state::update_gtids_impl 中我們在隨后的部分討論這個函數邏輯。
gtid_purged 變量修改時機
在 Mysql 觸發的清理 binlog 的情況下,比如 purge binary logs to 或者超過參數 expire_logs_days 設置的天數后自動刪除,需要將丟失的 Gtid 計入這個變量中。
棧幀如下:
#0 MYSQL_BIN_LOG::init_gtid_sets (this=0x2e00280, all_gtids=0x0, lost_gtids=0x2fcaee8, verify_checksum=false, need_lock=false, trx_parser=0x0, gtid_partial_trx=0x0, is_server_starting=false)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:4333
#1 0x0000000001850b8e in MYSQL_BIN_LOG::purge_logs (this=0x2e00280, to_log=0x7fff57a74ad0 /root/mysql5.7.14/percona-server-5.7.14-7/mysql-test/var/mysqld.1/test.000202 , included=false, need_lock_index=true,
need_update_threads=true, decrease_log_space=0x0, auto_purge=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:6036
#2 0x0000000001848ecf in purge_master_logs (thd=0x7fff49200dc0, to_log=0x7fff492051a8 test.000202) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:2815
其主要邏輯在 MYSQL_BIN_LOG::purge_logs 中,我們隨后查看其代碼片段,同時 MYSQL_BIN_LOG::init_gtid_sets 函數是一個及其重要的函數,主要用在:
Mysql 啟動時候初始化整個 Gtid_state 中的各種 Gtid_set。
Mysql 刪除 binlog(如 purge binary logfiles 或者超過 expire_logs_days 設置)后需要確認 gtid_purged 變量 (及 Gtid_state.lost_gtids) 的值的時候。
隨后我會單獨一節來講解 Mysql Gtid 模塊的初始化還會講解這個函數。
二、主庫修改時機源碼函數分析
這里就對上面提到的主要邏輯函數進行分析
Gtid_state::save_gtids_of_last_binlog_into_table 函數邏輯
logged_gtids_last_binlog.add_interval_memory(PREALLOCATED_INTERVAL_COUNT, iv); // 這里構建一個 logged_gtids_last_binlog 集合來保存切換后需要寫入表和 previous_gtids_logged 的 Gtid
/*
logged_gtids_last_binlog= executed_gtids - previous_gtids_logged -
gtids_only_in_table
*/
global_sid_lock- wrlock();//
ret= (logged_gtids_last_binlog.add_gtid_set( executed_gtids) != // 將當前執行過的 Gtid 全部加入 logged_gtids_last_binlog 列如:executed_gtids start=1, end=27
RETURN_STATUS_OK);
if (!ret)
{ logged_gtids_last_binlog.remove_gtid_set( previous_gtids_logged); // 獲得上一個 binlog 文件包含的全部 Gtid,并且做一個差集 列如:previous_gtids_logged 為 start=1, end=25
// 做完差集后 logged_gtids_last_binlog 為 start=26, end=27
logged_gtids_last_binlog.remove_gtid_set(gtids_only_in_table);// 此處主庫一定為空,除非異常情況
if (!logged_gtids_last_binlog.is_empty())
{
/* Prepare previous_gtids_logged for next binlog on binlog rotation */
if (on_rotation)
ret= previous_gtids_logged.add_gtid_set(logged_gtids_last_binlog);// 將這個 start=26, end=27 的 Gtid 集合加入到 previous_gtids_logged 中,這樣 previous_gtids_logged 也完整了
global_sid_lock- unlock();
/* Save set of GTIDs of the last binlog into gtid_executed table */
if (!ret)
ret= save(logged_gtids_last_binlog);// 將這個 start=26, end=27 的 Gtid 集合寫入到表 mysql.gtid_executed 表中
}
Gtid_state::update_gtids_impl 函數代碼片段
while (g.sidno != 0)
{ if (g.sidno != prev_sidno)
sid_locks.lock(g.sidno);
owned_gtids.remove_gtid(g); // 從 owned_gtid 中去掉
git.next();
g= git.get();
if (is_commit)
executed_gtids._add_gtid(g);// 將這個 Gtid 加入到 executed_gtids
}
MYSQL_BIN_LOG::purge_logs 函數代碼片段
if (!is_relay_log)
{ global_sid_lock- wrlock();
error= init_gtid_sets(NULL,
const_cast Gtid_set * (gtid_state- get_lost_gtids()),
opt_master_verify_checksum,
false/*false=don t need lock*/,
NULL/*trx_parser*/, NULL/*gtid_partial_trx*/);// 這里我看到將 gtid_state- lost_gtids 直接傳入給了 init_gtid_sets
//init_gtid_sets 會做正向查找獲得 gtid_state- lost_gtids 這個函數稍后
// 詳細討論
global_sid_lock- unlock();
if (error)
goto err;
}
三、從庫修改時機
(2)binlog 開啟同時參數 log_slave_updates 開啟的情況
這種情況 sql_thread 執行過的 Gtid 事物可以通過 binlog 進行維護,所以 mysql.gtid_executed 表和 gtid_purged 變量不需要實時更新。
mysql.gtid_executed 表修改時機
和主庫一致。及在進行日志切換的時候進行更新,不做討論
gtid_executed 變量修改時機
和主庫一樣實時更新,不做討論
gtid_purged 變量修改時機
和主庫一致,binlog 刪除時更新,不做討論
四、從庫修改時機源碼函數分析
commit_owned_gtids 函數邏輯:
// 如果 binlog 沒有開啟包括 (log_bin=0 和 sql_log_bin =0 ) 或者 開啟了 binlog 但是 slave 線程并且 slave update 沒有開啟, 都會記錄 gtid 到表
// 但是這里要注意一點在主庫上如果 binlog 不開啟那么 thd- owned_gtid.sidno ==0 因為這個時候 Gtid 都沒有生成, 生成階段為 order_commit 的 commit 階段
if ((!opt_bin_log || (thd- slave_thread !opt_log_slave_updates))
(all || !thd- in_multi_stmt_transaction_mode()) //all 代表是否是顯示 begin 事物 in_multi_stmt_transaction_mode 則相反
!thd- is_operating_gtid_table_implicitly // 是否是 GTID_NEXT 方式 flase
!thd- is_operating_substatement_implicitly)// 是否是子語句 flase
{
/*
If the binary log is disabled for this thread (either by
log_bin=0 or sql_log_bin=0 or by log_slave_updates=0 for a
slave thread), then the statement will not be written to
the binary log. In this case, we should save its GTID into
mysql.gtid_executed table and @@GLOBAL.GTID_EXECUTED as it
did when binlog is enabled.
*/
if (thd- owned_gtid.sidno 0)
{ error= gtid_state- save(thd);// 就是這里進行了 mysql.gtid_executed 表的實時更新
*need_clear_owned_gtid_ptr= true;
}
else if (thd- owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS)
*need_clear_owned_gtid_ptr= true;
}
Gtid_state::update_gtids_impl_own_gtid 函數邏輯片段
這個函數是 5.7.17 的,5.7.14 沒有邏輯放到了 Gtid_state::update_gtids_impl 中
if (is_commit)
{
DBUG_EXECUTE_IF(
rpl_gtid_update_on_commit_simulate_out_of_memory ,
DBUG_SET(+d,rpl_gtid_get_free_interval_simulate_out_of_memory);
/*
Any session adds transaction owned GTID into global executed_gtids.
If binlog is disabled, we report @@GLOBAL.GTID_PURGED from
executed_gtids, since @@GLOBAL.GTID_PURGED and @@GLOBAL.GTID_EXECUTED
are always same, so we did not save gtid into lost_gtids for every
transaction for improving performance.
If binlog is enabled and log_slave_updates is disabled, slave
SQL thread or slave worker thread adds transaction owned GTID
into global executed_gtids, lost_gtids and gtids_only_in_table.
*/
executed_gtids._add_gtid(thd- owned_gtid); // 加入 executed_gtids 集合
thd- rpl_thd_ctx.session_gtids_ctx().
notify_after_gtid_executed_update(thd);
if (thd- slave_thread opt_bin_log !opt_log_slave_updates)// 如果是 slave 線程同時 binlog 開啟了并且 log_slave_updates 關閉了
// 如果 binlog 關閉則使用 executed_gtids 這樣提高性能前面的注釋說了
{ lost_gtids._add_gtid(thd- owned_gtid); // 寫入 lost_gtids 也就是更新參數 gtid_purged 變量
gtids_only_in_table._add_gtid(thd- owned_gtid);
}
}
五、通用更改時機
mysql.gtid_executed 表修改時機
在 reset master 的時候清空本表
棧幀如下:
#0 Gtid_table_persistor::delete_all (this=0x2f9f9c0, table=0x7fff2c0116a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:795
#1 0x000000000180a4ef in Gtid_table_persistor::reset (this=0x2f9f9c0, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:689
#2 0x0000000001801f2e in Gtid_state::clear (this=0x2ff8bb0, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:36
#3 0x000000000184fee6 in MYSQL_BIN_LOG::reset_logs (this=0x2dffe80, thd=0x7fff2c000b70, delete_only=false)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:5586
#4 0x0000000001872308 in reset_master (thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_master.cc:587
其主要邏輯在 Gtid_state::clear 中。
在 set global gitd_purged 的時候,設置本表
棧幀如下:
#0 Gtid_table_persistor::save (this=0x2f9f9c0, gtid_set=0x7ffff0359a70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_persist.cc:425
#1 0x000000000180400a in Gtid_state::save (this=0x2ff8bb0, gtid_set=0x7ffff0359a70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:796
#2 0x0000000001803c25 in Gtid_state::add_lost_gtids (this=0x2ff8bb0, gtid_set=0x7ffff0359a70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:737
#3 0x00000000016778f3 in Sys_var_gtid_purged::global_update (this=0x2de9fe0, thd=0x7fff2c000b70, var=0x7fff2c006630)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sys_vars.cc:5888
#4 0x00000000014d5cd1 in sys_var::update (this=0x2de9fe0, thd=0x7fff2c000b70, var=0x7fff2c006630) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/set_var.cc:184
#5 0x00000000014d74ee in set_var::update (this=0x7fff2c006630, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/set_var.cc:812
#6 0x00000000014d6d1a in sql_set_variables (thd=0x7fff2c000b70, var_list=0x7fff2c003528) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/set_var.cc:669
其主要邏輯在 Gtid_state::add_lost_gtids 中。
gtid_executed 變量修改時機
在 reset master 的時候清空本變量
棧幀同上
在 set global gitd_purged 的時候,設置本變量
棧幀同上
在 mysql 啟動的時候初始化設置 gtid_executed 變量,這個將在后面章節詳細描述描述步驟。
gtid_purged 變量修改時機
在 reset master 的時候清空本變量
棧幀同上
在 set global gitd_purged 的時候,設置本變量
棧幀同上
在 mysql 啟動的時候初始化設置 gtid_executed 變量,這個將在后面章節詳細描述描述步驟。
六、通用更改時機源碼函數分析
Gtid_state::clear 函數邏輯
int Gtid_state::clear(THD *thd)
....
// the wrlock implies that no other thread can hold any of the mutexes
sid_lock- assert_some_wrlock();
lost_gtids.clear();// 此處清空 gtid_purged 變量
executed_gtids.clear();// 此處清空 gtid_executed 變量
gtids_only_in_table.clear();// 清空 only in table Gtid set
previous_gtids_logged.clear();// 清空 previous gtids logged Gtid set
/* Reset gtid_executed table. */
if ((ret= gtid_table_persistor- reset(thd)) == 1)// 此處清空 mysql.gtid_executed 表
{
/*
Gtid table is not ready to be used, so failed to
open it. Ignore the error.
*/
thd- clear_error();
ret= 0;
}
next_free_gno= 1;
DBUG_RETURN(ret);
}
Gtid_state::add_lost_gtids 函數邏輯
enum_return_status Gtid_state::add_lost_gtids(const Gtid_set *gtid_set)
......
if (save(gtid_set)) // 此處將 set gtid_purge 的值加入到 mysql.gtid_executed 表中
RETURN_REPORTED_ERROR;
PROPAGATE_REPORTED_ERROR(gtids_only_in_table.add_gtid_set(gtid_set));
PROPAGATE_REPORTED_ERROR(lost_gtids.add_gtid_set(gtid_set));// 此處將 set gtid_purge 的值加入到 gtid_purge 變量中
PROPAGATE_REPORTED_ERROR(executed_gtids.add_gtid_set(gtid_set));// 此處將 set gtid_purge 的值加入到 gtid_executed 變量中
lock_sidnos(gtid_set);
broadcast_sidnos(gtid_set);
unlock_sidnos(gtid_set);
DBUG_RETURN(RETURN_STATUS_OK);
}
“Mysql 5.7 中 mysql.gtid_executed 表及其他變量更改時機是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注丸趣 TV 網站,丸趣 TV 小編將為大家輸出更多高質量的實用文章!