2010-05-14 2 views
36

Devo progettare un server che deve servire milioni di client che sono simultaneamente connessi al server tramite TCP.Come conservare un milione di connessioni TCP simultanee?

Il traffico di dati tra il server e i client sarà scarso, quindi i problemi di larghezza di banda possono essere ignorati.

Un requisito importante è che ogni volta che il server deve inviare dati a qualsiasi client, deve utilizzare la connessione TCP esistente anziché aprire una nuova connessione verso il client (perché il client potrebbe trovarsi dietro un firewall).

Qualcuno sa come fare questo e quale hardware/software è necessario (al minor costo)?

+2

Deve essere TCP? Se il traffico è scarso, il costo del tracciamento di tutte le connessioni potrebbe essere irragionevolmente alto. E potresti approfondire un po 'cosa farà il server? Milioni di connessioni attive non utilizzate attivamente mi sembrano sospette. – VladV

risposta

19

Quali sistemi operativi stai considerando per questo?

Se si utilizza un sistema operativo Windows e si utilizza qualcosa più tardi di Vista, non si dovrebbe avere un problema con molte migliaia di connessioni su una singola macchina. Ho eseguito test (qui: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html) con una macchina Windows Server 2003 di bassa specifica e ho ottenuto facilmente più di 70.000 connessioni TCP attive. Alcuni dei limiti di risorse che influiscono sul numero di connessioni possibili sono stati notevolmente migliorati su Vista (vedi qui: http://www.lenholgate.com/blog/2005/11/windows-tcpip-server-performance.html) e quindi potresti probabilmente raggiungere il tuo obiettivo con un piccolo gruppo di macchine. Non so di cosa avresti bisogno di fronte a quelli per instradare le connessioni.

Windows fornisce una funzionalità chiamata I/O Completion Ports (vedere: http://msdn.microsoft.com/en-us/magazine/cc302334.aspx) che consente di eseguire il servizio di molte migliaia di connessioni simultanee con pochi thread (stavo facendo dei test ieri con 5000 connessioni che saturano un collegamento a un server con 2 discussioni per elaborare l'I/O ...). Pertanto l'architettura di base è molto scalabile.

Se si desidera eseguire alcuni test poi ho alcuni strumenti disponibili gratuitamente sul mio blog che consentono di thrash un server semplice eco con molte migliaia di connessioni (1) e (2) e un codice gratuito che è possibile utilizzare per iniziare (3)

La seconda parte della tua domanda, dai tuoi commenti, è più complicata. Se l'indirizzo IP del client continua a cambiare e non c'è nulla tra te e loro che sta fornendo NAT per darti un indirizzo IP coerente, le loro connessioni saranno, senza dubbio, terminate e dovranno essere ristabilite. Se i client rilevano che questa connessione si interrompe quando il loro indirizzo IP cambia, allora possono riconnettersi al server, se non possono, allora suggerirei che i client devono eseguire il polling del server ogni tanto in modo che possano rilevare la perdita della connessione e ricollegare. Non c'è nulla che il server possa fare qui in quanto non può prevedere il nuovo indirizzo IP e scoprirà che la vecchia connessione non è riuscita quando tenta di inviare dati.

E ricordate, i vostri problemi sono solo all'inizio, una volta che si ottiene il vostro sistema di scalare a questo livello ...

+1

Il tuo EchoServerTest è Ok, ma come possiamo testare oltre 64k connessioni? Il client ha limite di porta 64k – onmyway133

+1

Più macchine client. Devi farlo manualmente al momento, poiché non ho trovato bisogno di scrivere un test client in rete che può essere eseguito da una singola macchina con slave su altre macchine (è sulla mia lista di cose da fare ...). –

+1

Su Linux è anche possibile utilizzare gli indirizzi IP con alias su un computer client; ogni IP alias ti darà 65k in più. –

11

Questo problema è correlato al cosiddetto problema C10K. La pagina C10K elenca un buon numero di buone risorse per affrontare i problemi che si incontrano quando si tenta di consentire a migliaia di client di connettersi allo stesso server.

+0

grazie per la risposta. ma personalmente non penso che siano lo stesso problema. Quello che voglio sapere è come mantenere i client connessi 1M permanentemente connessi, NON come accettare le richieste di connessione o come rilevare il cambiamento dello stato della connessione. grazie comunque. – cow

+0

@cow: Non c'è nulla di particolarmente difficile nel mantenere i client connessi: cosa ti fa pensare che ci sarebbe? È lontano dalla parte più difficile del problema. – caf

+0

cosa succede se i client si trovano in una rete in cui i loro IP possono essere cambiati frequentemente. Ad esempio, ho un telefono T-Mobile G1. ho trovato che l'IP del mio telefono cambia di frequente.anche se il telefono ha una connessione TCP ad alcuni server fuori dalla rete T-Moble, quando non ci sono dati che fluiscono attraverso la connessione, la probabilità che l'IP del telefono venga cambiato è grande; una volta che l'IP è cambiato, ogni connessione TCP è in realtà interrotta. è per questo che ho il problema. – cow

-4

EDIT: Come notato nei commenti qui sotto, la mia affermazione originale che v'è un limite di 64 KB in base al numero di porte non è corretto, tuttavia non vi è un limite di 32K al numero di presa gestisce, quindi il mio il design suggerito è valido

Con un tipico design di server TCP/IP, il numero di connessioni aperte simultanee è limitato. Il server ha una porta di ascolto e quando un client si connette ad esso il server effettua una chiamata di accettazione e crea un nuovo socket su una porta casuale per il resto della connessione.

Per gestire più di 64 k connessioni simultanee, penso che sia necessario utilizzare UDP. È necessaria solo una porta per il server da ascoltare ed è necessario gestire le connessioni utilizzando un ID client a 32 bit nei dati del pacchetto invece di disporre di una porta separata per ciascun client. L'ID client a 32 bit potrebbe essere l'indirizzo IP del client e il client può ascoltare su una porta UDP conosciuta per i messaggi provenienti dal server. Quella porta sarebbe l'unica che deve essere aperta sul firewall.

Con questo approccio, l'unica limitazione è la velocità con cui è possibile gestire e rispondere ai messaggi UDP. Con milioni di client, anche il traffico sparse potrebbe dare grossi picchi, e se non leggi i pacchetti abbastanza velocemente la tua coda di input si riempirà e inizierai a rilasciare i pacchetti. La pagina C10K che Greg indica ti darà delle strategie per questo.

+1

Più connessioni client a un server non utilizzano porte * server * aggiuntive. Ci saranno ancora limitazioni tecniche, ma non è il numero di porte. Le connessioni sono identificate sul lato server usando l'esclusiva tupla da 4 (server_ip, server_port, client_ip, client_port). Potresti pensare al * handle di socket *, in cui un socket del server sembra generare più handle di socket tramite la chiamata 'accept()'. –

+0

Hmm. Sì, penso che tu abbia ragione. http://linux.die.net/man/2/accept dice accept non funzionerà se si esauriscono i descrittori di file, non le porte. Ho dato un'occhiata al codice sorgente del kernel Linux, e da quello che posso dire il numero massimo di file viene passato come int. Questo probabilmente limita i descrittori di file 32K, sebbene varieranno in base alla piattaforma. Ho torto sui dettagli del perché TCP sia limitato, ma penso che sia ancora limitato e l'UDP sia un'alternativa praticabile. – DougWebb

+0

grazie per i commenti di entrambi. ho visto la pagina c10k settimane fa. ricordo che suggerisce epoll(). Vorrei poterlo usare con UDP. in ogni modo, come so, epoll è irrilevante per un server UDP che ha solo un socket da ricevere, sono corretto? l'urgenza di leggere i pacchetti abbastanza velocemente è valida. tuttavia, non riesco a pensare a un modo migliore per leggere più velocemente rispetto all'utilizzo di un thread dedicato per leggere i pacchetti dal socket UDP e metterli in una coda per i thread di lavoro da consumare. potresti consigliare metodi migliori? Molte grazie in anticipo. – cow

4

Mi sono imbattuto nello APE Project qualche tempo fa. Sembra un sogno che si avvera. Possono supportare fino a 100k client concorrenti su un singolo nodo. Diffondili su 10 o 20 nodi e puoi servire milioni. Perfetto per applicazioni RESTful. Potrebbe voler guardare più a fondo per qualsiasi spazio dei nomi condiviso. Uno svantaggio è che questo è un server standalone, come in un server web supplementare. Questo server è ovviamente Open Source, quindi qualsiasi costo è relativo all'hardware/ISP.

+0

grazie per l'informazione. ma la mia app non è basata sul web. come posso utilizzare APE? – cow

+0

È possibile utilizzare APE senza browser. Utilizzano un protocollo predefinito (e puoi crearne uno tuo: http://www.ape-project.org/wiki/index.php/Protocol) Puoi scrivere la tua libreria per gestire i collegamenti con la tua lingua preferita usando il loro " APE Javascript framework "come riferimento. – Vic

+0

grazie ancora. esaminerò il protocollo per vedere se è opportuno sostituire il mio protocollo con codifica binaria con gli APE. – cow

0

Non è possibile utilizzare UDP. Se il client invia una richiesta e non si risponde immediatamente, un router dimenticherà il percorso inverso in 30 secondi o meno, in modo che il server non sarà mai in grado di rispondere al client.

TCP è l'unica opzione e anch'essa ti darà mal di testa. La maggior parte dei router dimenticherà la rotta e/o interromperà la connessione dopo alcuni minuti, quindi il codice client/server dovrà inviare "keep alive" abbastanza spesso.

Raccomando di impostare uno "sniffer", per vedere come le compagnie telefoniche sono in contatto con lo smartphone per la loro tecnologia "push". Copia quello che stanno facendo, perché quella roba funziona!

0

Come diceva Greg, il problema che stai descrivendo è C10K (o meglio "C1M" nel tuo caso) Ho recentemente creato un semplice server echo TCP su linux che si adatta molto bene al numero di sessioni (testato solo fino a 200.000), utilizzando la coda epoll. Su BSD, hai qualcosa di simile chiamato kqueue. Puoi controllare lo code se lo desideri. Spero che questo aiuti e buona fortuna!