[C++] Threads en veel simultane verbindingen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • eppie
  • Registratie: Maart 2000
  • Niet online
(overleden)
Hallo,

Ik zit met een probleem waar ik niet echt uitkom en op internet kan ik ook niet echt vinden hoe dit gedaan word.

Ik heb een multi-threaded applicatie welke simultaan erg veel verbindingen moet afhandelen. Wanneer er een inkomende verbinding wordt opgezet krijgt deze een eigen thread om zo zijn ding te doen. Echter wanneer er meer dan 350+ verbindingen tegelijk bezig zijn is het niet meer mogelijk nieuwe threads aan te maken en starten.

Nou weet ik dat elke thread een ruimte op de stack alloceerd en dat deze ruimte vol is en dus geen nieuwe meer aangemaakt kunnen worden. Gewoon meer geheugen er bij inprikken is geen echte oplossing.

Nou vraag ik mij dus af hoe doen projecten als bijvoorbeeld apache dit dan? Dat 1 thread meerdere verbindingen afhandelden? Of dat de ene thread in sleep state gezet wordt en de andere op running?

Hopelijk hebben jullie hier antwoord op :)

Acties:
  • 0 Henk 'm!

  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 16:51
Hoe lang lopen je processen? Apache werkt met workers maar die verwerken vele korte requests. Als je echt je maximum aantal workers hebt en die processen stoppen niet dan verwacht ik zeker dat je tegen grenzen aan gaat lopen maar vaak is dit niet zo.

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Je gebruikt niet 1 thread per verbinding (socket), dat is veel te veel overhead (niet alleen stack space, maar ook context switches etc) en maakt je veel meer vulnerable voor aanvallen (meer resources in gebruik per aanvaller)

Gebruik een threadpool die alle verbindingen serveert. Zoek eens naar select() of lees source-code van andere server software :)

[ Voor 14% gewijzigd door MLM op 06-01-2010 11:28 ]

-niks-


Acties:
  • 0 Henk 'm!

  • eppie
  • Registratie: Maart 2000
  • Niet online
(overleden)
De processen kunnen allemaal tegelijk werken.

Er wordt al een ThreadPool gebruikt echter doet deze niets anders dan vast van te voren een aantal threads aanmaken en deze uitgeven. Maar dit zal wel niet het enige doel zijn van een threadpool. Ik ga ook is na select kijken en de source van apache.

Acties:
  • 0 Henk 'm!

  • DexterDee
  • Registratie: November 2004
  • Laatst online: 21:10

DexterDee

I doubt, therefore I might be

Ik neem even aan dat je met 'verbindingen' socket connecties bedoelt?

Als je hiervan heel veel hebt, kun je inderdaad geen thread per connectie meer maken, omdat je dan tegen je thread limiet loopt. De oplossing zit 'm in het maken van een broker thread die "werk" gaat uitdelen aan worker threads. Je maakt bijvoorbeeld 10 worker threads en een broker thread waar de listening socket afgehandeld wordt. In de broker thread accepteer je een nieuwe socket verbinding en kiest 1 van de 10 worker threads om deze verbinding af te handelen. De manier om dit te doen is de resource door te geven naar de worker thread en de referentie weg te gooien in de broker thread.

In een worker thread zit je vervolgens met meerdere socket resources, die je simultaan wil bedienen. Dit doe je door met socket_select de activiteit op de sockets uit te lezen en deze in je main loop af te handelen. Bijkomend voordeel is dat socket_select een yield doet (dmv een timeout) naar je OS zodat bij geen of weinig activiteit de CPU tijd teruggegeven wordt.

Op deze manier kun je met bijvoorbeeld 10 worker threads, 100 socket connecties per thread afhandelen. Zit je totaal al op 1000 connecties. Apache doet dit ook, die zet al een aantal worker threads klaar bij het starten van de server en delegeert vervolgens inkomende socket verbindingen naar deze workers.

Klik hier om mij een DM te sturen • 3245 WP op ZW


Acties:
  • 0 Henk 'm!

  • eppie
  • Registratie: Maart 2000
  • Niet online
(overleden)
Ja klopt socket connecties.

Het is me duidelijk dat je dus met een worker meerdere verbinding afhandeld, echter zal dit dan niet simultaan gaan maar meer van eerst 1 dan 2 enz? Of als het mogelijk is switchen?

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Zoals MLM al aangaf: gebruik select(). Daarmee kun je een verzameling van sockets tegelijk checken. 350 verbindingen is zo weinig, dat kun je met 1 select() in 1 thread nog doen.

Overigens, als je Windows gebruikt, dan is Asynchrone I/O nog effectiever. Dat gedraagt zich alsof Windows de threadpool voor jou managed.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • eppie
  • Registratie: Maart 2000
  • Niet online
(overleden)
We gebruiken linux. Ik zit alleen nog even te kijken hoe om te gaan met langdurige communicatie. Voorbeelden zoals op http://www.cse.nd.edu/~dt...09/project4/project4.html gaan uit van een simpele request afhandelen en dan de volgende taak oppakken.

Mij lijkt het daarom misschien wel handig om na een ftp server ofzo te kijken omdat die simultaan erg veel gebruikers kan serveren zonder dat andere verbindingen hoeven te wachten.

Acties:
  • 0 Henk 'm!

  • DexterDee
  • Registratie: November 2004
  • Laatst online: 21:10

DexterDee

I doubt, therefore I might be

eppie schreef op woensdag 06 januari 2010 @ 11:56:
Ja klopt socket connecties.

Het is me duidelijk dat je dus met een worker meerdere verbinding afhandeld, echter zal dit dan niet simultaan gaan maar meer van eerst 1 dan 2 enz? Of als het mogelijk is switchen?
Stel je de volgende situatie eens voor:
Je hebt 100 simultane gebruikers die naar jouw worker thread in je server-applicatie via een socket een bestand van 100 Mb sturen. Om die honderd gebruikers allemaal het idee te geven dat 'hun' upload vlotjes en soepel afgehandeld wordt, ondanks dat het allemaal in 1 executiepad zit, kun je het volgende doen:

Kijk met socket_select welke sockets activiteit hebben (e.g. welke sockets data aanbieden). In je main loop lees je van al die sockets bijvoorbeeld sequentieel 16Kb. Dit gaat razendsnel, omdat de TCP buffer al aanwezig is (de data van de clients is al fysiek in de TCP buffer van de server aanwezig). Je verwerkt al deze brokjes data in je main loop gaat de volgende iteratie in. Op die manier gaan alle downloads schijnbaar simultaan vooruit, ongeacht hoe lang het uploaden duurt.

Een foutieve oplossingsrichting zou zijn om al die 100 sockets serieel af te handelen, dus het inlezen van 100Mb van user 1, dan 100Mb van user 2, etc. Dan zou de 100ste user verschrikkelijk lang moeten wachten en zal waarschijnlijk een timeout krijgen.

Om ervoor te zorgen dat je TCP buffers niet te groot worden zal zowel de client als de server socket zich aan bepaalde regels moeten houden. Dat valt onder de categorie flow control en windowing van packets. Maar dat is een hele andere discussie.

Klik hier om mij een DM te sturen • 3245 WP op ZW


Acties:
  • 0 Henk 'm!

  • xos
  • Registratie: Januari 2002
  • Laatst online: 12-09 12:41

xos

Beetje afhankelijk wat je wilt doen maar het is vaak aan te raden om sendfile te gebruiken. Mocht je grote bestanden willen versturen dan is het meestal aan te raden om het bestand in een aantal blokken te versturen. Maar het is afhankelijk van wat je wilt realiseren.

Overigens zouden 350 threads voor een recente linux kernel geen problemen moeten opleveren. Of zijn deze 350 threads allemaal tegelijkertijd bezig?

Acties:
  • 0 Henk 'm!

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 15-07 15:35

leuk_he

1. Controleer de kabel!

Een treadpool voorkomt dat teveel threads tegelijk gaan lopen. Meer dan 2x het aantal lopende processen t.o.v. van CPU's kost alleen maar meer overhead voor het verwerken van je data. Dan is je OS bezig met context switches en cache-reload, en komt minder toe aan het echte werk dat de applicatie moet doen.

Memory gaat wel degelijk een rol spelen 200 x 2 MB= 4 GB, en dat is alleen nog maar stack. En je OS heeft wellicht ook (slecht gedocumenteerde) beperking wat betreft het aantal threads per proces. Kunnen aanmaken en efficient verwerken zijn 2 verschillldende dingen.

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:47
xos schreef op woensdag 06 januari 2010 @ 18:21:
Overigens zouden 350 threads voor een recente linux kernel geen problemen moeten opleveren. Of zijn deze 350 threads allemaal tegelijkertijd bezig?
Misschien is het probleem dat er teveel geheugen gemapt wordt. Standaard krijgt een thread 8MB stack space, die weliswaar niet direct geïnitialiseerd wordt, maar wel gealloceerd. Met 350 threads zit je dan al op 2.73 GB terwijl je in een standaard 32-bit kernel maximaal 3 GB in user space kunt mappen, dus dat is wel een limiet waar je tegenaan loopt.

Een eenvoudige fix zou het verlagen van de grootte van de stack zijn (niet-recursive programma's die geen belachelijke hoeveelheden data op de stack alloceren kunnen met veel minder dan die 8MB toe) maar dat is natuurlijk geen structurele oplossing. Een select-gebaseerde aanpak schaalt natuurlijk veel makkelijker, maar vereist wel dat je de hele structuur van je programma omvergooit (opeens moet je reactief programmeren, in plaats van dat je read/write calls kunt doen wanneer het je uitkomt).
Een treadpool voorkomt dat teveel threads tegelijk gaan lopen. Meer dan 2x het aantal lopende processen t.o.v. van CPU's kost alleen maar meer overhead voor het verwerken van je data. Dan is je OS bezig met context switches en cache-reload, en komt minder toe aan het echte werk dat de applicatie moet doen.
Als je met "lopende threads" runnable threads bedoelt, dan geef ik je gelijk, maar de TS heeft het over lang-lopende processen die zo af en toe op netwerktraffic (en wellicht andere events) moeten reageren, maar verder slapen. Zolang de die threads maar grotendeels inactief zijn, kan de kernel er makkelijk duizenden ondersteunen. De overhead is wellicht iets groter dan wanneer je 't in userspace zou afhandelen (met een select-gebaseerde aanpak, of bijvoorbeeld met fibers) maar op zichzelf hoeft de opzet niet desastreus te zijn voor de performance.

[ Voor 41% gewijzigd door Soultaker op 06-01-2010 18:45 ]


Acties:
  • 0 Henk 'm!

  • leuk_he
  • Registratie: Augustus 2000
  • Laatst online: 15-07 15:35

leuk_he

1. Controleer de kabel!

Soultaker schreef op woensdag 06 januari 2010 @ 18:38:
[...]

Als je met "lopende threads" runnable threads bedoelt, dan geef ik je gelijk, maar de TS heeft het over lang-lopende processen die zo af en toe op netwerktraffic (en wellicht andere events) moeten reageren, maar verder slapen.
Ja ik had het over processen die allemaal runable zijn, of enkel wachten op korte lokale I/O. Hoe dan ook loop je dus tegen limieten aan door elk client zijn eigen thread th geven. In eeerste instantie lijkt dit simpeler, maar als je de locking/concurrenty/deadlocking en performance problemen door te grove locks erbij trekt dan besef je pas waar je tegen aan kunt lopen door elke client zijn eigen proces te geven.

Zoals soultaker al aangeeft kun je met wat compiler configuratie werk of door op 64 bit kernels te gaan zitten wel wat (en factor 2 tot 10) winnen, maar niet zoveel als je model omgooien. (Top die ik gezien heb, miljoen clients op p2p servers)

Need more data. We want your specs. Ik ben ook maar dom. anders: forum, ff reggen, ff topic maken
En als je een oplossing hebt gevonden laat het ook ujb ff in dit topic horen.


Acties:
  • 0 Henk 'm!

  • eppie
  • Registratie: Maart 2000
  • Niet online
(overleden)
Het gaat om een stuk software dat met plc's communiceerd. En het kan zijn dat op een moment er wel 300 tegelijk aan het communiceren zijn. Het lijkt mij dat ik dus moet gaan zoeken richting een select oplossing met eventueel wat workers threads om gebruik te kunnen maken van meerdere cores.

Iig alvast bedankt voor de vele reacties! _/-\o_

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Aangezien je C++ gebruikt, zoek eens op boost.asio. Prima async communicatie framework. (zit ook een voorbeeld bij van een HTTP server met een io-service-per-CPU design)

[ Voor 32% gewijzigd door Zoijar op 07-01-2010 05:03 ]


Acties:
  • 0 Henk 'm!

  • igmar
  • Registratie: April 2000
  • Laatst online: 03-09 22:58

igmar

ISO20022

Zie Wikipedia: C10k problem voor een mooi verhaal (en dan vooral de link naar de kegel.com website). Threads zijn leuk, maar niet als je er een hele hoop nodig hebt (en dan hebben we het nog niet over de scheduling overhead).
Pagina: 1