最近開發中遇到的一個MySQL主從延遲的坑,記錄並總結,避免再次犯一樣的錯誤。mysql
一個活動信息須要審批,審批以後才能生效。由於以後活動要編輯,編輯後也可能觸發審批,審批中展現的是編輯前的活動內容,考慮到字段比較多,也要保存審批活動的內容,所以設計採用了一張臨時表,審批中的活動寫進審批表(activity_tmp),審批經過以後才把真正的活動內容寫進活動表(activity)。表的簡要設計以下,這裏將活動內容字段合併爲content展現:sql
activity_tmp() id status // 審批狀態 content // 審批階段提交的活動內容 activity id content // 審批經過後真正展現的活動內容
當時是有編輯觸發審批的狀況,發現審批經過以後活動內容是空的,因而開始追查問題的緣由。這裏說一句,當程序出問題的時候,95%都是代碼的問題,先不要去懷疑環境出問題。好好的查日誌,而後看看你的代碼吧。數據庫
一、查activity_tmp表,發現當時提交審批的活動內容是正常的,並且狀態也更新爲審批經過了,懷疑是寫入activity表失敗
二、查activity表,發現審批後的內容確實沒有寫入,懷疑是代碼問題
三、查看代碼,代碼邏輯沒看出問題,懷疑數據庫操做失敗,查看日誌
四、日誌顯示,有一句insert語句的活動內容爲空,活動內容來自上一個mysql執行的是select語句,把該select語句拿出來放到線上的備庫查詢,發現活動內容是存在的。運行時查詢爲空,執行完畢後查詢時內容存在,初步懷疑是主從延遲問題。
五、報錯只是部分失敗,肯定是主從延遲的問題。架構
$intStatus = $arrInput[‘status’]; $this->objActTmp->updateInfoByAId($intActId, $intStatus); // 更新後,立刻查 $arrActContent = $this->objActTmp->getActByStatus($intStatus);
這就是主從延遲出現的地方,update後,立刻get,這是主從複製架構上開發的一個大忌。學習
這類問題的解決方案有兩種:this
修改代碼邏輯spa
修改系統架構設計
對於修改代碼邏輯,鄙人有兩點看法:日誌
若是第二步獲取的數據不須要第一步更新的status字段,那就先讀,而後再更新code
若是第二步獲取的數據須要依賴第一步的status字段,那就在讀出來的時候先判斷是否爲空,若是是空的,報錯,下一次重試。
其實以前也聽到過這樣的例子,可是因爲沒有親身經歷,因此只保留了一種理論上的記憶,實際上印象不深,經歷了這麼一次踩坑後,印象特別深入,如今看到別人寫這樣的代碼也能立刻發現並指出。仍是本身親身去踩坑印象最深。
日誌很重要,詳細的日誌更重要。日誌要記錄有用的信息,方便追查問題的時候去追溯問題的本質緣由。我以爲日誌就應該儘可能作成飛機中的黑匣子,幫助咱們保存「事故「發生時的全部相關信息。
接下來,會去學習主從複製的原理,敬請期待。
更多精彩內容,請關注我的公衆號。