2013-02-25 10 views
11

Sto implementando un server personalizzato che deve mantenere un numero molto elevato (100K o più) di connessioni longeve. Il server passa semplicemente i messaggi tra i socket e non esegue alcuna elaborazione seria dei dati. I messaggi sono piccoli, ma molti di questi vengono ricevuti/inviati ogni secondo. Ridurre la latenza è uno degli obiettivi. Mi rendo conto che l'utilizzo di più core non migliorerà le prestazioni e quindi ho deciso di eseguire il server in una singola discussione chiamando i metodi run_one o poll dell'oggetto io_service. In ogni caso, il server multi-thread sarebbe molto più difficile da implementare.Prestazioni a singolo filetto Asio Boost

Quali sono i possibili colli di bottiglia? Syscalls, larghezza di banda, completamento della coda/evento di demultiplexing? Ho il sospetto che i gestori di dispacciamento possano richiedere il blocco (fatto internamente dalla libreria asio). È possibile disabilitare anche il blocco della coda (o qualsiasi altro blocco) in boost.asio?

MODIFICA: domanda correlata. Le prestazioni di syscall migliorano con più thread? La mia sensazione è che siccome i syscalls sono atomici/sincronizzati dal kernel, l'aggiunta di più thread non migliorerà la velocità.

+0

Se si sta eseguendo tutto in un thread, non è necessario alcun blocco (scritto a mano). –

+1

L'utilizzo di più core probabilmente migliorerà le prestazioni - vedere http://cmeerw.org/blog/748.html#748 e http://cmeerw.org/blog/746.html#746 per alcuni benchmark che ho fatto l'anno scorso. – cmeerw

risposta

15

Si potrebbe voler leggere my question da alcuni anni fa, l'ho chiesto quando ho iniziato a studiare la scalabilità di Boost.Asio durante lo sviluppo del software di sistema per il Blue Gene/Q supercomputer.

Scalare a 100 o più connessioni non dovrebbe essere un problema, anche se è necessario essere consapevoli delle ovvie limitazioni delle risorse come il numero massimo di descrittori di file aperti. Se non hai letto il seminale C10K paper, ti suggerisco di leggerlo.

Dopo aver implementato l'applicazione utilizzando un singolo thread e un singolo io_service, suggerisco indagando un pool di thread invocano io_service::run(), e solo allora indagare appuntare un io_service ad un filo e/o CPU specifica. Ci sono più esempi inclusi nella documentazione di Asio per tutti e tre questi progetti, e several questions su SO con maggiori informazioni.Tenere presente che quando si introducono più thread che invocano io_service::run(), potrebbe essere necessario implementare strand s per assicurarsi che i gestori abbiano accesso esclusivo alle strutture di dati condivise.

9

Utilizzando boost :: asio è possibile scrivere server single-thread o multi-thread con lo stesso costo di sviluppo. È possibile scrivere la versione a thread singolo come prima versione, quindi convertirla in multithread, se necessario.

In genere, solo il collo di bottiglia per boost :: asio è che il reattore epoll/kqueue funziona in un mutex. Quindi, solo un thread sta facendo epoll allo stesso tempo. Questo può ridurre le prestazioni nel caso in cui si disponga di un server multithread, che serve molti e molti pacchetti molto piccoli. Ma, comunque, dovrebbe essere più veloce del semplice server di singlethread.

Ora parla del tuo compito. Se vuoi semplicemente passare messaggi tra le connessioni, penso che debba essere un server multithread. Il problema è syscalls (recv/send etc). Un'istruzione è molto facile da pensare per la CPU, ma qualsiasi syscall non è un'operazione molto "leggera" (tutto è relativo, ma relativo ad altri lavori nel tuo compito). Quindi, con un singolo thread, si otterranno grandi sovraccarichi di memoria, il motivo per cui consiglio di utilizzare lo schema multithread.

Inoltre, è possibile separare io_service e farlo funzionare come idioma "io_service per thread". Penso che questo debba dare le migliori prestazioni, ma ha lo svantaggio: se uno di io_service ottiene una coda troppo grande - altri thread non lo aiuteranno, quindi alcune connessioni potrebbero rallentare. Dall'altro lato, con il singolo io_service - l'overrun della coda può portare a un sovraccarico di grandi blocchi. Tutto quello che puoi fare: fai entrambe le varianti e misura larghezza di banda/latenza. Non dovrebbe essere troppo difficile implementare entrambe le varianti.

Problemi correlati