Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
De term, schaalbaarheid, wordt vaak misbruikt. Voor deze sectie wordt een dubbele definitie opgegeven:
- Schaalbaarheid is de mogelijkheid om volledig gebruik te maken van de beschikbare verwerkingskracht op een multiprocessorsysteem (2, 4, 8, 32 of meer processors).
- Schaalbaarheid is de mogelijkheid om een groot aantal clients te onderhouden.
Deze twee gerelateerde definities worden meestal omhoog schalengenoemd. Het einde van dit onderwerp bevat tips over uitschalen.
Deze discussie richt zich uitsluitend op het schrijven van schaalbare servers, niet op schaalbare clients, omdat schaalbare servers meer algemene vereisten zijn. In deze sectie wordt ook de schaalbaarheid in de context van RPC- en RPC-servers alleen besproken. Aanbevolen procedures voor schaalbaarheid, zoals het verminderen van conflicten, het voorkomen van frequente cachemissers op globale geheugenlocaties of het voorkomen van onwaar delen, worden hier niet besproken.
RPC Threading Model
Wanneer een RPC-aanroep wordt ontvangen door een server, wordt de serverroutine (managerroutine) aangeroepen op een thread die wordt geleverd door RPC. RPC maakt gebruik van een adaptieve threadgroep die toeneemt en afneemt naarmate de workload fluctueert. Vanaf Windows 2000 is de kern van de RPC-threadpool een voltooiingspoort. De voltooiingspoort en het gebruik ervan door RPC zijn afgestemd op nul tot lage conflictserverroutines. Dit betekent dat de RPC-threadgroep het aantal onderhoudsthreads agressief verhoogt als sommige worden geblokkeerd. Het werkt op het vermoeden dat blokkeren zeldzaam is en als een thread wordt geblokkeerd, is dit een tijdelijke voorwaarde die snel wordt opgelost. Deze benadering maakt efficiëntie mogelijk voor servers met weinig conflicten. Een void call RPC-server die werkt op een acht processor 550MHz-server die wordt geopend via een SAN (High Speed System Area Network) dient bijvoorbeeld meer dan 30.000 ongeldige aanroepen per seconde vanaf meer dan 200 externe clients. Dit vertegenwoordigt meer dan 108 miljoen oproepen per uur.
Het resultaat is dat de agressieve threadpool daadwerkelijk in de weg komt wanneer conflicten op de server hoog zijn. Ter illustratie stelt u zich een zware server voor die wordt gebruikt voor externe toegang tot bestanden. Stel dat de server de eenvoudigste aanpak gebruikt: het leest/schrijft het bestand synchroon op de thread waarop die RPC de serverroutine aanroept. Stel ook dat we een server met vier processoren hebben die veel clients bedienen.
De server begint met vijf threads (dit varieert eigenlijk, maar er worden vijf threads gebruikt voor het gemak). Zodra RPC de eerste RPC-aanroep heeft opgehaald, wordt de aanroep naar de serverroutine verzonden en wordt de I/O van de serverroutine door de serverroutine opgegeven. Zelden mist het de bestandscache en blokkeert het wachten op het resultaat. Zodra de thread wordt geblokkeerd, wordt de vijfde thread vrijgegeven om een aanvraag op te halen en wordt er een zesde thread gemaakt als een hot stand-by. Ervan uitgaande dat elke tiende I/O-bewerking de cache mist en 100 milliseconden (een willekeurige tijdwaarde) blokkeert en ervan uitgaande dat de server met vier processors ongeveer 20.000 aanroepen per seconde (5.000 aanroepen per processor) verwerkt, zou een eenvoudige modellering voorspellen dat elke processor ongeveer 50 threads spakt. Hierbij wordt ervan uitgegaan dat een aanroep die elke 2 milliseconden wordt geblokkeerd, en na 100 milliseconden wordt de eerste thread weer vrijgemaakt, zodat de pool ongeveer 200 threads (50 per processor) zal stabiliseren.
Het werkelijke gedrag is ingewikkelder, omdat het grote aantal threads extra contextswitches veroorzaakt die de server vertragen en ook de snelheid van het maken van nieuwe threads vertragen, maar het basisidee is duidelijk. Het aantal threads gaat snel omhoog wanneer threads op de server beginnen te blokkeren en te wachten op iets (of een I/O of toegang tot een resource).
RPC en de voltooiingspoort waarmee binnenkomende aanvragen worden gepoort, proberen het aantal bruikbare RPC-threads op de server te behouden dat gelijk is aan het aantal processors op de computer. Dit betekent dat op een server met vier processoren, zodra een thread terugkeert naar RPC, als er vier of meer bruikbare RPC-threads zijn, de vijfde thread geen nieuwe aanvraag mag ophalen en in plaats daarvan in een hot stand-bystatus wordt geplaatst als een van de momenteel bruikbare threadsblokken wordt geblokkeerd. Als de vijfde thread lang genoeg wacht als een hot stand-by zonder het aantal bruikbare RPC-threads onder het aantal processors te laten vallen, wordt deze uitgebracht, dat wil gezegd, zal de threadpool afnemen.
Stel u een server voor met veel threads. Zoals eerder uitgelegd, eindigt een RPC-server met veel threads, maar alleen als de threads vaak worden geblokkeerd. Op een server waar threads vaak worden geblokkeerd, wordt een thread die terugkeert naar RPC binnenkort uit de hot standby-lijst gehaald, omdat alle momenteel bruikbare threads blokkeren en een aanvraag wordt gegeven om te verwerken. Wanneer een thread wordt geblokkeerd, wordt de thread-dispatcher in de kernel overgeschakeld naar een andere thread. Deze contextswitch verbruikt zelf CPU-cycli. De volgende thread voert verschillende code uit, krijgt toegang tot verschillende gegevensstructuren en heeft een andere stack, wat betekent dat de slagsnelheid van de geheugencache (de L1- en L2-caches) veel lager is, wat resulteert in een tragere uitvoering. De talrijke threads die tegelijkertijd worden uitgevoerd, verhogen conflicten voor bestaande resources, zoals heap, kritieke secties in de servercode, enzovoort. Dit verhoogt de conflicten als konvooien op de vorm van resources. Als het geheugen laag is, veroorzaakt de geheugendruk die wordt uitgeoefend door het grote en groeiende aantal threads paginafouten, waardoor de snelheid waarmee de threads worden geblokkeerd, verder toeneemt en er nog meer threads worden gemaakt. Afhankelijk van hoe vaak het blokkeert en hoeveel fysiek geheugen beschikbaar is, kan de server zich stabiliseren op een lager prestatieniveau met een hoge snelheid van de contextwissel, of het kan verslechteren tot het punt waar het slechts herhaaldelijk toegang heeft tot de harde schijf en context schakelen zonder daadwerkelijk werk uit te voeren. Deze situatie zal natuurlijk niet worden weergegeven onder lichte werkbelasting, maar een zware werkbelasting brengt het probleem snel naar het oppervlak.
Hoe kan dit worden voorkomen? Als threads naar verwachting worden geblokkeerd, declareert u aanroepen als asynchroon. Zodra de aanvraag de serverroutine binnenkomt, plaatst u deze in een groep werkthreads die gebruikmaken van de asynchrone mogelijkheden van het I/O-systeem en/of RPC. Als de server op zijn beurt RPC-aanroepen doet, worden deze asynchroon gemaakt en zorgt u ervoor dat de wachtrij niet te groot wordt. Als de serverroutine bestands-I/O uitvoert, gebruikt u asynchrone bestands-I/O om meerdere aanvragen naar het I/O-systeem in de wachtrij te plaatsen en slechts een paar threads in de wachtrij te plaatsen en de resultaten op te halen. Als de serverroutine netwerk-I/O uitvoert, gebruikt u opnieuw de asynchrone mogelijkheden van het systeem om de aanvragen uit te geven en de antwoorden asynchroon op te halen en zo weinig mogelijk threads te gebruiken. Wanneer de I/O is voltooid of de RPC-aanroep die de server heeft uitgevoerd, voltooit u de asynchrone RPC-aanroep die de aanvraag heeft bezorgd. Hierdoor kan de server met zo weinig mogelijk threads worden uitgevoerd, waardoor de prestaties en het aantal clients dat een server kan gebruiken, toeneemt.
Uitschalen
RPC kan worden geconfigureerd voor gebruik met Netwerktaakverdeling (NLB) als NLB zodanig is geconfigureerd dat alle aanvragen van een bepaald clientadres naar dezelfde server gaan. Omdat elke RPC-client een verbindingsgroep opent (zie RPC en het netwerk), is het essentieel dat alle verbindingen uit de groep van de opgegeven client op dezelfde servercomputer terechtkomen. Zolang aan deze voorwaarde wordt voldaan, kan een NLB-cluster worden geconfigureerd om te functioneren als één grote RPC-server met mogelijk uitstekende schaalbaarheid.