1. 程式人生 > >關於Inception默認配置的一個坑

關於Inception默認配置的一個坑

logs 關於 問題 -o 小時 產生 lena 限制 正常

約半年前上線了去哪兒的開源審核工具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

關於Inception默認配置的一個坑