Blocco ottimistico vs. pessimistico


572

Comprendo le differenze tra blocco ottimistico e pessimistico. Ora qualcuno potrebbe spiegarmi quando avrei usato uno dei due in generale?

E la risposta a questa domanda cambia a seconda che io stia usando o meno una procedura memorizzata per eseguire la query?

Ma solo per verificare, ottimista significa "non bloccare la tabella durante la lettura" e pessimistico significa "bloccare la tabella durante la lettura".



1
Questa è una buona domanda soprattutto perché nella serializzabilità ho letto At any technique type conflicts should be detected and considered, with similar overhead for both materialized and non-materialized conflicts.
Little Alien,

1
Qui puoi trovare una buona spiegazione, qui su SO, su quale sia il concetto alla radice di Optimistic Locking .
Diego Mazzaro,

Risposte:


812

Il blocco ottimistico è una strategia in cui leggi un record, prendi nota di un numero di versione (altri metodi per farlo includono date, timestamp o checksum / hash) e verifica che la versione non sia cambiata prima di riscrivere il record. Quando si riscrive il record, si filtra l'aggiornamento sulla versione per assicurarsi che sia atomico. (ovvero non è stato aggiornato tra quando si controlla la versione e si scrive il record sul disco) e si aggiorna la versione in un colpo solo.

Se il record è sporco (ovvero versione diversa dalla tua), interrompi la transazione e l'utente può riavviarla.

Questa strategia è maggiormente applicabile ai sistemi ad alto volume e alle architetture a tre livelli in cui non si mantiene necessariamente una connessione al database per la sessione. In questa situazione il client non può effettivamente mantenere i blocchi del database poiché le connessioni vengono prese da un pool e potresti non utilizzare la stessa connessione da un accesso al successivo.

Il blocco pessimistico è quando si blocca il record per uso esclusivo fino a quando non si è finito con esso. Ha un'integrità molto migliore rispetto al blocco ottimistico, ma richiede di stare attenti con il design dell'applicazione per evitare deadlock . Per utilizzare il blocco pessimistico è necessaria una connessione diretta al database (come in genere accade in un'applicazione server client a due livelli ) o un ID transazione disponibile esternamente che può essere utilizzato indipendentemente dalla connessione.

In quest'ultimo caso, si apre la transazione con il TxID e quindi si riconnette utilizzando tale ID. Il DBMS mantiene i blocchi e consente di riprendere il backup della sessione tramite TxID. Ecco come funzionano le transazioni distribuite che utilizzano protocolli di commit a due fasi (come Transazioni XA o COM + ).


148
Il blocco ottimistico non utilizza necessariamente un numero di versione. Altre strategie includono l'uso di (a) un timestamp o (b) l'intero stato della riga stessa. Quest'ultima strategia è brutta ma evita la necessità di una colonna di versione dedicata, nei casi in cui non è possibile modificare lo schema.
Andrew Swan,

2
@geek: protocolli di transazione distribuiti come XA consentono di reticolare un identificatore di transazione separato su uno o più sistemi. Questo tipo di protocollo consente di utilizzare i blocchi tramite connessioni in pool poiché l'identificatore di transazione viene disaccoppiato dalle sessioni e fornito esplicitamente. Tuttavia, ciò comporta un certo sovraccarico ed è soggetto a blocchi di perdite e identificatori di transazione se l'applicazione non è scrupolosa nel tenerne traccia. È una soluzione molto più pesante.
Preoccupato di

22
@supercat - Non concordare sul fatto che il blocco ottimistico sia accurato meno del 100% - purché controlli tutti i record di input per le transazioni che dovrebbero rimanere non modificate per la durata, è accurato come il blocco pessimistico (selezionare per lo stile di aggiornamento) su quelli stessi record. La differenza principale è che il blocco ottimistico comporta un sovraccarico solo in caso di conflitto, mentre il blocco pessimistico ha ridotto il sovraccarico in caso di conflitto. Quindi l'ottimista è il migliore nel caso in cui la maggior parte delle transazioni non sia in conflitto, cosa che spero sia la maggior parte delle app.
RichVel,

2
@Legends - L'uso del blocco optimsitic sarebbe sicuramente una strategia appropriata per un'applicazione web.
Preoccupato di

2
Dovresti dire che la scelta dipende anche dal rapporto lettura / scrittura: se la tua applicazione è principalmente un'applicazione di sola lettura di molti utenti, e talvolta scrivi dati, allora vai per un blocco ottimistico. StackOverflow, ad esempio, ha molte persone che leggono le pagine, e talvolta qualcuno ne modifica una: con il blocco pessimistico, chi otterrebbe il blocco? il primo? Nel blocco ottimistico, la persona che desidera modificare la pagina può farlo fintanto che ne ha l'ultima versione.
jehon,

177

Il blocco ottimistico viene utilizzato quando non si prevedono molte collisioni. Costa meno per fare una normale operazione ma se si verifica la collisione pagheresti un prezzo più alto per risolverlo quando la transazione viene interrotta.

Il blocco pessimistico viene utilizzato quando è prevista una collisione. Le transazioni che violerebbero la sincronizzazione sono semplicemente bloccate.

Per selezionare il meccanismo di blocco corretto, è necessario stimare la quantità di letture e scritture e pianificare di conseguenza.


Nel caso normale, l'affermazione è perfetta, ma in casi speciali in cui è possibile gestire l' operazione CAS consentendo inesattezze come @skaffman menzionato nella risposta, direi che dipende davvero.
Sentito

75

L'ottimista presume che nulla cambierà mentre lo stai leggendo.

Il pessimista presume che qualcosa lo farà e quindi lo blocca.

Se non è essenziale che i dati vengano letti perfettamente, utilizzare l'ottimismo. Potresti ottenere la strana lettura "sporca", ma è molto meno probabile che si traduca in deadlock e simili.

La maggior parte delle applicazioni web va bene con letture sporche: in rare occasioni i dati non corrispondono esattamente al ricaricamento successivo.

Per operazioni esatte sui dati (come in molte transazioni finanziarie) utilizzare pessimisti. È essenziale che i dati vengano letti in modo accurato, senza modifiche non mostrate: ne vale la pena l'overhead di blocco aggiuntivo.

Oh, e il server Microsoft SQL ha come impostazione predefinita il blocco della pagina, in pratica la riga che stai leggendo e alcuni lati. Il blocco delle file è più preciso ma molto più lento. Spesso vale la pena impostare le transazioni su read-commit o no-lock per evitare deadlock durante la lettura.


Il blocco ottimistico di JPA consente di garantire coerenza nella lettura.
Gili,

4
La coerenza della lettura è una preoccupazione separata: con PostgreSQL, Oracle e molti altri database, si ottiene una visione coerente dei dati indipendentemente da eventuali aggiornamenti non ancora impegnati e non sono interessati nemmeno da blocchi di riga esclusivi.
RichVel

Sono d'accordo con @RichVel. Da un lato, posso vedere in che modo il blocco pessimistico potrebbe impedire letture errate se il livello di isolamento della transazione è READ UNCOMMITTED. Ma è fuorviante affermare che il blocco ottimistico è suscettibile alle letture sporche senza menzionare che la maggior parte dei database (incluso apparentemente MS SQL Server) hanno un livello di isolamento predefinito di "LEGGI IMPEGNATO", che impedisce letture sporche e rende il blocco ottimistico altrettanto accurato quanto pessimista.
antinome,

Eric Brower afferma che i banchieri, a differenza di altri, preferiscono operazioni sporche. I tuoi guru sembrano assolutamente fuori dai carrelli.
Little Alien,

1
Eric Brewer è il guru che ha detto il teorema della PAC sulla coerenza nel settore bancario . È l'opposto di ciò per cui lo onori.
Little Alien,

50

Oltre a quanto già detto:

  • Va detto che il optimisticblocco tende a migliorare la concorrenza a scapito della prevedibilità.
  • Pessimisticil blocco tende a ridurre la concorrenza, ma è più prevedibile. Paghi i tuoi soldi, ecc ...

3
Non vedo come la prevedibilità (comunque tu la definisca) sia migliorata con il blocco pessimistico - se intendi "la transazione può essere completata una volta che sono stati effettuati i blocchi" hai ragione, ma fino a quando la transazione avrà tutti i blocchi richiesti, potrebbe essere necessario attendere blocchi rimanenti e, di fatto, potrebbero essere interrotti a causa della logica di rilevamento + risoluzione del deadlock del DB. Le app che utilizzano il blocco pessimistico possono avere tempi di esecuzione altamente imprevedibili: l'esempio classico è che qualcuno blocca un record X quindi va a pranzo, quindi un utente blocca il record X e Y, quindi un altro Y e Z e così via fino a quando la maggior parte degli utenti viene bloccata. ..
RichVel,

40

Quando si affrontano i conflitti, sono disponibili due opzioni:

  • Puoi provare a evitare il conflitto, ed è quello che fa il Pessimistic Locking.
  • In alternativa, è possibile consentire il verificarsi del conflitto, ma è necessario rilevarlo al momento del commit delle transazioni, ed è ciò che fa il blocco ottimistico.

Consideriamo ora la seguente anomalia di Lost Update :

Aggiornamento perso

L'anomalia di Lost Update può verificarsi nel livello di isolamento Read Committed .

Nel diagramma sopra possiamo vedere che Alice crede di poterne ritirare 40 da lei, accountma non si rende conto che Bob ha appena cambiato il saldo del conto, e ora ne rimangono solo 20 in questo conto.

Blocco pessimistico

Il blocco pessimistico raggiunge questo obiettivo prendendo un blocco condiviso o di lettura sull'account in modo da impedire a Bob di modificare l'account.

Blocco pessimistico dell'aggiornamento perso

Nel diagramma sopra, sia Alice che Bob acquisiranno un blocco di lettura sulla accountriga della tabella che entrambi gli utenti hanno letto. Il database acquisisce questi blocchi su SQL Server quando si utilizza Lettura ripetibile o Serializable.

Poiché sia ​​Alice che Bob hanno letto il accountvalore PK di 1, nessuno dei due può modificarlo fino a quando un utente non rilascia il blocco di lettura. Questo perché un'operazione di scrittura richiede un'acquisizione di blocchi di scrittura / esclusivi e i blocchi condivisi / di lettura impediscono i blocchi di scrittura / esclusivi.

Solo dopo che Alice ha eseguito la transazione e il blocco di lettura è stato rilasciato sulla accountriga, Bob UPDATEriprenderà e applicherà la modifica. Fino a quando Alice non rilascia il blocco di lettura, l'UPDATE di Bob si blocca.

Per maggiori dettagli su come i framework di accesso ai dati utilizzano il supporto di blocco pessimistico del database sottostante, consulta questo articolo .

Blocco ottimistico

Il blocco ottimistico consente che si verifichi il conflitto ma lo rileva quando si applica AGGIORNAMENTO di Alice quando la versione è cambiata.

Transazioni a livello di applicazione

Questa volta, abbiamo una versioncolonna aggiuntiva . La versioncolonna viene incrementata ogni volta che viene eseguito un UPDATE o DELETE e viene anche utilizzata nella clausola WHERE delle istruzioni UPDATE e DELETE. Perché ciò funzioni, dobbiamo emettere SELECT e leggere l'attuale versionprima di eseguire UPDATE o DELETE, altrimenti, non sapremmo quale valore di versione passare alla clausola WHERE o da incrementare.

Per maggiori dettagli su come i framework di accesso ai dati implementano il blocco ottimistico, leggi questo articolo .

Transazioni a livello di applicazione

I sistemi di database relazionali sono emersi alla fine degli anni '70, all'inizio degli anni '80, quando un client si connetteva in genere a un mainframe tramite un terminale. Ecco perché vediamo ancora che i sistemi di database definiscono termini come l'impostazione SESSIONE.

Al giorno d'oggi, su Internet, non eseguiamo più letture e scritture nel contesto della stessa transazione di database e ACID non è più sufficiente.

Ad esempio, considerare il seguente caso d'uso:

inserisci qui la descrizione dell'immagine

Senza un blocco ottimistico, non è possibile che questo aggiornamento perduto venga rilevato anche se le transazioni del database utilizzano Serializable. Questo perché letture e scritture vengono eseguite in richieste HTTP separate, quindi su diverse transazioni del database.

Pertanto, il blocco ottimistico può aiutarti a prevenire gli aggiornamenti persi anche quando utilizzi transazioni a livello di applicazione che incorporano anche il tempo di riflessione dell'utente.

Per ulteriori dettagli sulle transazioni logiche o a livello di applicazione, consulta questo articolo .

Conclusione

Il blocco ottimistico è una tecnica molto utile e funziona perfettamente anche quando si utilizzano livelli di isolamento meno rigorosi, come Read Committed, o quando le letture e le scritture vengono eseguite nelle successive transazioni del database.

L'aspetto negativo del blocco ottimistico è che il rollback verrà attivato dal framework di accesso ai dati al momento della cattura di un OptimisticLockException, quindi perdendo tutto il lavoro svolto in precedenza dalla transazione attualmente in esecuzione.

Più contesa, più conflitti e maggiore è la possibilità di interrompere le transazioni. I rollback possono essere costosi per il sistema di database in quanto devono ripristinare tutte le modifiche in sospeso che potrebbero coinvolgere sia le righe della tabella che i record dell'indice.

Per questo motivo, il blocco pessimistico potrebbe essere adatto quando si verificano frequentemente conflitti, poiché riduce la possibilità di ripristinare le transazioni.


Per quali scenari suggeriresti di scegliere OptimisticLocking e PessimisticLocking? Dipende da quanto spesso si verifica un OptimisticLockException?
Stimpson Cat,

1
Dipende dal caso d'uso. A volte, il blocco ottimistico è l'unica soluzione (ad esempio, transazioni multi-richiesta). Altre volte, il blocco pessimistico è l'unica soluzione (ad esempio, i blocchi di avviso PostgreSQL ). A volte, devi combinarli, come nel caso PESSIMISTIC_FORCE_INCREMENT.
Vlad Mihalcea,

22

Penserei a un altro caso in cui il blocco pessimistico sarebbe una scelta migliore.

Per un blocco ottimistico, ogni partecipante alla modifica dei dati deve accettare di utilizzare questo tipo di blocco. Ma se qualcuno modifica i dati senza preoccuparsi della colonna della versione, ciò rovinerà l'intera idea del blocco ottimistico.


Le persone che tentano di usare il blocco ottimistico e pessimistico possono anche calpestarsi, per così dire. Immagina uno scenario in cui una sessione ottimista legge un record e sta facendo dei calcoli mentre una sessione pessimistica aggiorna il record, quindi la sessione ottimistica ritorna e aggiorna lo stesso record senza notare alcuna modifica apportata. Selezionare ... per l'aggiornamento funziona solo se ogni sessione utilizza la stessa sintassi.
lusional

Buona spiegazione, ti do il voto da parte mia
Dulaj Kulathunga,

15

Ci sono sostanzialmente due risposte più popolari. Il primo dice sostanzialmente

L'ottimismo richiede architetture a tre livelli in cui non si mantiene necessariamente una connessione al database per la sessione mentre il blocco pessimistico è quando si blocca il record per uso esclusivo fino a quando non si è finito con esso. Ha un'integrità molto migliore rispetto al blocco ottimistico, è necessaria una connessione diretta al database.

Un'altra risposta è

L'ottimismo (controllo delle versioni) è più rapido a causa dell'assenza di blocchi, ma il blocco (pessimistico) funziona meglio quando la contesa è elevata ed è meglio prevenire il lavoro piuttosto che scartarlo e ricominciare da capo.

o

Il bloccaggio ottimistico funziona meglio in caso di collisioni rare

Come è messo in questa pagina.

Ho creato la mia risposta per spiegare in che modo "mantenere la connessione" è correlato a "basse collisioni".

Per capire quale strategia è la migliore per te, non pensare alle Transazioni al secondo del tuo DB ma alla durata di una singola transazione. Normalmente, si apre trasnaction, si esegue un'operazione e si chiude la transazione. Questa è una breve, classica transazione che ANSI aveva in mente e che andava bene per evitare il blocco. Ma come si implementa un sistema di prenotazione dei biglietti in cui molti clienti prenotano le stesse stanze / posti allo stesso tempo?

Sfoglia le offerte, compila il modulo con molte opzioni disponibili e prezzi correnti. Ci vuole molto tempo e le opzioni possono diventare obsolete, tutti i prezzi non validi tra voi hanno iniziato a compilare il modulo e premere il pulsante "Accetto" perché non c'era nessun blocco sui dati a cui si è avuto accesso e qualcun altro, più agile, ha interferito cambiando tutti i prezzi e devi ricominciare con nuovi prezzi.

Puoi invece bloccare tutte le opzioni mentre le leggi. Questo è uno scenario pessimistico. Vedi perché fa schifo. Il tuo sistema può essere abbattuto da un singolo pagliaccio che semplicemente avvia una prenotazione e va a fumare. Nessuno può prenotare nulla prima che finisca. Il flusso di cassa scende a zero. Questo è il motivo per cui le riserve ottimistiche sono utilizzate nella realtà. Coloro che si dilettano troppo a lungo devono riavviare la prenotazione a prezzi più alti.

In questo approccio ottimista devi registrare tutti i dati che leggi (come nella mia Lettura ripetuta ) e arrivare al punto di impegno con la tua versione dei dati (voglio comprare azioni al prezzo che hai visualizzato in questa quotazione, non al prezzo attuale ). A questo punto, viene creata la transazione ANSI, che blocca il DB, controlla se non viene modificato nulla e commette / interrompe l'operazione. IMO, questa è un'emulazione efficace di MVCC , che è anche associata a Optimistic CC e presuppone anche che la tua transazione si riavvii in caso di interruzione, ovvero effettuerai una nuova prenotazione. Una transazione qui implica decisioni di un utente umano.

Sono lungi dal comprendere come implementare manualmente MVCC ma penso che le transazioni di lunga durata con l'opzione di riavvio siano la chiave per comprendere l'argomento. Correggimi se sbaglio ovunque. La mia risposta è stata motivata da questo capitolo di Alex Kuznecov .


12

Nella maggior parte dei casi, il blocco ottimistico è più efficiente e offre prestazioni più elevate. Quando si sceglie tra blocco pessimistico e ottimistico, considerare quanto segue:

  • Il blocco pessimistico è utile se ci sono molti aggiornamenti e possibilità relativamente alte di utenti che provano ad aggiornare i dati contemporaneamente. Ad esempio, se ogni operazione può aggiornare un gran numero di record alla volta (la banca potrebbe aggiungere gli interessi attivi su ogni conto alla fine di ogni mese) e due applicazioni eseguono tali operazioni contemporaneamente, avranno conflitti .

  • Il blocco pessimistico è anche più appropriato nelle applicazioni che contengono tabelle di piccole dimensioni che vengono frequentemente aggiornate. Nel caso di questi cosiddetti hotspot, i conflitti sono così probabili che il blocco ottimistico spreca sforzo nel rollback delle transazioni in conflitto.

  • Il blocco ottimistico è utile se la possibilità di conflitti è molto bassa: ci sono molti record ma relativamente pochi utenti o pochissimi aggiornamenti e principalmente operazioni di tipo read.


3

Un caso d'uso per il blocco ottimistico è che l'applicazione utilizzi il database per consentire a uno dei thread / host di "rivendicare" un'attività. Questa è una tecnica che mi è tornata utile regolarmente.

Il miglior esempio che mi viene in mente è per una coda di attività implementata utilizzando un database, con più thread che rivendicano attività contemporaneamente. Se un'attività ha lo stato "Disponibile", "Rivendicato", "Completato", una query db può dire qualcosa del tipo "Imposta stato =" Rivendicato "dove stato =" Disponibile ". Se più thread tentano di modificare lo stato in questo modo, tutti tranne il primo thread falliranno a causa di dati sporchi.

Si noti che questo è un caso d'uso che prevede solo un blocco ottimistico. Quindi, in alternativa al dire "Il blocco ottimistico viene utilizzato quando non ci si aspettano molte collisioni", può anche essere usato dove ci si aspetta collisioni ma si vuole che esattamente una transazione abbia successo.


3

Molte cose buone sono state dette sopra sul blocco ottimistico e pessimistico. Un punto importante da considerare è il seguente:

Quando si utilizza il blocco ottimistico, è necessario essere cauti sul fatto che l'applicazione verrà ripristinata da questi errori.

Soprattutto nelle architetture asincrone basate sui messaggi, ciò può comportare l'elaborazione di messaggi fuori servizio o aggiornamenti persi.

È necessario valutare gli scenari di errore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.