環境
系統版本 : CentOS release 6.8 (Final)
MySQL版本:5.6.29-log MySQL Community Server (GPL)
MySQL主從配置信息
- binlog format :MIXED
- sql_mode: NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
問題描述
從庫show slave status監控的時候發現sql_thread進程已經變成NO,並且爆出了1362錯誤,仔細查看報錯的是一條insert into語句,並且拋出了一個詳細的錯誤,大致的意思就是字段column_1設置了NOT NULL但是沒有插入值並且沒有默認值。然後仔細檢查了一下表結構,具體信息如下
- 字段column_1的確設置的是NOT NULL並且沒有設置default 默認值。
- column_1字段是是text類型,所以是無法設置defaut默認值。
本地環境手動執行驗證
在看到這個報錯的信息的時候,直接google了一下,大部分答案顯示都是由於sql_mode的原因所導致的,要想解決這個問題,必須將執行:
mysql> set global sql_mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";
但是我在slave獲取得到的sql_mode就是 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
,這個時候我在自己本地執行這個insert 插入語句驗證是否可以插入成功,發現是可以插入的。
猜想
這個時候我就想這個是否在主從複製的過程中,slave在執行這個insert插入的時候sql_mode發生了更改了,這個時候我解析slave的relay log信息獲取得到 :
# at 271
#181019 12:13:00 server id 5403005 end_log_pos 319 CRC32 0x755a7204 GTID [commit=yes]
SET @@SESSION.GTID_NEXT= '8e91de47-8f0b-11e8-824c-246e9699bb48:1408667354'/*!*/;
# at 319
#181019 12:13:00 server id 5403005 end_log_pos 440 CRC32 0x1add7880 Query thread_id=47560669 exec_time=0 error_code=0
SET TIMESTAMP=1539922380/*!*/;
SET @@session.pseudo_thread_id=47560669/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1344274432/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=45/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 440
#181019 12:13:00 server id 5403005 end_log_pos 689 CRC32 0x1537384f Query thread_id=47560669 exec_time=0 error_code=0
use `finance_fixin_product`/*!*/;
SET TIMESTAMP=1539922380/*!*/;
.....
.....
.....
/*!*/;
可以很明顯的得到在上面binlog中有一個 SET @@session.sql_mode=1344274432/!/; 操作,那麼這操作將賦予sql_mode什麼值呢?
mysql> SET @@session.sql_mode=1344274432;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@global.sql_mode;
+--------------------------------------------+
| @@global.sql_mode |
+--------------------------------------------+
| NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+
1 row in set (0.00 sec)
mysql> select @@sql_mode;
+----------------------------------------------------------------+
| @@sql_mode |
+----------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
執行操作之後,突然發現sql_mode多出來一個STRICT_TRANS_TABLES,這個時候大致可以獲取得到端倪了,因爲在binlog在執行這條SQL的設置了session的sql_mode爲嚴格模式,所以導致在sql_thread重放的時候出現了這個問題。
但是這個時候又冒出了一個新的問題,因爲線上的表結構和架構和測試環境一模一樣,並且線上運行了這麼久的時間也沒有出現這個問題,帶着這個疑問我再次解析了線上binlog的日誌信息:
#181101 10:12:26 server id 5403005 end_log_pos 420 CRC32 0x2fe38b78 Query thread_id=51519927 exec_time=0 error_code=0
SET TIMESTAMP=1541038346/*!*/;
SET @@session.pseudo_thread_id=51519927/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1344274432/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=45/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 420
#181101 10:12:26 server id 5403005 end_log_pos 538 CRC32 0xb848f658 Table_map: `finance_fixin_cgb_gateway`.`t_cgb_receive_message` mapped to number 2056756
# at 538
#181101 10:12:26 server id 5403005 end_log_pos 740 CRC32 0x42756468 Write_rows: table id 2056756 flags: STMT_END_F
### INSERT INTO
### SET
### @1=5300431
### @2='PA0052'
### @3='b0009201811010033433728'
### @4='10.201.5.129'
### @5=2433
### @6='128'
### @7='0009a201811010143659612590571520'
### @8='000920180907OR23805082566791168'
### @9='0'
### @10='0000'
### @11='0000-操作成功。'
### @12='2018-11-01 10:12:26'
### @13='2018-11-01 10:12:26'
# at 740
#181101 10:12:26 server id 5403005 end_log_pos 771 CRC32 0xf5516de4 Xid = 12837058229
COMMIT/*!*/;
對比之後發現,線上的binlog格式是ROW格式,並且通過查看insert語句發現在insert插入的時候沒有默認值會默認設置爲' ',所以slave是不會報錯的。
解決問題
這個時候提出了倆個方案:
- 更改表結構,允許爲NULL
- 設置master的binlog爲ROW格式
最後和開發溝通之後還是選擇了第一個方案,修改表結構,主要是binlog格式的修改,必須先要斷開所有的鏈接,所以綜合考慮直接修改了表結構。
補充:
在binlog爲statement的時候解析了發現了一條SET TIMESTAMP=1539922380語句,之前一直認爲在statement格式下面使用時間函數會導致主從數據不一致,現在看到這個SQL,發現並不出現這種情況。