偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

好險!一入職,就遇到MySQL這么大Bug!差點背鍋走人...

數(shù)據(jù)庫 MySQL
今年這種情況,有時候不找好下家還真不敢跳,這不,前段時間剛跳到新東家,剛辦入職那天,就遇上事了,真的是嚇出一身冷汗(老大一直盯著我,說要快速解決這個問題),差點被(背)開(鍋)了....

今年這種情況,有時候不找好下家還真不敢跳,這不,前段時間剛跳到新東家,剛辦入職那天,就遇上事了,真的是嚇出一身冷汗(老大一直盯著我,說要快速解決這個問題),差點被(背)開(鍋)了....

情況如何?且聽我下面慢慢道來?。?!希望對大家有所幫助與借鑒。

問題描述

線上有個重要Mysql客戶的表在從5.6升級到5.7后,master上插入過程中出現(xiàn)"Duplicate key"的錯誤,而且是在主備及RO實例上都出現(xiàn)。

以其中一個表為例,遷移前通過“show create table” 命令查看的auto increment id為1758609, 遷移后變成了1758598,實際對遷移生成的新表的自增列用max求最大值為1758609。

用戶采用的是Innodb引擎,而且據(jù)運維同學介紹,之前碰到過類似問題,重啟即可恢復正常。

內(nèi)核問題排查

由于用戶反饋在5.6上訪問正常,切換到5.7后就報錯。因此,首先得懷疑是5.7內(nèi)核出了問題,因此第一反應是從官方bug list中搜索一下是否有類似問題存在,避免重復造車。經(jīng)過搜索,發(fā)現(xiàn)官方有1個類似的bug,這里簡單介紹一下該bug。

背景知識1

Innodb引擎中的auto increment 相關(guān)參數(shù)及數(shù)據(jù)結(jié)構(gòu)。

主要參數(shù)包括:innodb_autoinc_lock_mode用于控制獲取自增值的加鎖方式,auto_increment_increment, auto_increment_offset用于控制自增列的遞增的間隔和起始偏移。

主要涉及的結(jié)構(gòu)體包括:數(shù)據(jù)字典結(jié)構(gòu)體,保存整個表的當前auto increment值以及保護鎖;事務(wù)結(jié)構(gòu)體,保存事務(wù)內(nèi)部處理的行數(shù);handler結(jié)構(gòu)體,保存事務(wù)內(nèi)部多行的循環(huán)迭代信息。

背景知識2

mysql及Innodb引擎中對autoincrement訪問及修改的流程

  •  (1) 數(shù)據(jù)字典結(jié)構(gòu)體(dict_table_t)換入換出時對autoincrement值的保存和恢復。換出時將autoincrement保存在全局的的映射表中,然后淘汰內(nèi)存中的dict_table_t。換入時通過查找全局映射表恢復到dict_table_t結(jié)構(gòu)體中。相關(guān)的函數(shù)為dict_table_add_to_cache及dict_table_remove_from_cache_low。
  •  (2) row_import, table truncate過程更新autoincrement。
  •  (3) handler首次open的時候,會查詢當前表中最大自增列的值,并用最大列的值加1來初始化表的data_dict_t結(jié)構(gòu)體中的autoinc的值。
  •  (4) insert流程。相關(guān)對autoinc修改的堆棧如下: 
  1. ha_innobase::write_row:write_row的第三步中調(diào)用handler句柄中的update_auto_increment函數(shù)更新auto increment的值。  
  2. handler::update_auto_increment: 調(diào)用Innodb接口獲取一個自增值,并根據(jù)當前的auto_increment相關(guān)變量的值調(diào)整獲取的自增值;同時設(shè)置當前handler要處理的下一個自增列的值。  
  3. ha_innobase::get_auto_increment:獲取dict_tabel中的當前auto increment值,并根據(jù)全局參數(shù)更新下一個auto increment的值到數(shù)據(jù)字典中  
  4. ha_innobase::dict_table_autoinc_initialize:更新auto increment的值,如果指定的值比當前的值大,則更新。  
  5. handler::set_next_insert_id:設(shè)置當前事務(wù)中下一個要處理的行的自增列的值。 
  •  (5) update_row。對于”INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE”語句,無論唯一索引列所指向的行是否存在,都需要推進auto increment的值。相關(guān)代碼如下: 
  1. if (error == DB_SUCCESS  
  2.     && table->next_number_field  
  3.     && new_row == table->record[0]  
  4.     && thd_sql_command(m_user_thd) == SQLCOM_INSERT  
  5.     && trx->duplicates)  {  
  6.     ulonglong    auto_inc; 
  7.        ……  
  8.     auto_inc = table->next_number_field->val_int();  
  9.     auto_inc = innobase_next_autoinc(auto_inc, 1, increment, offset, col_max_value);  
  10.     error = innobase_set_max_autoinc(auto_inc); 
  11.         ……  

從我們的實際業(yè)務(wù)流程來看,我們的錯誤只可能涉及insert及update流程。 

  1. BUG 76872 / 88321: "InnoDB AUTO_INCREMENT produces same value twice" 
  •  (1) bug概述:當autoinc_lock_mode大于0,且auto_increment_increment大于1時,系統(tǒng)剛重啟后多線程同時對表進行insert操作會產(chǎn)生“duplicate key”的錯誤。
  •  (2) 原因分析:重啟后innodb會把autoincrement的值設(shè)置為max(id) + 1。

此時,首次插入時,write_row流程會調(diào)用handler::update_auto_increment來設(shè)置autoinc相關(guān)的信息。首先通過ha_innobase::get_auto_increment獲取當前的autoincrement的值(即max(id) + 1),并根據(jù)autoincrement相關(guān)參數(shù)修改下一個autoincrement的值為next_id。

當auto_increment_increment大于1時,max(id) + 1 會不大于next_id。handler::update_auto_increment獲取到引擎層返回的值后為了防止有可能某些引擎計算自增值時沒有考慮到當前auto increment參數(shù),會重新根據(jù)參數(shù)計算一遍當前行的自增值,由于Innodb內(nèi)部是考慮了全局參數(shù)的,因此handle層對Innodb返回的自增id算出的自增值也為next_id,即將會插入一條自增id為next_id的行。

handler層會在write_row結(jié)束的時候根據(jù)當前行的值next_id設(shè)置下一個autoincrement值。如果在write_row尚未設(shè)置表的下一個autoincrement期間,有另外一個線程也在進行插入流程,那么它獲取到的自增值將也是next_id。這樣就產(chǎn)生了重復。

  •  (3) 解決辦法:引擎內(nèi)部獲取自增列時考慮全局autoincrement參數(shù),這樣重啟后第一個插入線程獲取的自增值就不是max(id) + 1,而是next_id,然后根據(jù)next_id設(shè)置下一個autoincrement的值。由于這個過程是加鎖保護的,其他線程再獲取autoincrement的時候就不會獲取到重復的值。

通過上述分析,這個bug僅在autoinc_lock_mode > 0 并且auto_increment_increment > 1的情況下會發(fā)生。實際線上業(yè)務(wù)對這兩個參數(shù)都設(shè)置為1,因此,可以排除這個bug造成線上問題的可能性。

現(xiàn)場分析及復現(xiàn)驗證

既然官方bug未能解決我們的問題,那就得自食其力,從錯誤現(xiàn)象開始分析了。

(1) 分析max id及autoincrement的規(guī)律 由于用戶的表設(shè)置了ON UPDATE CURRENT_TIMESTAMP列,因此可以把所有的出錯的表的max id、autoincrement及最近更新的幾條記錄抓取出來,看看是否有什么規(guī)律。抓取的信息如下:

乍看起來,這個錯誤還是很有規(guī)律的,update time這一列是最后插入或者修改的時間,結(jié)合auto increment及max id的值,現(xiàn)象很像是最后一批事務(wù)只更新了行的自增id,沒有更新auto increment的值。

聯(lián)想到【官方文檔】中對auto increment用法的介紹,update操作是可以只更新自增id但不觸發(fā)auto increment推進的。按照這個思路,我嘗試復現(xiàn)了用戶的現(xiàn)場。復現(xiàn)方法如下:

同時在binlog中,我們也看到有update自增列的操作。如圖:

不過,由于binlog是ROW格式,我們也無法判斷這是內(nèi)核出問題導致了自增列的變化還是用戶自己更新所致。因此我們聯(lián)系了客戶進行確認,結(jié)果用戶很確定沒有進行更新自增列的操作。

那么這些自增列到底是怎么來的呢?

(2) 分析用戶的表及sql語句 繼續(xù)分析,發(fā)現(xiàn)用戶總共有三種類型的表 

  1. hz_notice_stat_sharding  
  2. hz_notice_group_stat_sharding  
  3. hz_freeze_balance_sharding 

這三種表都有自增主鍵。

但是前面兩種都出現(xiàn)了autoinc錯誤,唯獨hz_freeze_balance_sharding表沒有出錯。難道是用戶對這兩種表的訪問方式不一樣?抓取用戶的sql語句,果然,前兩種表用的都是replace into操作,最后一種表用的是update操作。難道是replace into語句導致的問題?搜索官方bug, 又發(fā)現(xiàn)了一個疑似bug。 

  1. bug #87861: “Replace into causes master/slave have different auto_increment offset values” 

原因:

  •  (1) Mysql對于replace into實際是通過delete + insert語句實現(xiàn),但是在ROW binlog格式下,會向binlog記錄update類型日志。Insert語句會同步更新autoincrement,update則不會。
  •  (2) replace into在Master上按照delete+insert方式操作, autoincrement就是正常的?;赗OW格式復制到slave后,slave機上按照update操作回放,只更新行中自增鍵的值,不會更新autoincrement。

因此在slave機上就會出現(xiàn)max(id)大于autoincrement的情況。此時在ROW模式下對于insert操作binlog記錄了所有的列的值,在slave上回放時并不會重新分配自增id,因此不會報錯。但是如果slave切master,遇到Insert操作就會出現(xiàn)”Duplicate key”的錯誤。

  •  (3) 由于用戶是從5.6遷移到5.7,然后直接在5.7上進行插入操作,相當于是slave切主,因此會報錯。

解決方案

業(yè)務(wù)側(cè)的可能解決方案:

  •  (1) binlog改為mixed或者statement格式。
  •  (2) 用Insert on duplicate key update代替replace into。

內(nèi)核側(cè)可能解決方案:

  •  (1) 在ROW格式下如果遇到replace into語句,則記錄statement格式的logevent,將原始語句記錄到binlog。
  •  (2) 在ROW格式下將replace into語句的logevent記錄為一個delete event和一個insert event。

心得

  •  (1) autoincrement的autoinc_lock_mode及auto_increment_increment這兩個參數(shù)變化容易導致出現(xiàn)重復的key,使用過程中要盡量避免動態(tài)的去修改。
  •  (2) 在碰到線上的問題時,首先應該做好現(xiàn)場分析,明確故障發(fā)生的場景、用戶的SQL語句、故障發(fā)生的范圍等信息,同時要對涉及實例的配置信息、binlog甚至實例數(shù)據(jù)等做好備份以防過期丟失。

只有這樣才能在找官方bug時精準的匹配場景,如果官方?jīng)]有相關(guān)bug,也能通過已有線索獨立分析。 

責任編輯:龐桂玉 來源: java版web項目
相關(guān)推薦

2020-04-08 07:55:08

MySQLSLA數(shù)據(jù)

2021-05-17 08:11:44

MySQL數(shù)據(jù)庫索引

2019-12-03 13:57:38

CIO背鍋IT

2021-07-19 08:41:49

藍屏用戶Bug

2022-12-28 10:52:34

Etcd備份

2022-12-09 09:43:41

前端測試

2021-10-08 07:50:57

軟件設(shè)計程序

2017-09-25 10:52:27

2024-04-22 00:00:01

Redis集群

2019-09-17 10:31:51

崗位產(chǎn)品程序員

2018-12-26 17:36:37

開發(fā)者技能阿里

2020-06-16 18:09:54

Windows 10Windows電池驅(qū)動

2019-01-16 18:11:28

程序員技能開發(fā)者

2019-01-04 10:13:22

蘋果中國市場iPhone

2018-10-19 16:35:20

運維

2025-03-28 09:22:33

2019-12-10 10:28:47

運維架構(gòu)技術(shù)

2017-09-12 16:18:22

ICO區(qū)塊鏈互聯(lián)網(wǎng)+

2020-04-09 10:43:12

長事務(wù)P0故障

2021-04-30 07:09:48

SQLP0事故
點贊
收藏

51CTO技術(shù)棧公眾號