Sequelize 事務大併發下形成的死鎖問題

Author: bugall
Wechat: bugallF
Email: 769088641@qq.com
Github: https://github.com/bugallmysql

  • 環境git

  • Mysql 5.6 InnoDBgithub

一.聲明

這並非sequelize的bug,在涉及到connection pool的時候都有可能出現這個問題sql


二.原由

咱們有個須要事物的業務場景,上線之初一直運行正常,但是在晚上高峯的時候一直會有邏輯錯誤的問題,剛開始以爲是邏輯有問題。
後來查看innodb才發現出現大量的鎖,主表的某些數據行持有鎖不釋放,其它的sql一直等待,直到業務服務器報deadlock。由於主表其它業務模塊也會用到,因此是一個比較緊急的狀況數據庫


三.錯誤的代碼

代碼能夠簡寫爲:json

DBSequelize.transaction({autocommit:false,isolationLevel:'SERIALIZABLE'}).then(function(t){
    return db.Tuser.create({...},{transaction:t});
}).then(function(trans){
    return db.TuserRelation.update({...},{where:{...},transaction:t})
}).then(function(trans){
    return db.Twork.update({...},{where:{...}})
}).then(function(result){
    t.commit(res.json(result));
})

大概意思就是若是用戶註冊了一個帳號,就在帳號關係裏增長一個記錄這兩個操做是原子的。沒併發的狀況下,這個邏輯執行是沒有問題的,可是一旦有併發就會出問題。服務器


四.分析錯誤

首先在建立事務的時候咱們指定了兩個參數」不自動提交「,」一致性讀「。(咱們這裏但願對一條數據讀的時候加X鎖,事務級別可是問題不大,最可能是影響數據庫的併發性能,
對於主表來講加X鎖是一個很愚蠢的作法),問題關鍵是出如今不自動提交設置這裏。
剛開始我對事務理解就是:只有咱們主動執行commit的時候纔會把buffer cache的髒數據寫入磁盤並釋放事務裏持有的鎖。
可是真是狀況不是這樣的。在mysql官方文檔中找到了關於autocommit transaction相關描述session

By default, MySQL runs with autocommit mode enabled. This means that as soon as you execute a statement that updates (modifies) a table, MySQL stores the update on disk to make it permanent. The change cannot be rolled back.

To disable autocommit mode implicitly for a single series of statements, use the START TRANSACTION statement:

START TRANSACTION;
SELECT @A:=SUM(salary) FROM table1 WHERE type=1;
UPDATE table2 SET summary=@A WHERE type=1;
COMMIT;

With START TRANSACTION, autocommit remains disabled until you end the transaction with COMMIT or ROLLBACK. The autocommit mode then reverts to its previous state.

這裏有幾個概念能夠明確:併發

1. autocommit的設定是針對session的(一個數據庫鏈接),若是你對這個這個鏈接設定了autocommit=1那麼這個鏈接
   執行的全部sql都會自動commit,反之不會自動提交必須手動commit提交
2. 不管鏈接設置的autocommit是什麼狀態,在執行事務時候事務裏的autocommit狀態都會被隱式的設置爲0,當事物執行
   完成後autocommit會被設置爲原先的狀態(執行事務前)

因此咱們的問題出如今建立事務時候的{tautocommit=false}這個參數實際上是對鏈接設置的,而不是事務。
在併發的狀況下,sequelize鏈接池的鏈接是會複用的,假如一個執行了事務的鏈接去執行其它的DML語句,這些語句是不會提交的
也就是說數據行的鎖不釋放,其它請求設計到該條數據的時候將會被阻塞,直到超時。性能


五.解決

咱們只需在事務參數中設定autocommit=true就好了。須要注意的時候在Isolation的級別是一致性讀的時候,由於該級別違反了MVCC規範,因此這時候的autocommit=true/false是要分狀況討論的。這裏不是sequelize的問題,在用到connection pool對innodb進行操做的時候應該注意這個狀況。

相關文章
相關標籤/搜索