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

關於Inception預設配置的一個坑

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