C'è un problema nel tenere un gran numero di connessioni socket aperte per lunghi periodi di tempo?

7

L'applicazione che abbiamo in mente è un server relay. L'obiettivo è quello di accettare un numero elevato di connessioni socket in entrata (almeno migliaia) che rimarranno aperte per lunghi periodi (ore o forse giorni). Si scambieranno modeste quantità di dati e avranno bisogno di una latenza ragionevolmente bassa.

Il design tecnico è semplice e abbiamo un'implementazione di test. La nostra preferenza è usare Windows hosting e .NET, perché questa è la tecnologia che conosciamo. Tuttavia, questo tipo di utilizzo è ben al di fuori di ciò che ci è familiare.

La domanda è se ci sono limiti o vincoli specifici da tenere presente che sono inerenti o comuni al software che fa questo, e che dovremmo permettere nel nostro progetto e / o test prima di un lancio.

Ho trovato questa domanda ( Gestione di grandi quantità di socket ) e questo link ( link ), che tendono a suggerire che la nostra soluzione dovrebbe funzionare.

-

I commentatori hanno suggerito di aprire e chiudere le porte, o di usare un qualche tipo di protocollo, senza suggerire come. Il problema è che in qualsiasi momento un messaggio può essere inoltrato a una singola destinazione nota con l'aspettativa di essere ricevuto rapidamente (diciamo al massimo un secondo, preferibilmente prima). La destinazione è (in generale) dietro un firewall con proprietà sconosciute, quindi non può (in generale) eseguire un server o accettare connessioni in entrata. Può solo effettuare connessioni in uscita. Riteniamo che sia necessaria una connessione in uscita permanente per poter ricevere i pacchetti in qualsiasi momento senza preavviso. Suggerimenti alternativi potrebbero essere di interesse, anche se strettamente fuori tema per questa domanda.

Altri commentatori hanno suggerito che ci sono dei limiti del sistema operativo, ma non specificati. Supponendo che questa sia una versione del server Windows e qualche (forse grande) quantità di memoria, i limiti potrebbero essere un problema? Che cosa saranno? Windows è una cattiva idea?

    
posta david.pfx 03.04.2014 - 15:13
fonte

5 risposte

3

Ho lavorato su un server relay per i dati del mercato azionario in C # su un server Windows. Non c'era modo di ottenere migliaia di connessioni simultanee inoltrate da una sola macchina. Le specifiche per il relè erano molto semplici 1 connessione al fornitore di dati di borsa e connessioni in uscita illimitate ai clienti SilverLight.

Ci sono due approcci di base che ho studiato.

  • Utilizza un pool di thread, ogni client riceve un socket e un thread di lavoro.
  • Utilizza un thread di lavoro, il thread worker spinge i dati ripetendo su tutti i socket aperti.

Nessuno dei due approcci poteva superare i limiti di prestazioni della CPU e ogni approccio presentava limiti e restrizioni gravi.

Utilizzo di un pool di thread.

Windows fa schifo nella gestione multi-thread. Una volta che ho colpito circa 250 discussioni, le cose hanno iniziato a scendere. Non è un problema di memoria o di sistema. È un problema di quantità. Mentre Windows non ha problemi a gestire 250 thread. È un'altra storia che chiede a Windows di mantenere quei 250 thread impegnati a ritrasmettere i dati. Con il ritardo delle prestazioni, si verifica un backlog di dati.

Utilizzo di un thread di lavoro.

Non è possibile utilizzare un thread di lavoro per iterare i socket se questi socket stanno bloccando. Ogni volta che il thread colpisce un socket che deve scadere, tutti gli altri socket vengono lasciati in attesa. Se si passa alle operazioni di socket asycn, viene generato rapidamente un enorme backlog di callback e tutto si interrompe.

Per me i risultati sono stati.

100 clienti tutto è stabile. 250 clienti tutto funziona ma il limite raggiunto. 1000 clienti mai raggiunti.

Conclusione.

C # su Windows non è lo strumento giusto per un server relay relay. Non per le connessioni client che vanno a migliaia.

L'unica alternativa è non utilizzare i socket HTTP e passare a un protocollo di trasmissione come UDP o TCP. Per me questa non era un'opzione in quanto non è stato possibile abbandonare i dati. La maggior parte dei protocolli di trasmissione presuppone che la perdita di pacchetti sia accettabile.

Infine.

Se sei in grado di creare un relay C # in grado di gestire migliaia di client. Per favore, torna indietro e fammi sapere come hai fatto.

    
risposta data 04.04.2014 - 16:31
fonte
6

Penso che tu stia cercando un protocollo : qualcosa che possa gestire errori, ritrasmissioni, ecc. Ad esempio, cosa succede se uno dei socket viene eliminato perché la rete sottostante ha un problema? O se i tuoi messaggi vengono ricevuti due volte a causa di un interruttore difettoso lungo la linea? O se arrivano nell'ordine sbagliato?

Dato che stai pianificando un numero grande di connessioni, dovrai anche considerare l'aumento della probabilità che qualcosa non funzioni correttamente.

Inoltre, che succede se vuoi scalare la tua architettura in orizzontale, ad esempio aggiungendo più server? Non è possibile bilanciare il carico dei socket aperti e trasferirli senza problemi attraverso i nodi.

Alla fine raccomanderei l'uso di un protocollo di trasmissione dei messaggi più robusto, progettato in attesa di errori . In termini più semplici, considera ogni comunicazione atomica, dove il caso peggiore è una nuova connessione ogni volta. Più o meno lungo le linee del problema C10K .

Se hai ancora bisogno di essere più convincente, prova a testare la tua architettura con un modello: guarda come reagisce a dieci migliaia di client che si connettono contemporaneamente (è più facile in una LAN). Quindi immagina di aggiungere latenza di rete, errori, ecc.

    
risposta data 03.04.2014 - 17:39
fonte
4

I computer hanno un limite rigido di quante connessioni possono essere aperte al momento (deciso dal sistema operativo). I programmi ne vedono un sottoinsieme.

ogni socket aperto richiede alcune risorse e un heartbeat di timeout della rete in modo da poter rilevare le disconnessioni. Avendo un sacco di socket che inviano quei battiti cardiaci inizierà a riempire la larghezza di banda.

il mio suggerimento è di chiudere le connessioni in base alle esigenze e accettare solo la necessità di riaprirle.

    
risposta data 03.04.2014 - 15:20
fonte
1

L'esperienza suggerisce che esiste una soluzione migliore e probabilmente abbastanza diversa per il tuo problema.

Tuttavia, è possibile creare e mantenere un numero considerevole di connessioni socket per un lungo periodo di tempo con un'affidabilità inferiore al 100%.

Un design robusto sarebbe stato fatto in modo molto diverso.

Il problema è cosa succede quando il tuo server relay si blocca. Se si dispone di un solo server, il servizio verrà perso al 100%. Se si dispone di più server, i client possono riconnettersi e connettersi a un altro server, ma tutti i messaggi inviati a loro durante la disconnessione e la riconnessione saranno andati persi. A seconda del prodotto, questo potrebbe essere importante.

Se il tuo 'relay' è stato effettivamente implementato come un servizio di coda messaggi distribuito, fornisce un set di strumenti che risolve la maggior parte di questi problemi e fornisce un meccanismo per implementare il livello di robustezza e disponibilità che si adatta alla tua applicazione. / p>

Questa non è una raccomandazione, ma RabbitMQ è un esempio di un prodotto che può eseguire la funzione di inoltro per te. Ce ne sono altri, e dovrai rivedere una selezione per decidere quale sia la più appropriata per il tuo prodotto.

    
risposta data 03.04.2014 - 18:17
fonte
1

Dopo aver fornito il supporto per firewall e VPN per un paio d'anni, posso dire con certezza che le applicazioni che mantengono le porte aperte per un lungo periodo di tempo non sono stabili sia dal punto di vista del server locale che dal punto di vista della rete . Può anche essere un rischio per la sicurezza (se questa è una considerazione nel tuo caso).

Lasciare aperta una connessione persistente su una porta del server può potenzialmente causare un problema sul firewall poiché la tabella NAT accumula voci, per esempio.

Personalmente raccomando di mantenere i numeri dei client connessi nell'intervallo da 200 a 250 per server per le connessioni permanenti via TCP / IP, dove i dati inviati e ricevuti richiedono una latenza minima.

Se l'hardware è in grado di spostarsi su ATM (modalità di trasferimento asincrona), è possibile riconfigurare i client in modo che ascoltino solo il loro indirizzo specifico, che avrà un peso significativo dai server (a spese dei clienti). ATM dovrebbe portarti dai 300 ai 350 client attivi per capacità del server.

Per chiarire, la soluzione a questo problema è di mettere il tuo server in una DMZ sul firewall per migliorare l'accesso e utilizzare la connettività ATM con il maggior numero possibile di client. Altrimenti sei alla mercé del firewall di rete remoto e di altri router intelligenti intermedi.

    
risposta data 02.07.2015 - 01:38
fonte

Leggi altre domande sui tag