IPC-architectuur

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Hallo,

Ik zit met he volgende probleem. Ik ben bezig met het opzetten van een architectuur voor een mogelijk gedistribueerd systeem (voor load balancing). Ik heb een punt waar requests binnen komen (dispatcher) en vanuit hier wordt - afhankelijk van de load van de verschillende workers - de binnengekomen request aan een worker toegekend.

Dit is wat ik nu heb aan architectuur:
Afbeeldingslocatie: http://www.freeimagehosting.net/uploads/th.f6fafffe1e.png

Wat ik nu wil is dat het voor de dispatcher totaal transparant is waar de worker zich bevind of het een lokaal process is of een remote, moet niet uitmaken.

Nu vraag ik me af hoe ik dit het efficientste kan bereiken in .net. Is .NET Remoting de oplossing, of kan ik beter voor een WCF oplossing gaan (als dat al mogelijk is..?) of is er een andere manier/techniek wat jullie me aanraden?
Performance is overigens een belangrijke issue hier.

Edit:
Ik wil eigenlijk dus een interface wat geimplementeerd wordt door alle workers wat gebruikt kan worden door de dispatcher. En dat het voor de dispatcher dus niet uitmaakt hoe de interface geimplementeerd is.

[ Voor 11% gewijzigd door Data-base op 30-12-2008 14:31 ]


Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Ik heb geen ervaring met WCF, maar dit kan je zeker mbv Remoting oplossen.

Hierbij maak je een vaste interface die zowel lokaal als remote kan geimplementeerd worden. Via configuratie haal je dan de remote workers op voor het programma start en creer je de lokale workers.

Uiteindelijk kun je naar believen gaan dispatchen.

Ik weet niet welke data jij processed, maar het kan handig zijn om elk work item een schatting mee te geven en ook volgens die schatting te werken. Grote datasets wil je misschien niet zomaar over je netwerk dumpen met Remoting (of met WCF), of je wil je load-balancer zelf misschien niet gaan overbelasten met grote work items en enkel kleine korte items lokaal doen.

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
H!GHGuY schreef op vrijdag 02 januari 2009 @ 10:22:
Ik heb geen ervaring met WCF, maar dit kan je zeker mbv Remoting oplossen.

Hierbij maak je een vaste interface die zowel lokaal als remote kan geimplementeerd worden. Via configuratie haal je dan de remote workers op voor het programma start en creer je de lokale workers.

Uiteindelijk kun je naar believen gaan dispatchen.

Ik weet niet welke data jij processed, maar het kan handig zijn om elk work item een schatting mee te geven en ook volgens die schatting te werken. Grote datasets wil je misschien niet zomaar over je netwerk dumpen met Remoting (of met WCF), of je wil je load-balancer zelf misschien niet gaan overbelasten met grote work items en enkel kleine korte items lokaal doen.
Ik heb naar remoting gekeken en zit daarbij met het volgende probleem:
Mn worker moet kunnen communiceren met mn dispatcher en dispatcher met worker. Dat betekent dus dat beide zowel server als client zijn. Dit betekent ook dat beide van elkaar moeten weten op implementatieniveau, wat leidt tot circular references ;(
Daarnaast heb ik het idee dat het te veel overhead met zich mee brengt.

Het enige wat ik wil doen is seinen tussen de twee delen van mn programma. Ik ga dan ook de data zelf niet doorgeven van de dispatcher naar de worker. De dispatcher geeft een uri aan de worker.

Ik ben nu aan het kijken naar een oplossing waarbij een dispatcher tegen een "virtuele" worker aanpraat. Wanneer er een functie wordt aangeroepen op de virtuele worker, wordt er onder water met sockets een berichtje gestuurd naar de echte worker. En vv idem. Volgens mij is dat een oplossing wat beter is que performance.

Ik hoor graag wat jullie ervan vinden :)

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Je kan dat gerust oplossen. In Remoting kan je 2-way werken voor zover ik weet.

Oplossing 1:
Je voorziet de worker van een callback/delegate. Aan de dispatcher kant registreer je een lokaal object.

Oplossing 2:
Je voorziet een dispatcher interface en geeft de dispatcher mee aan de worker.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
// in aparte remote interfaces assembly, common voor client/server
public struct WorkItemDoneEventArgs
{
   Uri workUri;
   Uri resultUri;
}
public delegate void WorkItemDoneEvent(object sender, WorkItemDoneEventArgs args);
public interface IWorker
{
  void QueueWorkItem(Uri workUri);
  event WorkItemDoneEvent WorkItemDone;
}

C#:
1
2
3
4
5
6
7
8
9
// in aparte remote interfaces assembly, common voor client/server
public interface IDispatcher
{
  void WorkItemDone(Uri workUri, Uri resultUri);
}
public interface IWorker
{
  void QueueWorkItem(IDispatcher dispatcher, Uri workUri);
}

In dit laatste voorbeeld implementeert de client de IWorker en de server de IDispatcher.

edit:
Lees jezelf ook op voorhand in over lifetime van remote objecten, security, performance, etc.
Ze kunnen je veel problemen besparen.

Je zal waarschijnlijk het best kunnen vergelijken als je even snel een dummy client-server applicatie maakt met beide technologieen. Vooral Remoting heeft als doel om remote/local te abstraheren. Over WCF kan ik wegens gebrek aan ervaring echter weinig zeggen.

[ Voor 16% gewijzigd door H!GHGuY op 03-01-2009 12:27 ]

ASSUME makes an ASS out of U and ME


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Ik ga er eens mee aan de slag! Ik zal laten weten wat mn ervaringen waren!
Bedank!

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Wat je in je achterhoofd moet houden is dat distributie nooit transparant is, ook al kan je het code technisch wel volledig transparant maken. Je zult er altijd rekening mee moeten houden dat netwerk communicatie ordes van grote trager is dan dan in memory communicatie en verder is het veel minder betrouwbaar.

Je zult je dus altijd af moeten vragen: zou ik hier wel distributed willen werken? En kan ik distributie misschien op het allerhoogste nivo al afvangen zodat het daarna mooi op een machine kan blijven (ipv de hele tijd het netwerk over wordt gepompt). Hou dus rekening met zaken zoals processer en server affinity, als je dat niet doet zal je systeem wel eens serieuze performance problemen kunnen krijgen.

ps:
Verder zou ik enorm oppassen met te veel synchrone communicatie en callbacks. Binnen no time heb je een distributed deadlock in je systeem.

[ Voor 21% gewijzigd door Alarmnummer op 08-01-2009 11:46 ]


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Alarmnummer schreef op donderdag 08 januari 2009 @ 11:37:
Wat je in je achterhoofd moet houden is dat distributie nooit transparant is, ook al kan je het code technisch wel volledig transparant maken. Je zult er altijd rekening mee moeten houden dat netwerk communicatie ordes van grote trager is dan dan in memory communicatie en verder is het veel minder betrouwbaar.

Je zult je dus altijd af moeten vragen: zou ik hier wel distributed willen werken? En kan ik distributie misschien op het allerhoogste nivo al afvangen zodat het daarna mooi op een machine kan blijven (ipv de hele tijd het netwerk over wordt gepompt). Hou dus rekening met zaken zoals processer en server affinity, als je dat niet doet zal je systeem wel eens serieuze performance problemen kunnen krijgen.

ps:
Verder zou ik enorm oppassen met te veel synchrone communicatie en callbacks. Binnen no time heb je een distributed deadlock in je systeem.
Ik snap niet precies wat je bedoeld met distributie op het hoogste niveau afvangen? Wat moet ik me daarbij voorstellen?

Zover ik kan bedenken kan ik op termijn niet anders dan distributed. Het probleem is namelijk als volgt: Mijn software moet een hele hoop (zo veel mogelijk) requests kunnen processesen. Het processen van een request duurt tussen de 4 en 20 minuten (grofweg). In een ideaal geval kan ik dus op een quad-core 4 requests tegerlijk afhandelen (en ja als een request wordt geprocessed is die ook echt bezig, meer threads die tegerlijk processen heeft geen zin).
Dit is op termijn te weinig throughput, wat ik dus wil is een lan waarin een request binnen komt op bij een centrale (web)server. Deze request wordt aan een bepaalde machine toegekend (door een simpele notificatie) en deze machine plaatst deze request in zijn queue.

Zover ik zie heb ik geen andere alternatief. Overigens moet ik er wel bij vermelden dat ik heb besloten om niet met RPC (.net remoting) te gaan werken. Ik ga gewoon messages sturen via sockets aangezien de enige communicatie tussen worker en dispatcher zal zijn:

* Dispatch -> Worker : Handle request met id 5 af. Data staat op locatie uri://x/y
* Worker -> Dispatch : Ack (mn RAW queue bevat nu X items)

*Worker->Dispatch: Mn Raw queue bevat nu X items en mn preprocessed queue bevat Y items

*Worker->Notifier: Ik heb request met ID X af. Resultaat te vinden op locatie uri://x/y
*Notifier->Worker: Ack

Ik denk dat dit met sockets en strings een stuk beter performed dan wanneer ik .net remoting (of welke andere ipc dan ook) ga gebruiken.

Acties:
  • 0 Henk 'm!

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Data-base schreef op donderdag 08 januari 2009 @ 15:13:
[...]
wat ik dus wil is een lan waarin een request binnen komt op bij een centrale (web)server. Deze request wordt aan een bepaalde machine toegekend (door een simpele notificatie) en deze machine plaatst deze request in zijn queue.
Het zit er naar uit dat je dus parallellisatie op hoog nivo toe past. Nadat request is opgepakt door een machine, zal het daar ook blijven ipv continu het netwerk overgepompt worden.

Zoals je merkt heb je wel vrij cruciale informatie achter gehouden ;)
Ik denk dat dit met sockets en strings een stuk beter performed dan wanneer ik .net remoting (of welke andere ipc dan ook) ga gebruiken.
Het zal wellicht beter performen, maar stel dat het van 100ms terug naar naar 50ms maar een request is nog steeds tig minuten bezig, maakt het uiteindelijk niet veel uit voor de throughput of latency van een systeem. Je moet je bij iedere optimalisatie afvragen wat zijn invloed is op de totaal tijd.

"premature optimization is the root of all evil"

PS:
Kan je het niet gewoon oplossen met een message queue?

Je front end die het bericht ontvangt plaatst de request op een topic en een node die beschikbaar is die pakt het bericht er weer af. Nadat een node het bericht heeft verwerkt zet je het resultaat weer op een ander topic. Eventueel kun je nog functionaliteit inbouwen voor failover van nodes (bericht opnieuw plaatsen op een topic op het moment dat een bepaalde periode overschreden is). Maar dit is wel van een aantal factoren afhankelijk, zoals de size van het request en response (heb geen flauw idee wat msmq leuk vindt).

[ Voor 20% gewijzigd door Alarmnummer op 08-01-2009 15:35 ]


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Als je met meerdere machines gaat werken is Remoting via IPC geen oplossing. Je zult dan moeten terug vallen op de Http of Tcp Channels.. Zie ook de MSDN IPC documentie.

Als een machine tig minuten bezig is met een task is er eigenlijk geen noodzaak voor directe communicatie. Je geeft zelf al aan dat de dispatcher de payload van de task wegschrijft naar (een (tabel)queue op) de database. Kun je daarbij dan niet direct aangeven voor welke listener het request moet oppakken? Als een task 20 minuten kost, maakt het toch ook niet meer uit dat deze met een delay van zeg maximaal 30 seconden wordt uitgevoerd?

Maar als de task zelf tig minuten duurt, kun je dan niet beter kijken naar de optimalisatie van de task processing? Waar in je task zit de performance drop? Een aantal maanden geleden kwam ik bij een bedrijf een import service tegen welke meerdere machines kon aanspreken. Dit was noodzakelijk omdat de imports veel tijd in beslag namen. Echter bij profiling van de import bleek dat men een xml document als DOM probeerde in te lezen. Omdat het XML documenten zelf tussen de 200 en 750 MB waren raakte de machine al snel door het werk geheugen. Echter de processor load van de import zelf kwam nooit boven de 4% uit.

Door de import te verwerken middels een SAX parser en vervolgens alleen de product fragmenten als XmlDocument in te lezen (en dus niet de volledige product catalog) in combinatie met een thread dispatcher kon de import processing tijd worden verkort van gemiddeld 52 minuten naar 5 minuten. De bottleneck zit nu bij de database en de grote hoeveelheid queries daarop. Zodra de import is voltooid wordt gekeken of er nog een nieuw request aanwezig is en anders polled de service de FTP server elke 3 minuten.

Er zijn weinig langdurige processen welke sequentieel dienen te worden uitgevoerd. Zeker data processing tasks zijn goed te optimaliseren door gebruik van de juiste parser techniek en het gebruik van threads. Pas als tijdens de import je processor continue continue boven de 80% processor load zit heeft het eigenlijk pas zin om te kijken naar het gebruik van meerdere machines. Is de processor load lager dan geeft dat eigenlijk aan dat je op de verkeerde plek aan het optimaliseren bent..

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
Alarmnummer schreef op donderdag 08 januari 2009 @ 15:28:
Het zal wellicht beter performen, maar stel dat het van 100ms terug naar naar 50ms maar een request is nog steeds tig minuten bezig, maakt het uiteindelijk niet veel uit voor de throughput of latency van een systeem. Je moet je bij iedere optimalisatie afvragen wat zijn invloed is op de totaal tijd.

"premature optimization is the root of all evil"
Daar heb je idd wel een punt, helemaal niet aan gedacht wat stom! Zal er nog eens een keer goed over nadenken en er wat aan rekenen.
PS:
Kan je het niet gewoon oplossen met een message queue?

Je front end die het bericht ontvangt plaatst de request op een topic en een node die beschikbaar is die pakt het bericht er weer af. Nadat een node het bericht heeft verwerkt zet je het resultaat weer op een ander topic. Eventueel kun je nog functionaliteit inbouwen voor failover van nodes (bericht opnieuw plaatsen op een topic op het moment dat een bepaalde periode overschreden is). Maar dit is wel van een aantal factoren afhankelijk, zoals de size van het request en response (heb geen flauw idee wat msmq leuk vindt).
In principe is dat toch wat er gebeurt, alleen neemt de centrale punt (mn dispatcher dus) het initiatief ipv een vrije node.
Vraag me af wat de voor en nadelen zijn deze verschillende aanpakken.
Niemand_Anders schreef op donderdag 08 januari 2009 @ 17:54:
Als je met meerdere machines gaat werken is Remoting via IPC geen oplossing. Je zult dan moeten terug vallen op de Http of Tcp Channels.. Zie ook de MSDN IPC documentie.

Als een machine tig minuten bezig is met een task is er eigenlijk geen noodzaak voor directe communicatie. Je geeft zelf al aan dat de dispatcher de payload van de task wegschrijft naar (een (tabel)queue op) de database. Kun je daarbij dan niet direct aangeven voor welke listener het request moet oppakken? Als een task 20 minuten kost, maakt het toch ook niet meer uit dat deze met een delay van zeg maximaal 30 seconden wordt uitgevoerd?
De payload is een rar-file of een txt-file. Deze wordt door een gebruiker geupload. De dispatcher geeft aan een worker de locatie van een rar of txt. Ik zou natuurlijk een centrale tabel kunnen maken waarin een worker op kan zoeken wat zn volgende klus is, maar dan wordt mn centrale database de hotspot waardoor t slechter schaalbaar wordt.
Maar als de task zelf tig minuten duurt, kun je dan niet beter kijken naar de optimalisatie van de task processing? Waar in je task zit de performance drop? Een aantal maanden geleden kwam ik bij een bedrijf een import service tegen welke meerdere machines kon aanspreken. Dit was noodzakelijk omdat de imports veel tijd in beslag namen. Echter bij profiling van de import bleek dat men een xml document als DOM probeerde in te lezen. Omdat het XML documenten zelf tussen de 200 en 750 MB waren raakte de machine al snel door het werk geheugen. Echter de processor load van de import zelf kwam nooit boven de 4% uit.
Dat ga ik zeker nog doen, ik heb een prototype van de processing unit gemaakt en die kan vast wel nog hier en daar geoptimaliseerd worden. Maar echt veel zal t niet zijn gezien de CPU 100% aan het knallen is.
Het gaat om pattern matching in gigantische veel tekst.
Ik bereken hoeveel een ingezonden stuk tekst overeenkomt met een (statische) database waarin +/- 50.000 teksten staan. Nu hoef ik de ingezonden teksten natuurlijk alleen te vergelijken met teksen met dezelfde onderwerp, maar dat is nog steeds een hoop werk.
Even voor t idee, 1 request bestaat uit grofweg 30 teksten van 3.000 woorden. Per tekst moet ik in de database zoeken naar teksten met ongeveer dezelfde onderwerp (schat dat ik per tekst ongeveer 250 resultaten krijg van 3.000 woorden). Ik moet dus 30×250 afstandsmaten berekenen plus nog mn database queries.
Pagina: 1