Perché il database come coda è così brutto? [chiuso]

32

Ho appena letto questo articolo e io m confuso.

Immaginiamo 1 webapp e 1 applicazione distinta che agisce come "worker", entrambi che condividono lo stesso database .

Oh, ho detto "condivisione" ... ma di cosa parla l'articolo? :

Fourthly, sharing a database between applications (or services) is a bad thing. It’s just too tempting to put amorphous shared state in there and before you know it you’ll have a hugely coupled monster.

= > disaccordo. Ci sono alcuni casi in cui applicazioni distinte fanno ancora parte della stessa unità e, quindi, la nozione di "problema di accoppiamento" non ha senso in questo caso.

Continuiamo: la webapp gestisce le richieste HTTP dei client e può aggiornare in qualsiasi momento alcuni aggregati (termine DDD), generando gli eventi di dominio corrispondenti.
L'obiettivo del lavoratore sarebbe gestire quegli eventi di dominio elaborando i lavori necessari.

Il punto è:

Come devono essere trasmessi i dati degli eventi al lavoratore?

La prima soluzione, come promuove l'articolo letto, sarebbe quella di utilizzare RabbitMQ, essendo un ottimo middleware orientato ai messaggi.

Il flusso di lavoro sarebbe semplice:

Ogni volta che il web dyno genera un evento, lo pubblica tramite RabbitMQ, che alimenta il lavoratore.
Lo svantaggio sarebbe che nulla garantisce la consistenza immediata tra il commit dell'aggiornamento aggregato e la pubblicazione dell'evento, senza affrontare i potenziali errori di invio ... o problemi hardware; questo è un altro problema principale.

Esempio: sarebbe possibile che un evento sia stato pubblicato senza successo dell'aggiornamento aggregato ... risultando in un evento che rappresenta una rappresentazione errata del modello di dominio.
Si potrebbe sostenere che esiste un XA globale (commit a due fasi), ma non è una soluzione adatta a tutti i database o middleware.

Quindi quale potrebbe essere una buona soluzione per garantire questa coerenza immediata? :
IMO, memorizzando l'evento nel database, nella stessa transazione locale dell'aggiornamento aggregato.
Verrà creato un semplice programma di pianificazione asincrona e responsabile di eseguire query sugli eventi non pubblicati correnti dal database e inviarli a RabbitMQ, che a sua volta popola l'operatore.

Ma perché necessitare di uno scheduler aggiuntivo nel lato webapp e tra l'altro: perché aver bisogno di RabbitMQ in questo caso?

Da questa soluzione, appare logicamente che RabbitMQ potrebbe non essere necessario, soprattutto perché il database è condiviso.
In effetti, in ogni caso, abbiamo visto che la consistenza immediata implica un sondaggio dal database.
Quindi, perché il lavoratore non dovrebbe essere responsabile direttamente di questo sondaggio?

Pertanto, mi chiedo perché così tanti articoli sul web critichino difficilmente l'accodamento dei database, promuovendo al tempo stesso il middleware orientato ai messaggi.

Estratto dell'articolo:

Simple, use the right tool for the job: this scenario is crying out for a messaging system. It solves all the problems described above; no more polling, efficient message delivery, no need to clear completed messages from queues, and no shared state.

E consistenza immediata, ignorata?

Per riassumere, sembra davvero che qualunque sia il caso, ovvero che il database sia condiviso o meno, abbiamo bisogno del polling del database .

Ho perso alcune nozioni critiche?

Grazie

    
posta Mik378 06.03.2014 - 00:09
fonte

1 risposta

27

Se stai costruendo una semplice applicazione con poco traffico, c'è qualcosa da dire su come tenere un altro componente fuori dal tuo sistema. È molto probabile che non utilizzare un bus dei messaggi sia la risposta giusta per te. Tuttavia, suggerirei di costruire il sistema in modo da poter sostituire il sistema di coda basato su database per una soluzione middleware. Sono d'accordo con l'articolo. Un database non è lo strumento giusto per il sistema basato su code, ma potrebbe essere abbastanza buono per te.

I sistemi basati su code come RabbitMq sono costruiti su vasta scala su hardware moderato. La loro architettura è in grado di raggiungere questo risultato evitando i processi che rendono il ACID sistema di database conforme lento per loro natura. Poiché un bus dei messaggi deve solo garantire che un messaggio venga archiviato ed elaborato correttamente, non deve preoccuparsi di bloccare e scrivere i registri delle transazioni. Entrambi questi concetti sono assolutamente necessari per un sistema ACID ma sono spesso causa di conflitto.

Per quanto riguarda le prestazioni, si tratta di: una tabella SQL. Molte letture e molte scritture. Entrambi richiedono un qualche tipo di blocco per aggiornare righe, pagine e indici. Il meccanismo di polling blocca costantemente un indice per effettuare ricerche su di esso. Ciò impedisce che le scritture si verifichino; al meglio sono in coda. Anche il codice che esegue l'elaborazione si sta bloccando per aggiornare lo stato sulla coda man mano che vengono completati o falliti. Sì, è possibile eseguire l'ottimizzazione della query dopo l'ottimizzazione per farlo funzionare, oppure è possibile utilizzare un sistema specificamente progettato per il carico di lavoro richiesto. Un RabbitMq consuma questo tipo di carico di lavoro senza nemmeno perdere tempo; inoltre, puoi salvare il tuo database dal carico di lavoro, dandogli più spazio per scalare altre cose.

Un'altra cosa da considerare è che la maggior parte dei sistemi di code in genere non usa una tecnica di polling (alcuni consentono l'HTTP, ma raccomandano di evitare l'uso per il lato ricevente). RabbitMq utilizza protocolli di rete specificamente progettati per bus di messaggi come AMPQ .

Modifica: aggiunta di casi d'uso.

Il modo in cui ho usato Rabbit è che ho avuto un endpoint API che accetta una modifica che richiede una tabella di database pesantemente utilizzata. Questa tabella è costantemente in conflitto e, a volte, non sarà in grado di salvare una modifica in modo tempestivo dall'API. Quello che faccio invece è scrivere la richiesta di modifica in una coda e poi avere un servizio che gestisce questi messaggi come sono in grado. Se si verifica una contesa del database, la coda cresce semplicemente e l'elaborazione dei messaggi viene ritardata. Generalmente il tempo di elaborazione scende nell'intervallo di 14 ms, ma nei momenti di alta contesa si arriva a 2-3 secondi.

    
risposta data 06.03.2014 - 01:02
fonte