代码改变世界

参数 server_id 的潜在重要性

2024-01-12 20:18  abce  阅读(47)  评论(0编辑  收藏  举报

一般情况下,server_id 被设置为一个随机数字,只是与其他副本上配置的数字不同,而且一旦设置好,以后一般就不会再查看或更改,通常这没什么问题,但如果忽略了 server_id,就可能导致在下面描述的恢复场景中出现不必要的事务跳过。

 

假设我们有以下拓扑结构:

db2 - primary - server_id = 82
db1 - replica - server_id = 81

 

一旦主数据库(db1)上的流量被转移,我们就可以开始对其进行维护。在维护过程中,磁盘出现了问题,导致 MySQL 中的数据不一致。别担心,我们有当天早些时候从 db2 上获取的备份,让我们使用它吧

·使用 rsync 将备份从 db2 复制到 db1。
·使用 xtrabackup 还原数据
·使用与 db1 崩溃前相同的配置启动 MySQL。(server_id=81)。
·在设置复制时,可以使用来自 xtrabackup_binlog_info 的复制位置,因为我们需要一致备份是来自 db2 的日志位置。

 

在备份和还原之间,生成了许多需要应用的 binlog,因此我们预计复制需要一些时间才能完全赶上主系统。

复制配置完成后,却发现 binlog 的进度太快。

 

假设使用以下位置配置复制:

mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.10.10.10',
    -> MASTER_USER='repluser',
    -> MASTER_PASSWORD='XXXXXXXXXXXXXXXX',
    -> MASTER_LOG_FILE='mysql-bin.034322',
    -> MASTER_LOG_POS=375677230;
Query OK, 0 rows affected, 2 warnings (0.36 sec)

 

查看一下复制的状态:

*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.10.10.10
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.034324
              Read_Master_Log_Pos: 3898727534
               Relay_Log_File: mysql-relay-bin.000006
              Relay_Log_Pos: 369
        Relay_Master_Log_File: mysql-bin.034324
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
...
          Exec_Master_Log_Pos: 3898727534
...
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 2002
                  Master_UUID: 94318777-57fe-11ee-a884-b496916f3834
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400

注意到奇怪的事情了吗?是的,Seconds_behind_master: 0,即使有大约 40 多个 binlog 需要应用。

它一直以"快节奏"运行;在几分钟内就推进了 40 个 binlog,直到失败:

mysql> show slave statusG
*************************** 1. row ***************************
               Slave_IO_State:
                  Master_Host: 10.10.10.10
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.034372
          Read_Master_Log_Pos: 107962899
               Relay_Log_File: mysql-relay-bin.000086
                Relay_Log_Pos: 6294
        Relay_Master_Log_File: mysql-bin.034364
             Slave_IO_Running: No
            Slave_SQL_Running: No
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 1032
                   Last_Error: Could not execute Update_rows event on table test.mysql1; Can't find record in mysql1, Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.034364, end_log_pos 123596930

 

怎么回事?我们的备份坏了吗?

检查 binlog 后发现,"处理速度过快"由 server_id=81 导致的,而 server_id=81 与当前副本相同(因为这些记录是在 db1 上生成的,备份时 db1 是主服务器)。一旦尝试在具有相同 server_id 的服务器上应用这些记录,就会跳过这些记录。


然后,一旦完成故障转移,binlogs 事件就会以 server_id=82 (db2)生成。这时它开始实际应用事件,但由于它跳过了来自同一 server_id 的多个事件,因此错过了对数据库的许多更新和插入,导致数据库处于不一致状态。在这种情况下,别无他法,只能重试还原,这次要在开始复制前更改还原服务器上的 server_id 值。

 

除更改 server_id 外,另一种可行的方法是启用选项 replicate-same-server-id。根据文档:"该选项用于复制。默认值为 0(FALSE)。将该选项设置为 1(TRUE)后,副本不会跳过具有自己 server ID 的事件。此设置通常只在罕见配置中有用"。

 

提醒了我们,在复制环境中执行还原时要检查 server_id。这可以避免令人头疼的问题!

 

需要提醒的是,除非我们确定自己在做什么,否则不建议使用 "replicate-same-server-id "参数。