主從,恢復後,記得更改serverid

最近踩到一個說大不大,說小不小的坑,在此分享出來給各位同學。事情是這樣的,線上有2臺服務器,1主1從。A -> B,B服務器從A服務器同步數據。每天使用xtrabackup在B服務器上面進行全備。某天A服務器掛了,後來由於某種原因無法進入系統了,只有重裝了系統,那麼此時要恢復A服務器的步驟就是在A服務器部署mysql實例,從B服務器上面拿備份恢復到A,再根據POS點change到B服務器,讓A服務器從B服務器同步。此時是B -> A。相信熟悉MySQL的人都知道步驟是沒有問題的。

但在這過程中還是出問題了,在A服務器從新從B服務器同步完成以後,確認沒有延時以後,此時把A重新恢復成了原來的角色,也就是主庫,架構又變回了A -> B。恢復完成以後詢問開發說沒有異常。到第二天的時候有玩家反饋數據不正確。此時進行數據差異的查找。最後發現A的數據比B的數據少。在經過幾番查找以及回憶操作步驟以後,發現踩了大坑。那就是我們安裝mysql實例的時候,server-id是根據服務器ip地址的後2位生成的,比如ip地址是:192.168.5.6,那麼server-id就是56。

有同學會問了,和server-id有毛關係啊。大家仔細想想mysql的雙主是怎樣確定binlog是否需要應用的?沒錯,那就是server-id,如果server-id是自己的就不再應用binlog,那麼我踩的坑就是當A再次重新向B同步的時候,A的server-id還是老的,沒有修改,B服務器的binlog裏面記錄的server-id就是A服務器的server-id,最後導致有一部分binlog沒有應用。原理已經說明了,那麼接下來進行簡單的實驗就可以論證了。

環境:

自己搭建一個測試環境,簡單的1主1從。

我主庫的server-id是

複製代碼

mysql> show variables like '%server_id%';+---------------+-------+| Variable_name | Value |+---------------+-------+| server_id     | 25152 |+---------------+-------+1 row in set (0.00 sec)

複製代碼

從庫的server-id是

複製代碼

mysql> show variables like '%server_id%';+---------------+-------+| Variable_name | Value |+---------------+-------+| server_id     | 25250 |+---------------+-------+1 row in set (0.00 sec)

複製代碼

 主庫建庫,建表,插入數據:

複製代碼

mysql> create database yayun;
Query OK, 1 row affected (0.00 sec)

mysql> create table yayun.tb1 ( id int, age int, name char(20), primary key(id) );  
Query OK, 0 rows affected (0.07 sec)

mysql> use yayunDatabase changed
mysql> insert into tb1 (id,age,name)values(1,18,'aa');
Query OK, 1 row affected (0.00 sec)

mysql> insert into tb1 (id,age,name)values(2,18,'bb');
Query OK, 1 row affected (0.00 sec)

mysql> select * from tb1;+----+------+------+| id | age  | name |+----+------+------+|  1 |   18 | aa   ||  2 |   18 | bb   |+----+------+------+2 rows in set (0.00 sec)

mysql>

複製代碼

從庫查詢:

複製代碼

mysql> select * from tb1;+----+------+------+| id | age  | name |+----+------+------+|  1 |   18 | aa   ||  2 |   18 | bb   |+----+------+------+2 rows in set (0.00 sec)

mysql>

複製代碼

此時數據是一致的。

接下來在從庫備份數據,並且記錄pos點。(這裏模擬的是從庫每天進行的備份)

mysqldump -uroot -p --master-data=2 yayun > /tmp/backup_yayun.sql

下面在主庫繼續進行insert,update操作。

複製代碼

mysql> insert into tb1 (id,age,name)values(3,19,'cc');
Query OK, 1 row affected (0.00 sec)

mysql> update tb1 set name='yayun' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> select * from tb1;+----+------+-------+| id | age  | name  |+----+------+-------+|  1 |   18 | yayun ||  2 |   18 | bb    ||  3 |   19 | cc    |+----+------+-------+3 rows in set (0.00 sec)

mysql>

複製代碼

查詢從庫記錄:

複製代碼

mysql> select * from tb1;+----+------+-------+| id | age  | name  |+----+------+-------+|  1 |   18 | yayun ||  2 |   18 | bb    ||  3 |   19 | cc    |+----+------+-------+3 rows in set (0.00 sec)

mysql>

複製代碼

可以看到此時主從數據是一致的。接下來我們就當主庫掛了。重新需要拉取備份,然後向從庫同步數據。
1. 把備份文件backup_yayun.sql拉到主庫。

2. 把從庫的同步斷掉,清掉同步信息。

從庫操作:

mysql> stop slave;reset slave all;
Query OK, 0 rows affected (0.03 sec)

Query OK, 0 rows affected (0.05 sec)

mysql>

主庫操作:

mysql -uroot -p yayun < backup_yayun.sql

查看pos點:

[root@mdw ~]# grep -i change backup_yayun.sql 
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=4070;
[root@mdw ~]#

主庫change到原來的從庫

mysql> CHANGE MASTER TO  MASTER_HOST='10.36.25.250',MASTER_USER='repl',MASTER_PASSWORD='123',MASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=4070;
Query OK, 0 rows affected (0.10 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

查詢數據:

如果查詢出來的數據是下面的數據,那麼就是正確的:

複製代碼

+----+------+-------+| id | age  | name  |+----+------+-------+|  1 |   18 | yayun ||  2 |   18 | bb    ||  3 |   19 | cc    |+----+------+-------+

複製代碼

我們實際查詢一下:

複製代碼

mysql> select * from tb1;+----+------+------+| id | age  | name |+----+------+------+|  1 |   18 | aa   ||  2 |   18 | bb   |+----+------+------+2 rows in set (0.00 sec)

mysql>

複製代碼

臥槽,發生了什麼,怎麼數據少了,而且id等於1的name字段結果也不一樣?

下面我們看看原來老的從庫的binlog

複製代碼

#160908 13:45:57 server id 25152  end_log_pos 4239      Query   thread_id=16    exec_time=0     error_code=0SET TIMESTAMP=1473313557/*!*/;
insert into tb1 (id,age,name)values(3,19,'cc')/*!*/;
# at 4239#160908 13:45:57 server id 25152  end_log_pos 4266      Xid = 160COMMIT/*!*/;
# at 4266#160908 13:46:20 server id 25152  end_log_pos 4325      Query   thread_id=16    exec_time=0     error_code=0SET TIMESTAMP=1473313580/*!*/;
BEGIN/*!*/;
# at 4325#160908 13:46:20 server id 25152  end_log_pos 4427      Query   thread_id=16    exec_time=0     error_code=0SET TIMESTAMP=1473313580/*!*/;
update tb1 set name='yayun' where id=1/*!*/;
# at 4427#160908 13:46:20 server id 25152  end_log_pos 4454      Xid = 162COMMIT/*!*/;
DELIMITER ;

複製代碼

可以看見有insert,update,但是server id都是25152,也就是主庫的。這也就是爲什麼少了數據的原因。開頭也提到過了。

如果我們在新的主庫上面進行update,如果這條記錄在從庫沒有存在,而且主從的binlog是row模式,那麼就會觸發1032錯誤,複製將中斷,由於我的是mixed模式,同步一直沒有報錯,沒有早發現問題。我update語句加limit就會觸發row模式,下面我們試試。

主庫:

mysql> update tb1 set name='abcd' where id=3 limit 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql>

從庫:

複製代碼

mysql> show slave status\G*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 10.36.25.250
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000004
          Read_Master_Log_Pos: 4653
               Relay_Log_File: relaylog.000002
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000004
             Slave_IO_Running: Yes
            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 yayun.tb1; Can't find record in 'tb1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000004, end_log_pos 4626
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 4454
              Relay_Log_Space: 601
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULLMaster_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 1032
               Last_SQL_Error: Could not execute Update_rows event on table yayun.tb1; Can't find record in 'tb1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000004, end_log_pos 4626
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 252501 row in set (0.00 sec)

複製代碼

可以看見拋1032錯誤,主庫有這條記錄,從庫沒有,同時觸發了row模式,就會導致複製中斷。

 

結論:

1. 在重新搭建複製關係的時候一定注意server-id。

2. 線上對數據一致性要求比較高的一定要使用row模式。

 

作者:Atlas

出處:Atlas的博客 http://www.cnblogs.com/gomysql

您的支持是對博主最大的鼓勵,感謝您的認真閱讀。本文版權歸作者所有,歡迎轉載,但請保留該聲明。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章