Domanda

Sto cercando una buona strategia per gestire i deadlock del database dall'interno di un'applicazione Java 6;diversi thread paralleli potrebbero, potenzialmente, scrivere nella stessa tabella contemporaneamente.Il database (Ingres RDMBS) ucciderà casualmente una delle sessioni se rileva un deadlock.

Quale sarebbe una tecnica accettabile per affrontare la situazione di stallo, dati i seguenti requisiti?

  • Il tempo totale trascorso dovrebbe essere mantenuto il più piccolo ragionevolmente possibile
  • Uccidere una sessione dovrà sostenere un rollback significativo (misurabile)
  • i thread del tempo non hanno modo di farlo
    comunicare tra loro, ad es.La strategia dovrebbe essere autonoma

Finora, la strategia che ho ideato è qualcosa del genere:

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
    try {
        //insert loads of records in table 'x'
        success = true;
    } catch (ConcurrencyFailureException e) {
        attempts++;
        success = false;
        delayMs = 1000*attempts+random.nextInt(1000*attempts);

        try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
        }
    }
} while (!success);

Si può migliorare in qualche modo?per esempio.aspettando un numero fisso (numero magico) di secondi.Esiste una strategia diversa che produrrà risultati migliori?

Nota: Verranno utilizzate diverse tecniche a livello di database per garantire che i deadlock siano, nella pratica, molto rari.Inoltre, l'applicazione tenterà di evitare la pianificazione dei thread che scrivono nella stessa tabella contemporaneamente.La situazione di cui sopra sarà solo uno “scenario peggiore”.

Nota: La tabella in cui vengono inseriti i record è organizzata come tabella partizionata heap e non ha indici;ogni thread inserirà i record nella propria partizione.

È stato utile?

Soluzione

Un approccio comunemente usato è una qualche forma di esponenziale back-off. Piuttosto che il vostro aproach 1000*attempts+random, fare il ritardo una funzione esponenziale del numero di tentativi. Ciò garantisce una latenza minima nei primi uno o due tentativi, in cui potrebbe avere appena stata sfortuna che si in fase di stallo, ma ti dà molto più grandi ritardi in seguito, quando è chiaro che la connessione in realtà è congestionata.

Naturalmente, un altro approccio sarebbe quello di cercare di organizzare il vostro database di accessi in modo che situazioni di stallo hanno meno probabilità di verificarsi. Ma senza sapere cosa fanno le vostre domande (e come, e quando sono eseguiti), è impossibile dire se questo può essere fatto

Altri suggerimenti

Questo è il modo in cui l'abbiamo fatto. Loop e ripetere l'operazione fino a quando non finisce.

Non abbiamo fatto confusione con ritardi casuali.

Inoltre, abbiamo il commit all'interno del blocco try e il rollback nel gestore di eccezioni.

Quando si dispone di più risorse con serratura e molteplici transazioni concorrenti, situazione di stallo è inevitabile. Si tratta di una conseguenza logica di contesa per serrature.

Se evitare contesa per serrature (cioè bloccaggio pessimistica livello di tabella) allora si tende anche a prevenire concorrenza. Se è possibile definire un'operazione che non sostengono per serrature, si può evitare di stallo. l'accesso concorrente allo stesso tavolo, però, è più o meno la definizione di situazione di stallo.

Quando si carica, inserti (especial in una tabella di heap) possono (spesso) procedere in parallelo senza molti problemi contesa. Se si ritarda la costruzione degli indici, quindi non ci sono altri aggiornamenti in corso durante l'inserto.

Quindi, si può essere in grado di evitare facendo cadere gli indici, cambiando l'organizzazione ad un cumulo, caricando con più processi concorrenti (o thread, di solito è più veloce di avere più processi), quindi creare l'indici (ed eventualmente riorganizzare il tabella), si può essere in grado di evitare situazioni di stallo.

Quando si esegue aggiornamenti o eliminazioni, aiuta a non molto.

Se non c'è bisogno di avere accesso simultaneo al database una soluzione semplice potrebbe essere quella di rimuoverlo e utilizzare una coda di elaborazione compito di aggiornare il database, invece, serializzazione accesso al database tramite la coda. Mi rendo conto che introdurrà un elemento asincrona per la vostra applicazione, e quindi non sarebbe adatto per la maggior parte delle applicazioni utente avviato o web-applicazioni online, ma potrebbe essere opportuno prendere in considerazione per un'applicazione di tipo lotto / offline (mi rendo conto che probabilmente non la risposta alla tua ricerca per però).

Con un database come Ingres otterrai sempre alcuni deadlock, quindi devi presumere che qualsiasi inserimento, aggiornamento o eliminazione fallirà e disporre di una strategia di ripetizione (come nel tuo esempio).Dovresti progettare il tuo database in modo che i conflitti siano ridotti al minimo e che i deadlock si verifichino solo raramente.Se continui a riscontrare transazioni che falliscono anche dopo diversi tentativi, allora questo è un segno che dovrai fare qualche importante riprogettazione del database (o passare a un sistema come Oracle dove di solito è possibile progettare applicazioni per evitare blocchi con un uso adeguato del blocco a livello di riga).

come è questo?

short attempts = 0;
boolean success = false;
long delayMs = 0;

Random random = new Random();
do {
try {
     synchronized(ClassName.class) {
         //insert loads of records in table 'x'
      }

    success = true;
} catch (ConcurrencyFailureException e) {
    attempts++;
    success = false;
    delayMs = 1000*attempts+random.nextInt(1000*attempts);

    try {
                    Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
    }
  }
} while (!success);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top