2016-01-27 15 views
9

Ho a che fare con un promblem per un paio di giorni, e spero davvero che tu possa aiutarmi.Gestione transazioni rollback MySQL in Node.js

È un'API basata su node.js che utilizza sequelize per MySQL.

Su alcune chiamate API il codice inizia SQL transazioni che bloccano determinate tabelle e se invio più richieste contemporaneamente all'API, ho ricevuto errori LOCK_WAIT_TIMEOUT.

var SQLProcess = function() { 
    var self = this; 
    var _arguments = arguments; 

    return sequelize.transaction(function (transaction) { 
      return doSomething({transaction: transactioin}); 
     }) 
     .catch(function (error) { 
      if (error && error.original && error.original.code === 'ER_LOCK_WAIT_TIMEOUT') { 

       return Promise.delay(Math.random() * 1000) 
        .then(function() { 
         return SQLProcess.apply(self, _arguments); 
        }); 

      } else { 
       throw error; 
      } 
     }); 
}; 

Il mio problema è, le richieste in esecuzione contemporaneamente si bloccano a vicenda per un lungo periodo di tempo, e la mia richiesta ritorna dopo un lungo lungo tempo (~ 60 secondi).

Spero di poterlo spiegare in modo chiaro e comprensibile e potresti offrirmi qualche soluzione.

+0

Questo non è un problema 'node.js' o' sequelize', è un messaggio di errore di MySQL '1205 Lock wait timeout exceeded; prova a riavviare la transazione ». Dovresti esaminare le transazioni e i loro stati all'interno del server MySQL. –

+0

È assolutamente chiaro, perché ottengo questo errore. Sto cercando una soluzione su come potrei gestirla. – Adam

+0

C'è solo un modo per capire cosa succede ed è 'SHOW ENGINE INNODB STATUS \ G'. Nella mia esperienza, ho avuto transazioni con blocchi fissi in MySQL più volte. –

risposta

3

Questa potrebbe non essere una risposta diretta alla tua domanda, ma forse guardando perché hai avuto questo problema sarebbe stato d'aiuto.

1) Che cosa fa DoSomething()? Ad ogni modo possiamo fare dei miglioramenti lì?

In primo luogo, una transazione che richiede 60 secondi è sospetta. Se si blocca una tabella per così tanto tempo, è probabile che il progetto venga rivisitato. Data una tipica operazione db, viene eseguito da 10 a 100 ms.

Idealmente, tutta la preparazione dei dati deve essere eseguita al di fuori della transazione, compresi i dati letti dal database. E la transazione dovrebbe essere davvero solo per operazioni transazionali.

2) È possibile utilizzare la stored procedure mysql?

Vero, la stored procedure per mysql non è compilata, come PL/SQL per Oracle. Ma è ancora in esecuzione sul server di database. Se la tua applicazione è davvero complicata e contiene molto back e forza il traffico di rete tra il database e l'applicazione del nodo in quella transazione, e considerando che ci sono così tanti livelli di chiamate javascript, potrebbe davvero rallentare le cose. Se 1) non ti fa risparmiare molto tempo, considera l'uso della procedura memorizzata mysql.

Lo svantaggio di questo approccio, ovviamente, è che è più difficile mantenere i codici sia in nodejs che in mysql.

Se 1) e 2) non sono assolutamente possibili, è possibile prendere in considerazione una sorta di controllo di flusso o strumento di accodamento. O la tua app si accerta che la seconda richiesta non vada fino a quando non termina la prima, o se hai qualche strumento di accodamento di terze parti per gestirlo. Sembra che non sia necessario alcun parallelismo nell'esecuzione di tali richieste.

+0

Grazie! Lo strumento di messa a punto lo ha fatto! Ho impostato una 'bluebird-queue' e ora tutte le richieste si ripetono una dietro l'altra senza bloccare. – Adam

2

Il motivo principale di deadlock è la progettazione del database insufficiente. Senza ulteriori informazioni sulla struttura del database e su quali query esatte si potrebbero bloccare o meno, è impossibile fornire una soluzione specifica per il problema.

Tuttavia posso darvi un consiglio generale/approccio per risolvere questo problema:

  • vorrei fare in modo che il database è normalized almeno in terza forma normale o, se questo ancora non è abbastanza ancora di più. Potrebbero esserci strumenti per automatizzare questo processo per te.

    Oltre a ridurre la probabilità di deadlock, ciò aiuta anche a mantenere i dati coerenti, che è sempre una buona cosa.
  • Mantieni le tue transazioni il più possibile snelle. Se si inseriscono nuove righe nelle tabelle e si aggiornano di conseguenza altre tabelle, si consiglia di utilizzare un trigger piuttosto che un'altra istruzione SQL per farlo. Lo stesso vale per la lettura di righe e valori. Tali cose possono essere fatte prima o dopo la transazione.
  • Scegliere il livello di isolamento corretto. I possibili livelli di isolamento sono:

    READ_UNCOMMITTED
    READ_COMMITTED
    REPEATABLE_READ
    SERIALIZABLE

    di official documentation Sequelize descrive come è possibile impostare il livello di isolamento e bloccare/sbloccare le operazioni da soli.



Come ho detto, senza ulteriori indicazioni circa la vostra base di dati e query questo è tutto quello che posso fare per te in questo momento.
Spero che questo aiuti.

Problemi correlati