2015-12-18 24 views
9

Ho uno scenario per la mia app che è simile all'invio di una richiesta di amicizia su Facebook.MongoDB Concurrency Issue

Quando l'utente A invia una richiesta di amicizia all'utente B, internamente viene creato un nuovo documento di richiesta di amicizia. In un secondo momento, quando l'utente B vuole anche inviare una richiesta di amicizia ad A, il sistema dovrebbe scoprire che esiste un documento di richiesta di amicizia e quindi dovrebbero essere amici l'uno dell'altro, non verrà creato alcun nuovo documento di richiesta di amicizia.

Sto cercando di capire il caso in cui l'utente A e l'utente B entrambe invia contemporaneamente richiesta di amicizia tra di loro che sarà quindi creare 2 documenti amico di richiesta e che porta ad un comportamento indeterminato ...

Grazie per la vostra suggerimenti .. Davvero apprezzato!

Modifica: Alcuni avevano suggerito di utilizzare una coda di richieste per risolvere questo; tuttavia, Sono confuso sull'uso della coda perché pensavo che avrebbe reso sequenziali le richieste di processo api dell'endpoint. Non perderei tutti i vantaggi del multi-threading usando la coda? Non posso fare a meno di immaginare quanto sarebbe male se il mio servizio avesse milioni di richieste in coda e aspettasse di essere eseguito uno per uno solo a causa di questo problema. Qualcuno ha visto qualcosa con problemi simili visti in produzione?

risposta

4

Avevo una situazione simile con il mio client che ha scritture concorrenti nel database, Quello che ho implementato è un servizio di coda.

Create a request in the queue rather than writing in the database, a separate reader will 
read one message from the queue at a time and check if it is valid to write it to 
database, write only if there is no previous request. 

È possibile implementare il proprio coda o è possibile utilizzare il servizio come AWS-SQS, RabbitMQ, MSMQ ecc

+0

Non significa che il mio server non elaborerà più le richieste in parallelo, il che significa che non sarà più performante come prima? – user1955934

+0

No, solo l'operazione di scrittura di questa particolare funzionalità passerà attraverso una coda. Puoi avere lettori paralleli se vuoi –

+0

sì, ma se c'è un carico di operazioni di scrittura in coda, la risposta non sarebbe molto lenta o addirittura un timeout? Voglio dire, vale la pena esibire un compromesso su questo raro caso? Spero che ci sia un altro modo per risolvere questo tipo di caso molto raro .. :( – user1955934

3

// specifico al vostro caso

  1. Nelle operazioni di MongoDB scrivere su un il singolo documento è atomico.
  2. mongodb ha una caratteristica di indice univoco.

Quindi se si inserisce il documento con un _id (o qualsiasi altro indice univoco) con nomi di persona A e B con la creazione di indice univoco per entrambi (come "a_b" di classificare lexicographically i nomi) prima di fare l'inserimento. Sarai intrinsecamente in grado di inserire solo un'istanza di quel documento.

// generale

Quello che in sostanza ci piacerebbe avere sono le transazioni, ma dal momento che MongoDB non supporta tale, a partire da ora. Ci sono alcuni trucchi per raggiungere questo obiettivo:

  1. 2 fasi impegna: https://docs.mongodb.org/v3.0/tutorial/perform-two-phase-commits/

  2. Utilizzando un server esterno per mantenere una bandiera, ad esempio utilizzando memcache che supporta l'inserimento in maniera transazionale/Confronta e Swap .

+0

la richiesta di amicizia ha una direzione, per indicare quale utente ha inviato la richiesta e a quale utente è destinato. quindi non può essere un documento che può essere rappresentato solo come A_B, ma piuttosto A_B e B_A. E questo non è un problema di transazione/atomicità poiché il problema principale è sapere quale documento creare in base a una condizione che potrebbe cambiare inaspettatamente; in questo caso, la condizione è "la richiesta di amicizia esiste?", ma questa condizione potrebbe non essere più valida dopo il controllo ... – user1955934

+0

Per occuparsi della direzione, ci può sempre essere un altro campo, ad esempio RequestFrom, requestTo. L'indice univoco dovrebbe essere un campo completamente diverso, per contrassegnare la relazione tra A e B (che è unica e una sola volta tra A e B). –

+0

Aggiungendo al commento sopra, lasciami spiegare perché penso che questo sia un problema di transazione: Come hai detto, "il problema principale è sapere quale documento creare in base a una condizione", questo è un problema molto semplice che può essere risolto da un semplice controllo del codice, MA "questa condizione potrebbe non essere più valida dopo il controllo" il motivo per cui questa condizione cambierà è che non c'è modo di sapere se durante la lettura c'è un altro thread che potrebbe scrivere, questo problema potrebbe essere risolto se in qualche modo si potrebbe acquisire un blocco di lettura/scrittura sul documento. Questa è essenzialmente una transazione. –

2

Qui, se si utilizza il sistema chiama metodo in frontend allora si dovrebbe sparare una richiesta di frontend dal database quando qualche utente come, io mando si richiede quindi all'interno di un database secondi si invia una chiamata di sistema e il vostro frontend codice immediatamente corretto il testo pulsante mi piace

"Aggiungi un amico" a "richiesta in arrivo"

o altro.

se siete solo configurando banca dati poi basta effettuare una chiamata di sistema che inviarlo a UI quando richiesta di amicizia arriva o come dici tu documento creato, l'ulteriore processo sarà gestito da UI Developer. Grazie. se la risposta non ti piace, allora mi scuso per questo, ma non mi sottovalutare perché sono nuovo nella Community Overflow dello Stack.