mysql主從常見問題

1、主從複製概述mysql

      主從複製是Mysql內建的複製功能,它是構建高性能應用程序的基礎,技術成熟,應用也很普遍。其原理就是經過將Mysql主庫的sql語句複製到從庫上,並從新執行一遍來實現的。複製過程當中主庫將更新寫入二進制日誌文件,並維護文件的一個索引以跟蹤日誌循環。這些日誌能夠記錄發送到從庫的更新。每次從庫鏈接主庫時,它會通知主庫最後一次成功更新的位置。從庫接收從那時起發生的任何更新。在進行主從複製時,全部命令都必須在主庫上進行,從庫不作操做。不然,會引發主從庫之間的數據不一樣步,複製會中斷。sql

下面列舉了主從模式時常見的一些問題,都是平時工做中實際遇到過的實戰案例。數據庫

2、錯誤及解決辦法服務器

問題: 從數據庫沒法同步app

Slave_SQL_Running 值爲 NO,或 Seconds_Bebind_Master 值爲 Nullsocket

緣由:post

1. 程序有可能在 slave 上進行了寫操做性能

2. 也有多是 slave 機器重啓後,事務回滾形成的ui

解決方法一:編碼

msyql> stop slave;

msyql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;

msyql> start slave;

解決方法二:

msyql> stop slave; 

#查看主服務器上當前的 bin-log 日誌名和偏移量

msyql> show master status;

#獲取到以下內容:

+------------------+----------+--------------+------------------+

| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB |

+------------------+----------+--------------+------------------+

| mysql-bin.000005 |      286 |              |                  |

+------------------+----------+--------------+------------------+

#而後到從服務器上執行手動同步

msyql> change master to

    ->master_host="192.168.10.1",

    ->master_user="user",

    ->master_password="123456",

    ->master_post=3306,

    ->master_log_file="mysql-bin.000005",

    ->master_log_pos=286;

    

msyql> start slave;

  • 場景1:主庫上用系統命令複製或刪除表數據文件

    【模擬異常】:

    主庫上直接copy表數據文件,或直接rm表數據文件主庫上拷貝test表數據文件後,執行insert into test values('111');或主庫上執行rm -f test05.*後,執行create table test05(a int(11));

【錯誤日誌】:

從庫日誌:SHOW SLAVE STATUS \G;

Last_Errno: 1146

Last_Error:Error 'Table'testdb.test 'doesn't exist'on query' insertinto test values('111') '.

Default database: 'testdb'. Query: 'insert into testvalues('111')'

或者以下:

Last_Error: Error 'Table’test05 'already exists' on query.

【錯誤緣由】:

表的建立或刪除不是經過執行sql,未寫入binlog,從庫上沒有相關表;

【解決方案】:

在從庫上手動建立此表(建表語句可參考主庫);

之後,主庫上對錶的操做請經過sql完成,避免使用系統命令拷貝或刪除

 

  • 場景2:數據不一致:包括刪除失敗、主鍵重複、更新丟失

【問題1】:

主鍵重複:在slave已經有該記錄,又在master上插入了同一條記錄。

從庫日誌:SHOW SLAVE STATUS \G;

Last_Errno: 1062

Last_Error: Error 'Duplicate entry 'xxxn-66-77' for key1' on query. Default database: 'guild'. Query: 'insert into pynpcrecord setMapCode = 'xxxn', UpdateTime = '2015-08-07 00:00:32''

     【解決方案】:

方案1:在從庫上將重複的主鍵記錄刪除,再次重啓主從;

 deletefrom xxxx where 主鍵=yyyy;

  stopslave;start slave;

       方案2:停掉主從同步,忽略一次錯誤,再開啓同步:

    stop slave;

      set global sql_slave_skip_counter=1;startslave;

  如果新配主從,忽略3次還報此錯,還能夠在my.cnf里加

      一 行: slave-skip-errors=1062

      而後重啓實例,再重啓主從同步;

   stop slave; start slave;

【問題2】刪除失敗:在master上刪除一條記錄,而slave上找不到。

從庫日誌:SHOW SLAVE STATUS \G;

Last_Errno: 1032;

Last_Error: Could not execute Delete_rows event ontable hcy.t1;

Can't find record in 't1',

【解決方案】:

因爲master要刪除一條記錄,而slave上找不到而報錯,這種狀況主庫都將其刪除了,從庫能夠直接跳過。

可用命令:

stop slave;

set global sql_slave_skip_counter=1;startslave;

【問題3】:更新丟失:在master上更新一條記錄,而slave上找不到,丟    失了數據。

從庫日誌:SHOW SLAVE STATUS \G;

Last_Errno: 1032;

Last_Error: Could not execute Update_rows event ontable hcy.t1; Can't find record in 't1',

     【解決方案】:

把丟失的數據在slave上填補,而後跳過報錯便可。

  • 場景3:字段不一致:包括字段丟失、不夠長等

【問題1】

從庫日誌:SHOW SLAVE STATUS \G;

Slave_IO_Running: Yes

Slave_SQL_Running: No

Last_Errno: 1264

Last_Error: Error 'Out of range value for column 'JFNow' at row 1' onquery. Default database: 'guild'. Query: 'update pyPHBWS set JFNow =JFNow -1 wherePlayerName = '狂魔''

雖然從庫該字段和主庫的一致,但從庫仍是報錯:

guild> desc pyPHBWS;

+------------+---------------------+------+-----+---------+-------+

| Field      |Type                | Null | Key |Default | Extra |

+------------+---------------------+------+-----+---------+-------+

| PlayerName | varchar(30)         | NO  | PRI | NULL    |       |

| JFNow   | int(10)unsigned    | YES  |     |NULL    |       |

| JFAll   |int(10) unsigned    | NO   |    | NULL    |       |

     【解決方案】

修改字段:

ALTER TABLE guild.pyPHBWS MODIFY JFNowbigint(20) unsigned;

重啓主從:stop slave;start slave;

【問題2】

從庫日誌:

  SHOW SLAVE STATUS \G;

Slave_IO_Running: Yes

Slave_SQL_Running: No

Last_Errno: 1054

Last_Error:Error 'Unknown column 'qdir' in 'field list''on query. Default database: 'club'. Query: 'insert into club.question_del (id,pid, ques_name, title, intime, order_d, endtime,qdir) select id, pid,ques_name, title, intime, order_d, endtime ,qdir from club.question whereid=7330212'

【解決方案】

主庫:查詢 desc club.question_del,發現club.question_del表裏面沒有qdir這個字段;

從庫:執行 alter table question_del add qdirvarchar(30) not null;

  • 場景4:超出MyISAM數據表大小限制

【錯誤日誌】

從庫日誌:

   SHOW SLAVE STATUS \G;

Slave_IO_Running: No

Slave_SQL_Running: Yes

Last_Errno : 1114

Last_Error : Error 'The table   'tbleventlog' is full' onquery. Default database: 'dblog'. Query: 'insert into `tbleventlog`(`PlayerName`, `ACTION`, `VALUE`, `PARAM`, `TIME`) values ('ĺɫ', '־', '620',':2,:397842703', '2015-07-28 06:56:04')'

找到該實例所在的目錄,發現該表大小超過4GB;

【解決方案】

對於MyISAM數據表,單個.MYD和.MYI默認4GB。

利用AVG_ROW_LENGTH和MAX_ROWS建表選項能夠把這個最大值擴大到800萬TB.

max_rows主要對myisam生效.

從庫:調整max_rows並重啓slave.

use dblog; ALTER TABLE tbleventlog MAX_ROWS=1000000000;

stop slave; start slave;

  • 場景5:slave的中繼日誌relay-bin損壞

【模擬異常】

SLAVE在宕機,或者非法關機,例如電源故障、主板燒了等,形成中繼日誌損壞,同步停掉。

【錯誤日誌】

從庫日誌:SHOW SLAVE STATUS \G;

Slave_IO_Running: Yes

Slave_SQL_Running: No

Last_Errno: 1593

Last_Error: Error initializing relay log position: I/Oerror reading event at position 4

【解決方案】

在主庫上找到同步的binlog和POS點,而後從新作同步,這樣就能夠有新的中繼日誌了。

mysql> CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000010',MASTER_LOG_POS=821;

  • 場景6:binlog index記錄不一致

【模擬異常】

主數據庫忽然中止或問題終止,更改了mysql-bin.xxx日誌,slave服務器找不到這個文件。

【錯誤日誌】

從庫日誌:SHOW SLAVE STATUS \G;

Master_Log_File: mysql-bin.000029

Last_Errno: 1594

Last_Error: Relay log read failure: Could not parserelay log event entry.

【解決方案】

找到同步的點和日誌文件,而後chage master便可:

change master to master_log_file='mysql-bin.000025',master_log_pos=1010663436;

  • 場景7:時區不一致致使主從數據不一致

【模擬異常】:主從服務器設置不一樣的時區

主庫:show variables like '%timezone%';      #.看到變量timezone值爲EDT

從庫:showvariables like '%timezone%';       #.看到變量timezone值爲 CST

【錯誤日誌】:主庫執行insert into tbname(dtime)values(now());

主庫:  select* from tbname;  #.看到字段dtime值爲 2013-05-08 18:40:18

從庫:  select* from tbname;  #.看到字段dtime值爲 2013-05-09 06:40:18

【解決方案】:

設置主從爲相同時區,並儘可能使用相同時間服務器

若是對時間字段用now()寫入,在刪除時候用delete * from tbname where dtime='xxx',因爲主從時間是不一致的,就會形成刪除的非同一條記錄,也會引發主鍵衝突問題。

  • 場景8:字段集不一致

【模擬異常】

1.主庫:版本MySQL 4.0.18,字符集gb2312,主鍵字段PlayerName

show create table pybcsltscore; 

PRIMARY KEY (`PlayerName`)  ENGINE=MyISAM DEFAULT CHARSET=gb2312

2.從庫:版本MySQL 4.1.22,字符集latin1,主鍵字段PlayerName

show create table pybcsltscore; 

PRIMARY KEY (`PlayerName`)  ENGINE=MyISAM DEFAULT CHARSET=latin1

3.主庫:執行sql:

mysql> insert into pybcsltscore set PlayerName = '怒☆斬', PT = 'pchg.c8';

mysql> insert into pybcsltscore set PlayerName = '怒★斬', PT = 'pchg.c8';

4. 主庫:查詢正常

select * from pybcsltscore where playername='怒☆斬' or playername='怒★斬';

【錯誤日誌】

從庫:查詢異常,查詢實心星號,結果卻出現空心星號

select * from pybcsltscore_bak where playername='怒★斬';

從庫: 從庫狀態:

Last_Errno: 1062

Last_Error: Error 'Duplicate entry '怒★斬' for key 1' on query. Defaultdatabase: 'test0505'. Query: 'insert into pybcsltscore set PlayerName = '怒★斬', PT = 'pchg.cs68'‘

從庫:插入playname=’怒★斬’ 的記錄,會提示主鍵衝突

insert into score_bak set PlayerName = '怒★斬', PT = 'pchg.cs68';

ERROR 1062 (23000): Duplicate entry '怒★斬' for key 1

【解決方案】

方案1. 從庫:去掉主鍵

alter table pybcsltscore_test0513 drop primary key;

stop slave sql_thread; start slave sql_thread;

       方案2. 從庫:修改默認編碼爲gb2312

mysql --default-character-set=gb2312 -S mysql3307.sock

       從庫:再次查詢:

select * from pybcsltscore where playername='怒☆斬' or playername='怒★斬';

  • 場景9:max_allowed_packet過小

【模擬異常】

1. 主庫:設置max_allowed_packet爲特小值,好比12K:

mysql> set global max_allowed_packet=12*1024;

Query OK, 0 rows affected (0.00 sec)

   mysql> show variables like 'max_allowed_packet';                 

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| max_allowed_packet | 12288 |

+--------------------+-------+

2. 重啓slave io thread

#說明:slave若是不重啓的話,我的以爲主從關係所使用的主庫的變

不會改變,重啓以便從新加載一些變量

 

3. 主庫:導入r2.txt(僅一行記錄    

 # du -sh r2.txt    80K    r2.txt)

 ./bin/mysql test0505 -e "load data infile'/tmp/r2.txt' into table test2;"

 

4. 查看從庫狀態

Slave_IO_Running: No

Slave_SQL_Running: Yes

5. 從庫:

mysql> show variables like 'max_allowed_packet';                 

+--------------------+----------+

| Variable_name      | Value    |

+--------------------+----------+

| max_allowed_packet | 16776192|

+--------------------+----------+

【錯誤日誌】

查看從數據庫的錯誤日誌,找到以下信息:

[ERROR] Got fatal error 1236: 'log event entry exceededmax_allowed_packet;

Increase max_allowed_packet on master' from master whenreading data from binary log

或相似:

[ERROR] Error reading packet from server: Got packetbigger than          'max_allowed_packet' bytes (server_errno=2020)

應該是master上的dump線程在從binlog讀取數據時,讀取的結果集超出了max_allowed_packet限制,形成往slave發送失敗。

 

【解決方案】

修改max_allowed_packet的大小,而後重啓slave。建議主從一致

mysql> set global max_allowed_packet=16*1024*1024;

重啓slave, stop salve;start slave;

  • 場景10:臨時表太大致使磁盤寫滿

【錯誤日誌】:從庫日誌

 Last_Errno: 3

  Last_Error: Error 'Error writing file '/tmp/FeqMc' (Errcode: 28)'on query.

  Default database: 'evt'. Query: 'delete from goodslogwhere OpTime<'2015-07-01''

【錯誤緣由】

1. tmp目錄不可寫,或磁盤沒有空間;

2. tmp還有空間,可是原表太大,因此查詢時生成的臨時表過大,所以出   錯。

 

【解決方案】

1. 確認/tmp可寫入,同時磁盤未寫滿;

2. 修改socket目錄到空間較大的分區,再重啓實例;

把 socket = /tmp/mysql.sock 改成 socket = /app/mysql.sock

相關文章
相關標籤/搜索