Come faccio a bilanciare 100 client controllando la stessa tabella di database in un ciclo?

7

Cosa ho

Questo è un prototipo . Ho un pool di 100 client collegati al server tramite websocket che segnalano cose e in attesa di comandi. Il server esegue il polling della tabella di database commands di tipo MEMORY in un ciclo utilizzando una query con WHERE client_id=? . Posso inserire una combinazione di client_id + command in quella tabella e, una volta fatto, il ciclo corrispondente corrisponderà e SELECT esso e lo riporterà al client.

Qual è il problema

L'approccio sembra funzionare, ma per quanto ho capito sto parlando di n di connessioni e query di database simultanee in un ciclo infinito ( n è il numero di client), che non suona efficace. Sarebbe molto meglio fare una query in un ciclo e poi controllare in qualche modo il client_id , se esiste, e distribuire i risultati ai client corrispondenti.

Questo mi ricorda l'approccio in cui stai selezionando gli articoli per primo e poi for () {} il set di risultati e fai query separate per ottenere i dettagli su ciascun elemento, il che si traduce in n+1 di query eseguite. La soluzione è una grande query con JOIN s e anche il preloading degli altri dati che non rientrano nella query JOIN ed principale. Ci dovrebbe essere anche il modo più efficace di eseguire il polling del database.

UPDATE : ho trovato questa risposta nella relativa sezione, e dice più o meno la stessa cosa:

Hammering your database isn't really a good idea. While I'm pretty sure you've realized this, others might not have. I remember a friend of mine tried to use a php script and a Javascript AJAX function in a loop for a semi-real time game. He very quickly realized that performance degraded as more people joined, simply because he was executing a ton of queries per second which hammered the database.

Quindi il polling del database per ogni client sembra non scalabile e inefficace quanto la creazione di un'applicazione di chat AJAX.

Quello che sto chiedendo

Immagino che ogni possibile approccio di programmazione debba essere stato nominato e coperto ora, quindi come si chiama questo? Qual è il consiglio / approccio comune qui?

    
posta aexl 08.10.2015 - 11:26
fonte

5 risposte

4

Si desidera un pool di connessioni: 100 client verranno limitati a utilizzare un pool di una manciata di connessioni DB in modo che il DB non si sovraccarichi rispondendo a molte richieste simultanee.

Potresti provare a ottimizzare le chiamate ma dovrai comunque consentire ai client di accedere al DB attraverso un meccanismo identico a un pool di connessioni, anche se nel pool è disponibile solo una connessione, puoi combinare tutti gli ID dai client in sospeso insieme in una singola clausola where per passare al DB e decomprimere i risultati su ciascun client al suo ritorno. Dovrai tenere traccia di quale client è presente nella richiesta o assicurarti che i risultati abbiano un risultato per ogni client richiedente, poiché più client arriveranno mentre la query DB è in corso, quando i risultati vengono distribuiti ai client, si ripete con il nuovi.

Se si dispone di un pool come questo, e le circostanze lo consentono, è possibile anche ritardare le richieste DB a un ritmo delicato, ma colpire ripetutamente il DB su una singola connessione non influisce sulle prestazioni, ad esempio fino a 100 client tutti spingendo contemporaneamente all'attenzione.

    
risposta data 08.10.2015 - 11:35
fonte
2

Hai posto la domanda sbagliata. La domanda giusta è "Dovrei utilizzare una tabella di database per implementare una coda?" e la risposta è NO . Utilizzare un'implementazione di accodamento distribuita robusta come Kafka.

Oppure il tuo database potrebbe avere un meccanismo di accodamento incorporato. Oracle lo fa. Tom Kite dedica una pagina o due in uno dei suoi libri Oracle che descrive il motivo per cui non si dovrebbe usare una tabella di database come coda.

    
risposta data 13.10.2015 - 08:27
fonte
1

Idealmente dovresti spingere al server web (attraverso una richiesta http o qualsiasi meccanismo di code menzionato nelle altre risposte) nel momento in cui le scritture si verificano nel database. In questo modo puoi evitare completamente il polling del database.

Se non hai altro da fare se non utilizzare il database, quindi esegui una query che otterrà le informazioni per tutti i client. Questo ti aiuterà a evitare di scrivere query in un ciclo. Nella tua applicazione puoi separare i dati per ciascun cliente ed emetterli tramite websocket.

    
risposta data 13.10.2015 - 07:30
fonte
0

A meno che le domande che i client devono eseguire siano complesse, non utilizzerei qui un database sql. C'è un bel po 'di overhead, anche quando si utilizza una tabella di memoria: interprocesso della comunicazione, interpretando la query, mantenendo un indice che probabilmente supporta tipi di query non necessari (ad esempio intervalli), marshalling dei dati e così via.

Precisamente come lo farei dipende molto dalle altre richieste delle applicazioni. Se non prevedi la necessità di ridimensionare a più server, un archivio in-process (ad esempio una mappa javascript in una variabile condivisa) è di gran lunga il modo più efficace di condividere i dati. Altrimenti, guarderei i database dei database dei valori delle chiavi in memoria, ad es. Redis.

Soprattutto, avrei astratto l'accesso ai dati in modo che il passaggio da una di queste opzioni a una data successiva sia facile.

    
risposta data 08.10.2015 - 12:58
fonte
0

IMO, hai quasi capito tutto da solo ... cercherò di elaborare il tipo di pattern che il mio framework preferito utilizza per questo genere di cose.

Prima i tuoi clienti si iscrivono ai comandi, in questo modo il tuo server sa quale socket (client) vuole i comandi associati a quale client_id. Il server esegue il polling del database, ogni X secondi (millisecondi?) O utilizza oplog tailing * per vedere se ci sono comandi da eseguire, se ce ne sono, invierà quel comando ai socket sottoscritti in base al client client_id ...

* Il tailing oplog viene utilizzato nei replicaset, è un log di tutte le operazioni eseguite in un database. La sua chiusura può essere più efficace del raggruppamento diretto del database ... O utilizzando la coda per sapere quando è stato inserito un nuovo documento e quindi sapere che il database dovrebbe essere interrogato si abbasseranno i carichi su insiemi di grandi dimensioni, ma potrebbe non essere necessario.

    
risposta data 08.10.2015 - 14:30
fonte

Leggi altre domande sui tag