Cosa devo fare se il blocco ottimistico non funziona?

10

Ho questo seguente scenario:

  1. Un utente fa una richiesta GET a /projects/1 e riceve un ETag .
  2. L'utente fa una richiesta PUT a /projects/1 con ETag dal punto # 1.
  3. L'utente fa un'altra richiesta PUT a /projects/1 con ETag dal punto # 1.

Normalmente, la seconda richiesta PUT riceverebbe una risposta 412, dal momento che l'ETag ora è obsoleto - la prima richiesta PUT ha modificato la risorsa, quindi l'ETag non corrisponde più.

Ma cosa succede se le due richieste PUT vengono inviate contemporaneamente (o esattamente una dopo l'altra)? La prima richiesta PUT non ha il tempo di elaborare e aggiornare la risorsa prima dell'arrivo di PUT # 2, il che fa sì che PUT # 2 sovrascriva PUT # 1. L'intero punto del blocco ottimistico è che ciò non avvenga ...

    
posta maximedupre 05.10.2018 - 19:13
fonte

5 risposte

22

Il meccanismo ETag specifica solo il protocollo di comunicazione per il blocco ottimistico. È responsabilità del servizio applicazioni implementare il meccanismo per rilevare gli aggiornamenti simultanei per applicare il blocco ottimistico.

In un'applicazione tipica che utilizza un database, di solito si esegue questa operazione aprendo una transazione durante l'elaborazione di una richiesta PUT. Normalmente leggerai lo stato esistente del database all'interno di quella transazione (per ottenere un blocco di lettura), controlla la validità di Etag e sovrascrivi i dati (in un modo che causerà un conflitto di scrittura quando c'è una transazione concorrente non compatibile), quindi impegnarsi. Se si imposta la transazione correttamente, uno dei commit dovrebbe fallire perché entrambi tenteranno di aggiornare gli stessi dati contemporaneamente. Sarai quindi in grado di utilizzare questo errore di transazione per restituire 412 o ripetere la richiesta, se ha senso per l'applicazione.

    
risposta data 05.10.2018 - 19:27
fonte
13

Devi eseguire la seguente coppia atomicamente:

  • verifica della validità del tag (ovvero è aggiornato)
  • aggiornamento della risorsa (che include l'aggiornamento del tag)

Altri lo chiamano una transazione - ma fondamentalmente, l'esecuzione atomica di queste due operazioni è ciò che impedisce di sovrascrivere l'altro per caso; senza questo hai una condizione di gara, come stai notando.

Questo è ancora considerato un blocco ottimistico, se si guarda al quadro generale: che la risorsa stessa non è bloccata dalla lettura iniziale (GET) da parte di qualsiasi utente o qualsiasi utente che sta guardando i dati, sia con l'intenzione di aggiornare oppure no.

Alcuni comportamenti atomici sono necessari, ma ciò avviene all'interno di una singola richiesta (il PUT) piuttosto che tentare di mantenere un blocco su più interazioni di rete; questo è un blocco ottimistico: l'oggetto non è bloccato da GET ma può ancora essere aggiornato in modo sicuro con PUT.

Ci sono anche molti modi per ottenere l'esecuzione atomica di queste due operazioni: bloccare la risorsa non è l'unica opzione; ad esempio, un thread leggero o un blocco oggetto può essere sufficiente e dipende dall'architettura e dal contesto di esecuzione dell'applicazione.

    
risposta data 05.10.2018 - 20:26
fonte
1

È lo sviluppatore dell'applicazione che controlla effettivamente l'E-Tag e fornisce quella logica. Non è magico quello che fa il server web perché sa solo come calcolare E-Tag di intestazioni per il contenuto statico. Prendiamo il tuo scenario sopra e analizziamo come dovrebbe avvenire l'interazione.

GET /projects/1

Il server riceve la richiesta, determina l'E-Tag per questa versione del record, restituendolo con il contenuto effettivo.

200 - OK
E-Tag: "412"
Content-Type: application/json
{modified: false}

Poiché il client ora ha il valore E-Tag, può includerlo con la richiesta PUT :

PUT /projects/1
If-Match: "412"
Content-Type: application/json
{modified: true}

A questo punto la tua applicazione deve fare quanto segue:

  • Verifica che l'E-Tag sia ancora corretto: "412" == "412"?
  • In tal caso, effettua l'aggiornamento e calcola un nuovo E-Tag

Invia la risposta positiva.

204 No Content
E-Tag: "543"

Se arriva un'altra richiesta e tenta di eseguire un PUT simile alla richiesta di cui sopra, la seconda volta che il codice del server la valuta, sei responsabile di fornire il messaggio di errore.

  • Verifica che l'E-Tag sia ancora corretto: "412"!="543"

In caso di errore, invia la risposta all'errore.

412 Precondition Failed

Questo è il codice che devi effettivamente scrivere. L'E-Tag può infatti essere qualsiasi testo (entro i limiti definiti nelle specifiche HTTP). Non deve essere un numero. Può anche essere un valore hash.

    
risposta data 05.10.2018 - 19:50
fonte
0

In tal caso il servizio è rotto. Dovrebbe utilizzare transazioni o blocchi o database che hanno questa funzionalità fuori dalla scatola.

    
risposta data 05.10.2018 - 19:23
fonte
-2

Come complemento alle altre risposte, pubblicherò una delle migliori citazioni nella documentazione di ZeroMQ che descrive fedelmente il problema di fondo:

To make utterly perfect MT programs (and I mean that literally), we don't need mutexes, locks, or any other form of inter-thread communication except messages sent across ZeroMQ sockets.

By "perfect MT programs", I mean code that's easy to write and understand, that works with the same design approach in any programming language, and on any operating system, and that scales across any number of CPUs with zero wait states and no point of diminishing returns.

If you've spent years learning tricks to make your MT code work at all, let alone rapidly, with locks and semaphores and critical sections, you will be disgusted when you realize it was all for nothing. If there's one lesson we've learned from 30+ years of concurrent programming, it is: just don't share state. It's like two drunkards trying to share a beer. It doesn't matter if they're good buddies. Sooner or later, they're going to get into a fight. And the more drunkards you add to the table, the more they fight each other over the beer. The tragic majority of MT applications look like drunken bar fights.

    
risposta data 05.10.2018 - 20:35
fonte

Leggi altre domande sui tag