復制的基礎
MySQL復制基礎是SQL語句的邏輯復制。其中復制中對于執行的SQL語句進行驗證,但對整個結構(表,數據庫)等不會進行驗證。
從目前自身提供的幾種HA核心架構,可以知曉單臺節點負載和性能,會影響Relay Log回放速度,如超過負載,延遲無可避免。

在這種情況下,當主從切換的時候,會存在數據不一致的情況,更嚴重的數據混亂情況。對于企業核心系統,數據不一致是非常致命的。
發生不一致情況
主從數據不一致可能是由多種因素造成的,常見的數據不一致,從目前了解的一些案例總結如下:
1.從庫被寫入數據
1、 這里分多種情況,常用的架構里因為前段應用訪問的vip,因網絡心跳問題,在主從節點上vip跳動,導致分別在兩邊都寫入。通稱腦裂現象。

2、 雙主情況下,為了保證負載,業務特性,雙節點都在寫,但因為復制進程斷開或延遲存在,導致兩個節點都寫入同樣的數據。復制破壞被迫停止,業務持續當中,這種情況破壞性越來越擴大。

3、 從庫人為做了操作:誤鏈接從節點進行操作.

2.binlog非row格式
binlog三種模式,不管statement模式 還是mixed模式都有可能會用sql語句方式,把不應該操作的數據進行更改。最終數據不一致。

3.存儲過程 或 觸發器
存儲過程或 觸發器 因為本地調用的特有特性,有可能導致數據不一樣結果。特別是時間和自增字段。
auto increment ,datetime ,timestamp
4.sql_mode不一致
因為模式不同,對數據的處理不一樣。典型的STRICT_TRANS_TABLES嚴謹模式,進行數據的嚴格校驗,錯誤數據不能插入。當模式不一樣下數據會被截斷,最終就會存在不一致問題。
mysql> CREATE TABLE `t1` (
`id` int NOT NULL,
`name` varchar(10) ,
PRIMARY KEY (`id`)
) ENGINE=InnoDB ;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like '%sql_mode%';
+---------------+-----------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+---------------+-----------------------------------------------------------------------------------------------------------------------+
| sql_mode | ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+---------------+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
mysql> set sql_mode="";
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t1(id,name) values(1,"hello beijing nice to meet you");
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from t1;
+----+------------+
| id | name |
+----+------------+
| 1 | hello beij |
+----+------------+
1 row in set (0.00 sec)
5.復制跳過
slave_skip_error, sql_slave_skip_counter和gtid_next方式,跳過事務,就說明對應事務,沒有在從庫執行,這些復制跳過方式運行當中需要謹慎操作。
1、sql_slave_skip_counter :傳統position模式下,跳過當前時間來自于master的之后N個事件,這對于恢復由某條SQL語句引起的從庫復制有效。

2、gtid_next跳過方式;
在碰到一些gtid事務沖突的時候,手動處理跳過事務,gtid信息和事務編號一定要精準。
Gtid_next可以接受以下任何值:
| 字段 | 說明 |
|---|---|
| AUTOMATIC | 使用下一個自動生成的全局事務ID。 |
| ANONYMOUS | 事務沒有全局標識符,僅通過文件和位置進行標識。 |
| UUID | NUMBER格式的全局事務ID。 |

3、slave_skip_error 應對復制SQL thread線程回放語句進行跳過。
復制SQL線程在語句返回選項值中列出的任何錯誤時,跳過,繼續復制。這是保證復制不斷,但丟失數據一致性。
slave_skip_errors選項有四個可用值,分別為:off、all、ErorCode、ddl_exist_errors。

如下配置:
主從庫同步錯誤:
1062 Error ‘Duplicate entry ‘1438019’ for key ‘PRIMARY’’ on query;
1032 Error Can’t find record in ‘table’;
1053 Error:復制過程中主服務器宕機
[mysqld]
slave_skip_errors=1062,1053,1032
備注:
因NDB集群之間復制時不以相同的方式工作(epoch序列號,一旦丟失或打亂了順序,會立即停止復制應用程序線程)。從NDB 8.0.28開始,提供忽略跳過的epoch事務,可以通過同時指定NDB-application-allow-skip-epoch和——slave-skip-errors;
6.雙1設置
MySQL日志體系中存在服務器日志和引擎層日志,寫入底層文件,控制參數為sync_binlog,innodb_flush_log_at_trx_commit。其中innodb_flush_log_at_trx_commit是將事務日志從innodb log buffer寫入到redo log中,sync_binlog是將二進制日志文件刷新到磁盤上binlog。
不是雙1的情況下,mysqld服務崩潰或者服務器主機crash的情況下,很有可能出現binlog或者relaylog文件出現損壞,導致主從不一致。
7.半同步機制
在開啟半同步復制下,不合理的參數設置,會導致數據不一致的風險。
主要核心參數rpl_semi_sync_master_wait_point有兩個值after_commit是MySQL5.6半同步參數,after_sync是MySQL5.7參數,用以解決MySQL5.6半同步缺陷的選項。
區別于是在從庫接收ack確認以后主庫在引擎層做提交(after_sync),而after commit是先在引擎層做提交后等待ACK確認。因此,在寫入數據后并且在從庫確認之前,其他的客戶端可以看到在這一事務。
mysqld服務崩潰或者服務器主機crash的情況下,要不丟失,要不回滾,可能會導致主從不一致。
8.ignore/do/rewrite等replication等規則**
過濾復制源數據,常見的問題出現在不同schema下跨schema操作。
如:復制數據庫如db1,但在db2中進行 db1.table的更改,這樣從庫就不會回放這條SQL語句。
9.binlog_row_image記錄內容
binlog_row_image參數可以設置三個值: FULL、MINIMAL、NOBLOB。不同的設置binlog記錄數據不一樣。
前鏡像:數據庫表中修改前的內容
后鏡像:數據庫表中修改后的內容

| 值 | 說明 |
|---|---|
| full | 表無論有沒有主鍵約束或者唯一約束binlog都會記錄所有前后鏡像; |
| minimal | 如果表有主鍵或唯一索引,前鏡像只保留主鍵列,后鏡像只保留修改列;如果表沒有主鍵或唯一索引,前鏡像全保留,后鏡像只保留修改列; |
| noblob | text/blob列;如表有主鍵或唯一索引,前后鏡像忽略text/blob列。如果表沒有主鍵或唯一索引,前后鏡像全保留;如果表沒有主鍵或唯一索引,修改列不是text/blob列,前鏡像全保留,后鏡像忽略text/blob列。 |
10.sql_log_bin參數
sql_log_bin是一個動態變量,開啟參數之后更改操作不寫入binlog。對于數據更改,就不能使用這個參數。不寫入binlog就無法同步到從節點。
如下述操作 就不會記錄binlog,數據將不同步:
mysql> SET @@SESSION.SQL_LOG_BIN= 0;
Query OK, 0 rows affected (0.00 sec)
mysql> update t1 set age=10 where id =4;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SET @@SESSION.SQL_LOG_BIN= 1;
11.表結構不一致
為了一些特許需求,有時主從結構不一致,比如從庫設置主鍵,唯一鍵,多余的字段,字段類型 或 默認值等。
數據本身不一致,可能會導致未知的問題。
12.外鍵約束
foreign_key_checks 參數導致,從庫SQL回放的時候,沒有驗證外鍵值。
13.備份一致性丟失
因備份是參數(如:邏輯備份mysqldump參數 single-transaction和master-data )和 開源備份軟件xtrabackup 導致最終一致性丟失。這樣搭建出來的復制節點,本身就存在問題。
14.版本不一致
特別是高版本是主,低版本為從的情況下,主數據庫上面支持的功能,從數據庫上面不支持該功能。
15.自身bug
mysql本身的bug引起的主從不同步。
比如:碰到的現象是Slave_IO_Running,Slave_SQL_Running進程Yes狀態,但實際復制進程窮住。
應對不一致
雖然目前國內MySQL使用已經非常普遍,但還是會碰到數據不一致問題。這些不一致問題,如上述描述中的一條件 或 多種組合。對于發生不一致問題,要及時發現,要及時修復,要初期避免。
避免不一致:
- 多節點寫入, 業務要合理設計,不應該存在沖突;
- slave_skip_error參數絕對不可用,如特殊情況應急可以;
- innodb_flush_log_at_trx_commit,sync_binlog 雙1數據安全性保障;
- 設置從庫為只讀模式,不可操作;
- 增強半同步避免數據丟失采取after_sync模式;
- binlog強烈建議設置為row格式;binlog_row_image 為FULL模式;
- 復制存在延遲時,把從庫提升為主庫,有可能存在數據不一致情況;
- 過濾復制源數據,不得跨schema操作;
- 存儲過程&觸發器使用不要依賴一些特性的字段,盡量不使用;
- sql_mode必須采取嚴謹模式;
- 主從表結構必須一致;
- 備份恢復搭建從庫,一致性要保證;
發現不一致
發現問題,需要做好監控,還需定期進行主從一致性檢驗。
不一致的修復
1、將從庫重新搭建
恢復時間比較慢,而且有時候從庫也是承擔一部分的查詢操作的,不能貿然重建。但發生數據不一致,不要覺得麻煩,就選擇手動修復,建議還是重新搭建
2、使用percona-toolkit工具輔助
PT工具包中包含pt-table-checksum和pt-table-sync兩個工具,主要用于檢測主從是否一致以及修復數據不一致情況。修復速度快,不需要停止主從輔助
3、手動修復不一致的表或數據
執行期間需要暫時停止從庫復制,按照不一致的提示信息,手動修復。
除了上訴這些,做好日常備份。當所有手段無用的,通過備份恢復,修復不一致數據。




