[alg] concurrency problematiek client/server apps *

Pagina: 1
Acties:

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik ben op dit moment mijn geheugen weer eens aan het opfrissen over concurrency problematiek (en dan vooral mbt enterprise/clientserver applicaties) en ik vraag me af hoe jullie dit soort problemen oplossen.

Maken jullie gebruik van een framework zoals EJB waarbij het verboden is om zelf threads aan te maken. De EJB applicatie server zorgt er wel voor dat er geen race problemen optreden, en weet wat te doen bij deadlocks.

Maken jullie gebruik van zelf gebouwde systemen waarbij je de concurrency control zelf oplost? (eventueel mbv een collectie patterns en synchronisatie bouwstenen) Dit is een uiterst complexe zaak en het lijkt me niet dat er veel mensen zijn die dit echt kunnen.

Maken jullie een applicatie waarbij alles op 1 thread wordt afgehandeld? Dit is natuurlijk prachtig om te ontwikkelen omdat je de concurrency problematiek bij de voordeur kan laten staan. Helaas blijft de performance ook bij die voordeur staan.

Maken jullie applicaties en douwen er een lading synchronisatie elementen erin en dan maar op hoop van zegen? Dus hopen dat er geen race problemen zich voortdoen (dat lukt wel als je er maar genoeg synchronisatie erin drukt) en al helemaal geen deadlocks. De performance van dit soort systemen is per definitie bager omdat je waarschijnlijk te veel loopt te syncronizen (of te weinig met als gevolg allerlei raceproblematiek).

[ Voor 15% gewijzigd door Alarmnummer op 29-07-2004 16:13 ]


  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
Als je bijvoorbeeld naar .Net webservices kijkt, dan is het de bedoeling dat elke "webmethod" aan ACID properties voldoet. Als je alleen met de database praat, dan voldoet transacties op database niveau. En anders zul je wellicht op de COM+ transactietour moeten.

Maar daarbij los je nog niet de problematiek op met dat de gebruiker naar een kopie van de data zit te gebruiken. Op database niveau gebruik ik daarvoor optimistic locking. Op GUI niveau probeer ik dat op ongeveer schermniveau te voorkomen door pessimistic locking door degene die als eerste is zowel schrijven toe te laten staan en mensen die later komen alleen lezen. Dat was toevallig voor deze applicatie geschikt gedrag.

Maar ik heb het idee dat Alarmnummer het wil hebben over asynchroon gedrag op server niveau?

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Infinitive schreef op 29 juli 2004 @ 16:31:
Maar ik heb het idee dat Alarmnummer het wil hebben over asynchroon gedrag op server niveau?
Yep.. Het gaat me dus niet zozeer om data uit de database, maar bv om objecten op een server. Bv een webserver. Een singlethreaded webserver is te traag, dus zul je meerdere threads moeten gebruiken. Maar waarschijnlijk heb je een hele zwik met objecten staan (misschien loggers, protocolhandlers, cachingzaken etc) waar gecommuniceerd mee moet worden. Hoe zorg je ervoor dat je in complexe object omgevingen je concurrency control zaken goed voor elkaar krijgt. (En je krijgt ook nog eens te maken met crashende clients, dus al je synchronisatie structuren moeten ook weer goed worden gezet)

Ik ben zelf iemand die kijkt naar allerlei bestaande structuren en probeer dat weer toe te passen en ze met elkaar te vergelijken. Maar iedere keer heb ik bij concurrency problematiek het gevoel: hoe meer ik weet, hoe onzekerder ik word.

[ Voor 7% gewijzigd door Alarmnummer op 29-07-2004 16:42 ]


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Alarmnummer schreef op 29 juli 2004 @ 16:35:
Een singlethreaded webserver is te traag.
Dat is IMO niet per definitie zo. Met een select() model of met IO completion kom je volgens mij behoorlijk ver met een single-threaded design.
Verder hangt het af van wat je precies serveert. Serveer je alleen static pages dan is een single-threaded design zo gek nog niet.
Als je met een DB moet praten, moet je dat of op een non-blocking manier doen of daar een (of meerdere) helper-threads voor gebruiken.
Kan het afhandelen van een request erg lang duren, dan is een multi-threaded design waarschijnlijk beter.

Maar het hangt grotendeels af van de complexiteit van je requests/responses.

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
OlafvdSpek schreef op 29 juli 2004 @ 20:24:
Dat is IMO niet per definitie zo. Met een select() model
Dit is al de 2e keer dat ik dit vandaag tegenkom :) Dat moet ik dus even gaan bekijken.
Maar het hangt grotendeels af van de complexiteit van je requests/responses.
De webserver was even een voorbeeld. Ik wil graag weten hoe jullie multithreaded client server omgevingen omzetten. Ik ben geen noob op het gebied van concurrency, maar het valt me op dat me dit altijd veel meer tijd kost dan andere onderdelen. KLeine dingetjes gaan dan ook nog wel, maar het kan al zo snel zo complex worden.. dat ik me dus echt afvraag hoe en of jullie hiermee omgaan.

  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
In een praktijksituatie heb ik eigenlijk niet veel ingewikkelders gebruikt dan simpele critical sections zeg maar. Hoewel er veel "ingewikkelde" manieren zijn voor concurrency control, was dat in die situaties ook niet echt nodig. Doorgaans heb ik in veel gevallen toch vooral alleen met een dbms te maken en die hebben het concurrency zaakje wel goed voor elkaar. Voor zaken als logging en dergelijke houd ik het bij zo'n cirtical section. Wanneer dat niet snel genoeg zou zijn, dan zien we wel weer. Bijv. bij logging naar een file is het zonde om dat volledig binnen een critical section te doen (weg concurrency). Dan maar een aparte logging thread met synchronized queue.

Maar jij bent waarschijnlijk met iets ingewikkelders bezig. Je praat o.a. over clients die kunnen crashen en daarmee mogelijk locking problemen veroorzaken. Je hebt waarschijnlijk een ingewikkeldere heen en weer communicatie dan een typische stateless request-response (zonder mogelijkheid tot callbacks naar de client). Want voor dat laatste geval zijn concurrency garanties eenvoudig te geven.

Misschien dat je nog een voorbeeldje kan geven?

[ Voor 4% gewijzigd door Infinitive op 29-07-2004 22:22 ]

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Alarmnummer schreef op 29 juli 2004 @ 21:22:
De webserver was even een voorbeeld. Ik wil graag weten hoe jullie multithreaded client server omgevingen omzetten.
Als de eis multi-threaded is, dan is het niet anders, maar anders kan het dus ook gewoon single-threaded.
Voor iets als een FTPd/SSHd heb je misschien niet eens shared state dus ook geen locking. Voor een IRCd heb je erg veel shared state, etc.
Dus het hangt heel erg af van de exacte toepassing, de hoeveelheid shared state en de tijdsduur van de 'transacties' op die shared state.

Een voorbeeld is dus misschien wel handig ja.
Het performance niveau dat je wilt halen speelt ook mee.
10 open TCP links of 50000?
10 kbit traffic of 1 gbit?
1 CPU of 8+?

[ Voor 15% gewijzigd door Olaf van der Spek op 29-07-2004 23:16 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
OlafvdSpek schreef op 29 juli 2004 @ 23:14:
Als de eis multi-threaded is, dan is het niet anders, maar anders kan het dus ook gewoon single-threaded.
Als het aan mij lag maakte ik ook alleen maar singlethreaded applicaties. Helaas zal niet iedere gebruiker me dit in dank afnemen. En het gaat me ook niet om de discussie singlethreaded vs multithreaded, maar wel om hoe jullie omgaan met client/server + multithreaded problematiek.

Ik wil dus weten hoe jullie er dus mee omgaan. Wat voor technieken jullie gebruiken. Waar jullie onzeker over zijn, wat jullie anders willen zien. Misschien patterns of andere ontwerp tips.

Verwijderd

Sowieso is het wel handig om concurrency mee te nemen in je ontwerp, en te proberen je diverse onderdelen zo min mogelijk met elkaar te laten communiceren; Dan verminder je al de hoeveelheid locking die je nodig hebt. Als je moet locken, kan het een optie zijn om het object waaruit je gegevens nodig hebt bijvoorbeeld met een eenvoudige critical section te locken, de gegevens er uit te kopieren en het direct weer te unlocken. Zo houd je de lock tijden beperkt.

Ook kun je eventueel gebruik maken van aparte read en write locks (wat bijvoorbeeld handig is voor het 'cache' voorbeeld uit deze thread). Een write lock kan slechts op een object gezet worden als er geen openstaande read locks meer zijn. Als er geen wachtende write lock is krijgt een read lock altijd toegang. Locks kan je queuen als er een write lock verzocht wordt. Er zijn voor zover ik weet geen standaard synchronisatieprimitieven in windows die dit doen, maar met wat critical sections kan je dit zelf vrij eenvoudig bouwen.

Voor het vermijden van deadlocks zijn een aantal vrij eenvoudige regeltjes waar je aan kunt voldoen waardoor dit probleem niet (vaak) meer optreedt. Ik zal nog even zoeken of ik er een artikeltje over kan vinden aangezien 't wel een heel verhaal is...

  • Infinitive
  • Registratie: Maart 2001
  • Laatst online: 25-09-2023
Voor mensen die meer willen weten over concurrency en oplossingen, kan ik verwijzen naar Diktaat van Gedistribueerd Programmeren @cs.uu.nl (postscript formaat). Het is introductiewerk dus niet echt geschikt om te discussieren in dit topic. Hoewel de bespreking van de relatie tussen concurrency control en het constraint satisfaction probleem wellicht wel interessant is.

putStr $ map (x -> chr $ round $ 21/2 * x^3 - 92 * x^2 + 503/2 * x - 105) [1..4]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23-05 18:13
Ik wilde de link van Infinitive even inzien maar ik heb geen GhostScript ter beschikking; kan iemand misschien een PDF versie ervan maken?

Het is toch gelukt. Een PDF versie is hier te vinden: gp.pdf

[ Voor 32% gewijzigd door Soultaker op 30-07-2004 19:43 ]


Verwijderd

Alarmnummer schreef op 30 juli 2004 @ 01:18:
Als het aan mij lag maakte ik ook alleen maar singlethreaded applicaties. Helaas zal niet iedere gebruiker me dit in dank afnemen. En het gaat me ook niet om de discussie singlethreaded vs multithreaded, maar wel om hoe jullie omgaan met client/server + multithreaded problematiek.
Je vermijdt de discussie omdat je het niet helemaal begrijpt volgens mij. Je kunt in een enkele thread meerdere clients serven door non-blocking IO en poll() (of select(), maar select() schaalt niet naar duizenden clients). Je krijgt dan dus een event-driven server waarin elk client-object callback-routines heeft die worden aangeroepen bij het arriveren van data, bij de mogelijkheid om meer data naar een client te schijven, of bij een fout van de client (verbroken connectie ed.). Zo'n server is (bijna) per definitie sneller dan een server met een thread per client omdat er geen context switching hoeft plaats te vinden; en hij schaalt ook beter (met 10.000 clients betekent dat 10.000 threads en ontzettend veel context switches).

Het voordeel van multithreaded schrijven is dat je elke thread als een "single client server" kunt schrijven ipv. een event-driven framework, maar het nadeel is de moeilijkheden met synchen die je jezelf op de hals haalt.
Ik wil dus weten hoe jullie er dus mee omgaan. Wat voor technieken jullie gebruiken. Waar jullie onzeker over zijn, wat jullie anders willen zien. Misschien patterns of andere ontwerp tips.
Ik gebruik semaforen, mutexen, spinlocks (critical sections) en rwlocks, de basisprimitieven dus. Persoonlijk maak ik de meeste fouten met objecten waarop meerdere mutexen (of anderer synchers) gezet zijn; unlock je die mutexen in de verkeerde volgorde (de goede volgorde is soms contra-intuitief) dan veroorzaak je deadlocks.

Hoewel ik al meer dan 15 jaar geregeld multithreaded servers schrijf maak ik dus nog steeds fouten waar erg veel debugging tijd in gaat zitten; en mijn peroonlijk advies is dan ook: gebruik geen threads als het ook anders kan, threads hebben pas zin wanneer het client-server protocol ingewikkelder is dan de locking problematiek, anders is het overkill.
Pagina: 1