天天看點

關于Inception預設配置的一個坑

本文位址:https://www.cnblogs.com/ajiangg/p/9850902.html

約半年前上線了去哪兒的開源稽核工具Inception(最近發現已經閉源了.....)以及基于Inception的SQL稽核平台Yearning。

一直都用得很爽...直到昨天踩坑。

昨天晚上某個表A新加了一個字段,今早收到業務告警。最後從日志中發現類似如下報錯(B表的外鍵指向了不存在的表_A_old):

Cannot add or update a child row: a foreign key constraint fails (db.B, CONSTRAINT B_ibfk_2 FOREIGN KEY (A_id) REFERENCES _A_old (id))

至于為啥會有外鍵...這屬于曆史遺留問題。

第一反應,昨天加字段的時候Inception調用pt-osc出問題了,導緻外鍵沒有連結到新表上去。

既然pt-osc會有問題,那就老老實實直接删除外鍵,重加吧

alter table B drop foreign key B_ibfk_2,add constraint new_key FOREIGN KEY (A_id) REFERENCES A(id)

悲劇的是B表實在是太大,線上跑了一個小時也無果,于是Kill復原。

回過頭來研究為毛B表會指向利用pt-osc進行字段增加時的舊表_A_old呢?

先看看pt-osc關于外鍵的參數--alter-foreign-keys-method:

(1)auto

自動決定采用哪個方法,如果可以就采用rebuild_constraints,如果不可以就采用drop_swap

(2)rebuild_constraints

該方法采用alter table來drop并re-add連結新表的外鍵。除非相關的子表太大使得alter過程花費時間過長,一般都采用該方法。這裡的花費時間是通過比較子表中的行數和該工具将原始表資料拷貝到新表中的拷貝速率來評估的,如果評估後發現子表中資料能夠在少于--chunk-time的時間内alter完成,就會采用該方法。另外,因為在MySQL中alter table比外部拷貝資料的速率快很多,是以拷貝速率是按照--chunk-size-limit來決定的

因為MySQL的限制,外鍵在改表前後的名字會不一樣,改表後新表中的外鍵名前會加一個下劃線,同樣,會自動的更改外鍵相應的索引名字

(3)drop_swap

該方法禁止外鍵檢查(FOREIGN_KEY_CHECKS=0),然後在rename新表之前就将原始表drop掉,這個方法更快而且不會被阻塞,但是風險比較大,風險有二:

在drop掉原始表和rename新表之間有一個時間差,在這段時間裡這個表是不存在的,這會導緻查詢報錯

如果rename新表時發生了錯誤,那問題就大了,因為原始表已經被drop掉了,隻能呵呵了

(4)none

這個方法類似沒有"swap"的drop_swap,原始表中的所有外鍵都會被指定到一個不存在的表上

因為原始表(database.tablename)會被rename為database.tablename_old然後drop掉。這種處理外鍵的方法可以讓DBA在需要時取消該工具的這種内置功能

以下是我關于這些參數的測試結果(參數auto略過了):

1.有子表的表A使用最安全的--alter-foreign-keys-method=rebuild_constraints來進行線上更新時,

在copy完父表之後,子表進行更改的方式是alter table B drop foreign key old_key,add constraint new_key FOREIGN KEY (A_id) REFERENCES A(id)。如果子表B比較大,或者A表有好幾個子表,那麼我還有使用pt-osc的必要麼?(對線上的影響可能遠遠大于直接alter table A帶來的影響)

2.有子表的表A使用--alter-foreign-keys-method=none來進行線上更新時,

在copy完父表之後,資料庫是直接執行set FOREIGN_KEY_CHECKS=0,然後drop舊表_A_old,然後rename新表_A_new為A。然後就收工了。

是以子表B的外鍵指向的仍然是pt-osc運作過程中的那張原始父表_A_old

很顯然,Inception針對pt-osc的預設配置就是使用--alter-foreign-keys-method=none。

3.有子表的表A使用--alter-foreign-keys-method=drop_swap來進行線上更新時,

在copy完父表之後,資料庫是直接執行set FOREIGN_KEY_CHECKS=0,然後drop舊表_A_old,然後rename新表_A_new為_A_old,最後再rename為A。

這樣弄完之後父子表的關系仍然存在。(在rename_A_new為_A_old之後,drop舊表_A_old産生的錯誤指向就被帶回來了)

--------------------------------------------------------------------------------------解決方法-----------------------------------------------------------------------------------------------

既然rename表之後,子表的外鍵關系能跟着變,那麼最後線上問題的修正方法也就有了:

現在子表B的外鍵指向是一個不存在的表_A_old,那麼我把現在的A表rename成_A_old,外鍵關系聯系上了之後再重新rename回A表,不就好了麼:

alter table A rename _A_old;

alter table _A_old rename A;

經測試沒問題,秒恢複正常,然後線上執行OK。

最後回過頭來檢查Inception關于pt-osc對外鍵的配置發現:

inception_osc_alter_foreign_keys_method的預設配置是none(即它調用pt-osc的預設參數為--alter-foreign-keys-method=none),是以出現了外鍵指向不存在的表。

在這裡我将配置改成了drop_swap

--------------------------------------------------------------------------------------華麗麗的分割線-----------------------------------------------------------------------------------------------

最後的檢討:

資料庫有變更的時候,變更完成後需要對相關的業務進行檢查。這次雖然我們業務告警系統也在變更之後立即告警了,但卻當成“狼來了”給略過了,此處需向老闆好好檢討......

關于外鍵,一直都是抵制的。對于新表,新需求一直都禁止使用外鍵。但舊的系統,很難推動去改掉它。

以前對于外鍵的一些細節,總是想着反正不會用到,是以遇到這樣的細節直接就跳過了。

現在看來,雖然可能一般不會碰到,但這些細節還是需要好好的去了解掌握。

本文位址:https://www.cnblogs.com/ajiangg/p/9850902.html