溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL中server_id一致帶來的問題如何處理

發布時間:2021-11-06 10:33:01 來源:億速云 閱讀:302 作者:小新 欄目:MySQL數據庫

小編給大家分享一下MySQL中server_id一致帶來的問題如何處理,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

簡介

我們都知道在MySQL搭建復制環境的時候,需要設置每個server的server_id不一致,如果主庫與從庫的server_id一致,那么復制會失敗。但是最近在解決一個客戶的問題的時候,遇到一個有意思的現象,客戶環境有三臺數據庫服務器,一主兩從,客戶的兩臺從庫設置了相同server_id,在排查問題的過程中,查看MySQL錯誤日志,發現有很多奇怪的信息。
我們模擬了客戶的環境,并進行測試、分析,最終在代碼中找到了我們想要的答案。下面就是我們測試、分析、總結的步驟以及內容。

測試步驟

環境介紹

  • 主庫
    IP:192.168.1.130
    server_id:3656

  • 從庫A
    IP:192.168.1.36
    server_id:56

  • 從庫B
    IP:192.168.1.57
    server_id:56

三臺主機除server_id之外,其余配置如下:

  1. server_id = 123

  2.     [client]

  3.     socket = /home/mysql/data/mysqldata5.5/sock/mysql.sock

  4.     [mysqld]

  5.     #server_id = 3655

  6.     server_id = 123

  7.     port = 3306

  8.     skip_name_resolve = 1

  9.     binlog_format = ROW

  10.     #binlog_format = STATEMENT

  11.     basedir = /home/mysql/program/mysql5.5.36

  12.     datadir = /home/mysql/data/mysqldata5.5/mydata

  13.     socket = /home/mysql/data/mysqldata5.5/sock/mysql.sock

  14.     pid-file = /home/mysql/data/mysqldata5.5/sock/mysql.pid

  15.     tmpdir = /home/mysql/data/mysqldata5.5/tmpdir

  16.     log-error = /home/mysql/data/mysqldata5.5/log/error.log

  17.     slow_query_log

  18.     slow_query_log_file = /home/mysql/data/mysqldata5.5/slowlog/slow-query.log

  19.     log-bin = /home/mysql/data/mysqldata5.5/binlog/mysql-bin

  20.     relay-log = /home/mysql/data/mysqldata5.5/relaylog/mysql-relay-bin

  21.     innodb_data_home_dir = /home/mysql/data/mysqldata5.5/innodb_ts

  22.     innodb_log_group_home_dir = /home/mysql/data/mysqldata5.5/innodb_log

  23.     #innodb_undo_directory = /home/mysql/data/mysqldata5.5/undo/

  24.     sync_binlog=1

  25.     innodb_file_per_table=1

  26.     #skip_grant_tables

  27.     expire_logs_days = 1

  28.     log_slave_updates = ON

  29.     #replicate-same-server-id=1

  30.     skip_slave_start

  31.     #innodb_undo_tablespaces=1

5.5.36版本現象

初始搭建環境之后,查看各主機狀態。搭建環境的步驟就省略。

主庫(192.168.1.130)

主庫通過show processlist語句查看,只有一個dump線程,但是通過多次刷新,可以看到連接的是不同的服務器??梢钥吹矫看瓮ㄟ^show processlist語句顯示的dump線程的Host字段中,IP:PORT的值是不斷在更新的,說明dump線程在不斷的重連,才會出現占用不同的端口的現象。
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理

從庫A(192.168.1.36)

通過show slave status\G命令查看復制狀態,多次執行可以看到Slave_IO_Running字段顯示的內容,出現YES或者Connnecting兩種狀態??梢钥吹絀/O線程在不斷的進行重連。
并且通過tail -f命令查看error log,可以看到I/O線程一直在嘗試重新連接。
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理
可以看到在錯誤日志中打印的信息是,I/O線程連接
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理

從庫B(192.168.1.57)

從庫B現象與從庫A一致。
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理

MySQL中server_id一致帶來的問題如何處理

5.6.36版本現象

搭建環境步驟省略。

主庫(192.168.1.130)

show processlist查看有兩個dump線程,并且多次刷新,發現Host字段中的IP:PORT并沒有修改,說明dump線程一直保持連接。
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理

從庫A(192.168.1.36)

tail -f /home/mysql/data/mysqldata5.6/log/error.log查看錯誤日志,沒有不斷斷開連接
MySQL中server_id一致帶來的問題如何處理

從庫B(192.168.1.57)

tail -f /home/mysql/data/mysqldata5.6/log/error.log查看錯誤日志,沒有不斷斷開連接
MySQL中server_id一致帶來的問題如何處理
MySQL中server_id一致帶來的問題如何處理

原因分析

http://www.penglixun.com/tech/database/mysql_multi_slave_same_serverid.html這是彭立勛寫的關于多個slave使用相同server_id時沖突的原因的一篇文章。按照彭大大的分析,我理解的是,slave的I/O線程連接上主庫的時候,主庫上會調用register_slave()這個函數,在這個函數中又調用了unregister_slave()函數,會將之前使用相同server_id的線程給注銷掉。從而導致從庫的I/O線程不斷斷開重連。
但是仔細看了一下unregister_slave()函數的代碼,并沒有發現MySQL是根據server_id來注銷dump線程的。并且進一步比較了一下5.5.36和5.6.36版本的代碼,并沒有發現不同。而從庫設置server_id一致導致I/O線程不斷重連的現象只在5.5版本中看到,在5.6版本中并沒有這個現象,所以導致5.5現象的原因不是在unregister_slave()函數中。
進一步看了一下彭大大的文章,發現有人在下面評論,說主要是kill_zombie_slave_threads()函數導致的。于是看了一下kill_zombie_slave_threads()函數的邏輯,發現MySQL應該就是在這一步根據server_id將線程kill了。

  • 5.5.36版本
    首先來看下5.5.36版本的kill_zombie_dump_threads()函數的代碼??吹竭@個函數傳入的參數是一個uint32類型的slave_server_id,在函數中做的事情是,遍歷MySQL中的所有線程,如果遍歷到一個線程是dump線程并且線程的server_id是等于傳入的參數值話,則跳出遍歷循環,并對kill掉這個線程。

  1. void kill_zombie_dump_threads(uint32 slave_server_id)

  2.     {

  3.       mysql_mutex_lock(&LOCK_thread_count);

  4.       I_List_iterator<THD> it(threads);

  5.       THD *tmp;

  6.       while ((tmp=it++))

  7.       {

  8.         if (tmp->command == COM_BINLOG_DUMP &&

  9.           tmp->server_id == slave_server_id)

  10.         {

  11.          mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete

  12.          break;

  13.         }

  14.       }

  15.       mysql_mutex_unlock(&LOCK_thread_count);

  16.       if (tmp)

  17.       {

  18.         /*

  19.          Here we do not call kill_one_thread() as

  20.          it will be slow because it will iterate through the list

  21.          again. We just to do kill the thread ourselves.

  22.         */

  23.         tmp->awake(THD::KILL_QUERY);

  24.         mysql_mutex_unlock(&tmp->LOCK_thd_data);

  25.       }

  26.     }


5.6.35版本
再來看一下5.6.36版本的kill_zombie_dump_threads()函數的代碼實現,與5.5.36大不相同。首先傳入的參數是一THD類型的指針,在函數中實現的邏輯同樣是遍歷MySQL中的所有線程,如果找到dump線程,首先看一下這個線程有沒有uuid字段(因為uuid是在5.6之后的版本才有的,這邊是為了兼容5.5),如果有uuid則用uuid進行比較,如果沒有uuid,則用server_id進行比較。

  1. void kill_zombie_dump_threads(THD *thd)

  2.     {

  3.       String slave_uuid;

  4.       get_slave_uuid(thd, &slave_uuid);

  5.       if (slave_uuid.length() == 0 && thd->server_id == 0)

  6.         return;

  7.       mysql_mutex_lock(&LOCK_thread_count);

  8.       THD *tmp= NULL;

  9.       Thread_iterator it= global_thread_list_begin();

  10.       Thread_iterator end= global_thread_list_end();

  11.       bool is_zombie_thread= false;

  12.       for (; it != end; ++it)

  13.       {

  14.         if ((*it) != thd && ((*it)->get_command() == COM_BINLOG_DUMP || (*it)->get_command() == COM_BINLOG_DUMP_GTID))

  15.         {

  16.          String tmp_uuid;

  17.          get_slave_uuid((*it), &tmp_uuid);

  18.          if (slave_uuid.length())

  19.          {

  20.            is_zombie_thread= (tmp_uuid.length() && !strncmp(slave_uuid.c_ptr(),

  21.                                              tmp_uuid.c_ptr(), UUID_LENGTH));

  22.          else

  23.          {

  24.            /*

  25.            ? Check if it is a 5.5 slave's dump thread i.e., server_id should be

  26.            ? same && dump thread should not contain 'UUID

函數調用
知道了kill_zombie_dump_threads()線程實現的邏輯,那MySQL是在什么地方會調用這個函數的呢??戳艘幌潞瘮凳窃赾ase COM_BINLOG_DUMP中被調用的。
在5.5.36版本中是在


  1. case COM_BINLOG_DUMP:

  2.      {

  3.      ulong pos;

  4.      ushort flags;

  5.      uint32 slave_server_id;

  6.      status_var_increment(thd->status_var.com_other);

  7.      thd->enable_slow_log= opt_log_slow_admin_statements;

  8.      if (check_global_access(thd, REPL_SLAVE_ACL))

  9.     break;

  10.      /* TODO: The following has to be changed to an 8 byte integer */

  11.      pos = uint4korr(packet);

  12.      flags = uint2korr(packet + 4);

  13.      thd->server_id=0; /* avoid suicide */

  14.      if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0

  15.      kill_zombie_dump_threads(slave_server_id);

  16.      thd->server_id = slave_server_id;

  17.      general_log_print(thd, command, "Log: '%s'  Pos: %ld", packet+10, (long) pos);

  18.      mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);

  19.     unregister_slave(thd,1,1);

  20.     /* fake COM_QUIT -- if we get here, the thread needs to terminate */

  21.      error = TRUE;

  22.     break;

  23.     }


在5.6.36版本中也是在case COM_BINLOG_DUMP中,只不過是將之前的邏輯封裝在了com_binlog_dump()函數中了,kill_zombie_dump_threads()也是在com_binlog_dump()函數中調用的。

  1. case COM_BINLOG_DUMP:

  2.     error= com_binlog_dump(thd, packet, packet_length);

  3.     break

case COM_BINLOG_DUMP中所進行的操作就是將dump線程通知I/O線程拉取新的binlog。

看完了這篇文章,相信你對“MySQL中server_id一致帶來的問題如何處理”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女