Come risolve il problema di coerenza nell'applicazione concomitante e distribuita (costruita attorno al dilemma dei banchieri)?

5

Questo è un problema classico che sono sicuro sia stato risolto molte volte da molte persone diverse. Non ho alcun corso di formazione formale (non ho studiato informatica o altri argomenti accademici simili) e quindi non sono sicuro del modo migliore per risolvere il problema che sto per descrivere.

Se immaginiamo che il diagramma sottostante sia un esempio di dilemma dei banchieri (due utenti Foo e Bar hanno accesso a un singolo conto bancario: Baz). Qual è il comportamento previsto quando si segue uno dei percorsi indicati?

Note: I'm assuming we're using a mutex (or some other form of synchronisation) on the Baz variable.

Esempio 1: Baz inizialmente detiene il valore 10. Se Foo scrive un nuovo valore (che è il risultato della rimozione di 5 dal valore corrente) prima di Bar; quindi la barra finirà col prendere 10 dal nuovo valore 5, lasciando un saldo negativo (ad esempio il valore finale sarà -5). Significa che sono stati presi più soldi di quelli disponibili.

Esempio 2: Baz inizialmente detiene il valore 10. Se Bar scrive un nuovo valore (che è il risultato della rimozione di 10 dal valore corrente) prima di Foo; quindi Foo finirà col prendere 5 dal nuovo valore 0, lasciando un saldo negativo (ad esempio il valore finale sarà -5). Significa che sono stati presi più soldi di quelli disponibili.

Entrambe le azioni ( Foo (-5) e Bar (-10) ) vengono attivate contemporaneamente. Quindi, come possiamo garantire che Foo o Bar siano avvisati del fatto che la loro transazione non può essere completata (in quanto non ci sono fondi sufficienti per il successo)?

Sembra che una possibile soluzione sia garantire che il chiamante esegua un metodo che utilizza internamente un mutex per bloccare prima il valore; poi una volta che il valore è bloccato possiamo leggere il valore; e quindi controllare se l'azione è valida. Se la condizione passa, aggiorniamo il valore e rilasciamo il blocco sul valore. Significa che il prossimo chiamante sarà in grado di bloccare il valore e di eseguire gli stessi passi.

Ma come funzionerebbe questo approccio con un sistema distribuito? Puoi suggerire di utilizzare un archivio dati globale, ma dovrebbe essere tale da garantire la coerenza (ad esempio, un servizio come AWS "Dynamo DB offre" coerenza finale "e quindi non funzionerebbe per un istituto bancario); ma la consistenza garantita è generalmente considerata molto lenta (a seconda del numero di nodi distribuiti che presumo).

Quindi, come possiamo tentare di risolvere questo problema di progettazione?

    
posta Integralist 12.10.2014 - 17:59
fonte

2 risposte

3

Per un sistema distribuito, dovresti:

a) Usa "importo sottrazione o errore di restituzione se non puoi", dove il codice responsabile per baz restituisce un errore se il risultato sarebbe stato negativo (o restituisce "successo" se non ci fosse un errore)

b) Utilizzare l'equivalente del blocco; dove il codice responsabile per baz ha un "acquis baz" e "release baz" che devono essere utilizzati prima e dopo.

Si noti che questo è tipicamente solo la punta dell'iceberg. È più probabile che tu abbia 2 o più conti bancari e desideri trasferire fondi da uno all'altro in modo che tutti gli account vengano aggiornati o nessuno sia aggiornato. In questo caso, potresti (ad es.) Finire con una combinazione.

Ad esempio, se ci sono due account "Fred" e "Jane" e si desidera trasferire $ 5 da Fred a Jane; allora potresti finire con una sequenza del tipo:

  • Da te all'account di Fred: "Se l'account di Fred è 5 o superiore, blocca l'account di Fred e dimmi che posso procedere, altrimenti dimmi che non posso procedere"

  • Dall'account di Fred a te: "Puoi procedere"

  • Da te all'account di Jane: "Se l'account di Jane può essere aumentato di 5 blocchi l'account di Jane e dimmi che posso procedere, altrimenti dimmi che non posso procedere"

  • Dall'account di Jane a te: "Puoi procedere"

  • Da te all'account di Fred: "Sottrai 5 dall'account di Fred e rilascia il lucchetto che mi hai dato in precedenza"

  • Da te all'account di Jane: "Aggiungi 5 all'account di Jane e rilascia il lucchetto che mi hai dato in precedenza"

Si noti che per questo esempio; tu, l'account di Fred e l'account di Jane potrebbero essere tutti in esecuzione su computer completamente diversi che comunicano con messaggi / pacchetti (senza memoria condivisa).

    
risposta data 12.10.2014 - 19:22
fonte
2

Comprendo che l'industria finanziaria utilizza un sistema di controllo e correzione "after-the-fact" per risolvere errori.

cioè, fai ogni transazione sui singoli sistemi in modo indipendente (in modo tale che tu sappia che ogni sistema è corretto) e scrivi a un log i dettagli di ogni transazione. Questi log vengono quindi confrontati in un secondo momento e se si verifica un errore in uno, l'altro viene istruito a eseguire il rollback della transazione.

Quindi, la banca A ritira con successo i soldi, ma la banca B non riesce ad accreditarla. Successivamente, gli elenchi delle transazioni di entrambi vengono confrontati e Bank A ottiene un credito per sistemare le cose.

Non è possibile implementare un "blocco" distribuito in tali sistemi in quanto non rispondono nel modo previsto - e non si desidera bloccare l'account di qualcuno mentre si effettua un prelievo se non è possibile stabilire per quanto tempo sarà prima del l'altro sistema coinvolto nella transazione richiederà il completamento, si potrebbe finire con un blocco che rimane aperto bloccando altre transazioni su quell'account.

    
risposta data 13.10.2014 - 09:48
fonte

Leggi altre domande sui tag