公司一個線上招聘項目,后端采用Django開發,數據庫使用MySQL。最近一次線上招聘會活動,因短時間大量用戶涌入,被吐槽服務響應時間過長。后端和運維人員經排查,定位到MySQL數據庫有死鎖
根據錯誤日志,發現產生死鎖的有4個接口。這4個接口中,閱讀業務代碼,發現均有使用update_or_create。為什么update_or_create方法會造成死鎖呢?通過閱讀源碼
發現,update_or_create是使用了事務with transaction.atomic(using=self.db)並select_for_update。而mysql事務中,FOR UPDATE中的WHERE篩選語句如果有查詢m沒有索引字段或者索引未生效,將產生表鎖,否則將產生行鎖(參考https://www.cnblogs.com/wangshiwen/p/9837408.html)。
閱讀事故日志4個接口的代碼中使用的update_or_create中涉及到的查詢,發現索引字段。因此每個接口請求將鎖住業務涉及到的表,而短時間大量用戶涌入造成了MySQL死鎖的產生。
參考:
https://haicoder.net/note/mysql-interview/mysql-interview-mysql-select-for-update.html
https://www.cnblogs.com/jpfss/p/9225453.html
https://www.cnblogs.com/wangshiwen/p/9837408.html