Recyclage d’AppDomain

On parle souvent de recyclage de processus IIS mais ASP.NET permet aussi de recycler un Application Domain ou AppDomain. Pour ceux qui découvrent cette notion, on peut définir un AppDomain comme un processus .NET hébergé dans un processus Windows classique (dans le cas d'IIS/ASP.NET: W3WP.EXE). Un pool d'applications IIS peut ainsi héberger, dans un même espace mémoire, plusieurs application .NET, chaque application tournant dans son propre AppDomain. Ceci permet notamment à deux applications .NET hébergées dans un même worker process IIS (W3WP) de communiquer plus rapidement sans avoir besoin d'utiliser une communication inter processus complexe (RPCs, canaux nommés…etc).

WinDbg et l'extention SoS permet de visualiser les AppDomains chargés dans un processus à l'aide de la commande !DumpDomain. Dans l'exemple ci-dessous, on peut ainsi identifier que le global.asax est chargé dans l'AppDomain2 :

!DumpDomain

--------------------------------------System Domain: 6d9ae1f8LowFrequencyHeap: 6d9ae21cHighFrequencyHeap: 6d9ae268StubHeap: 6d9ae2b4Stage: OPENName: None--------------------------------------Shared Domain: 6d9adb48LowFrequencyHeap: 6d9adb6cHighFrequencyHeap: 6d9adbb8StubHeap: 6d9adc04Stage: OPENName: NoneAssembly: 015e6640[…]Assembly: 015e6020--------------------------------------Domain 1: 001107f0LowFrequencyHeap: 00110814HighFrequencyHeap: 00110860StubHeap: 001108acStage: OPENSecurityDescriptor: 015b9920Name: DefaultDomainAssembly: 001b2fa0[D:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]ClassLoader: 001b3010SecurityDescriptor: 001f0dc0Module Name[…]--------------------------------------Domain 2: 015f99f0LowFrequencyHeap: 015f9a14HighFrequencyHeap: 015f9a60StubHeap: 015f9aacStage: OPENSecurityDescriptor: 015b9558Name: /LM/W3SVC/5/ROOT-1-129055248675466786Assembly: 001b2fa0[D:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll]ClassLoader: 001b3010SecurityDescriptor: 015ea7f8Module Name60c11000 D:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll007f2358 D:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sortkey.nlp007f2010 D:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\sorttbls.nlpAssembly: 015e5f40 [D:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\6d9924ec\86afc5bf\App_global.asax.siihhkue.dll]ClassLoader: 015e5fb0SecurityDescriptor: 015eb078Module Name00ab55c0 D:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\6d9924ec\86afc5bf\App_global.asax.siihhkue.dll

Cette fonctionnalité existait déjà dans les versions précédentes d'IIS mais, une nouveauté d'IIS7 est de permettre le recyclage d'un AppDomain à la demande. Vous trouvez ci-dessous un script d'exemple vous permettant d'énumérer et de décharger un AppDomain à la demande via la méthode WMI AppDomain.Unload :

UnloadAppDomainSample.vbs

'Author: Julien Clauzel'Description: Sample script to unload appdomains on IIS7'Input: '    If no parameters are provided list appdomain and prompt for recycling'    If a parameter is provided it is assumed to be an appdomain name to be recycled. For example MyAppDomain'Output: set %errorlevel% variable to :'    0 if successful, '    -1 if appdomain passed as a parameter is not found'    -2 if some required IIS components are not found or failed to initialize'    value of the errorOption ExplicitDim oService, Input, oAppDom, AppDom, oArgs, bAppDomainFoundSub Cleanup    Set oService = Nothing    Set oAppDom = Nothing    Set oArg = NothingEnd SubSub UnloadAppDomain (AppDomain)    AppDomain.Unload    If Err.Number <> 0 Then        WScript.Echo " =>ERROR while unloading:" & Err.Number & " " & Err.Description        Cleanup        WScript.Quit Err.Number    Else        WScript.Echo " =>Unloaded"        If oArgs.Count = 1 Then bAppDomainFound = True    End IfEnd SubbAppDomainFound = FalseInput = ""On Error Resume nextSet oService = GetObject("winmgmts:root\WebAdministration")Set oArgs = WScript.Arguments ' Get the AppDomainsSet oAppDom = oService.InstancesOf("AppDomain")If Err.Number <> 0 Then    WScript.Echo "Error: some IIS compontents are not found or failed to initialize, exiting."WScript.Quit -2End IfFor Each AppDom In oAppDom If Err.Number = 0 Then    If oArgs.Count = 1 Then        If AppDom.SiteName = oArgs(0) Then            UnloadAppDomain (AppDom)        End If    Else         WScript.Echo " AppDomain => " & AppDom.SiteName & " PID:" & AppDom.ProcessId        WScript.Echo " Unload AppDomain (Y/N)?"        Input = WScript.StdIn.ReadLine         If Input ="Y" then            UnloadAppDomain (AppDom)         Else            WScript.Echo " =>Skipped."            WScript.Echo ""         End If    End IfEnd IfNext

If oArgs.Count = 1 and Not bAppDomainFound Then        WScript.Echo "Error AppDomain:" & oArgs(0) & " not found"        Cleanup        WScript.Quit -1    End IfCleanupWScript.Echo "Exiting"WScript.Quit 0

Exemple d'utilisation :

UnloadAppDomain.vbs

AppDomain => JulianGroove PID:9596Unload AppDomain (Y/N)?Y=>UnloadedAppDomain => WebNot PID:6188Unload AppDomain (Y/N)?N=>Skipped.Exiting

Le script permet aussi de décharger un AppDomain en passant simplement son nom en argument :

UnloadAppDomain.vbs WebNotification

=>UnloadedExiting

Quelques remarques :

  • Quand le script termine avec succès la variable %errorlevel% est positionné à 0
  • Si le nom de l'AppDomain passé en paramètre ne peut être trouvé, la valeur retournée est : -1
  • Si un des composants nécessaire au script n'est pas trouvé, la valeur retournée est : -2
  • Si une erreur est rencontrée, %errorlevel% est positionné à la valeur de l'erreur

On peut se demander quand un processus ou un AppDomain doit être recyclé et quels sont les impacts du recyclage.

Le recyclage d'un processus IIS est conditionné par le paramétrage effectué dans le gestionnaire IIS :

  • Le système ou l'administrateur a défini une politique de recyclage (par défaut toutes les 1740 minutes à compter du démarrage du processus)

  • Un recyclage manuel a été demandé soit :
    • Via le gestionnaire IIS
    • En ligne de commande (voir notre blog sur le sujet) :
      • appcmd list wp
        • Cette commande donne la liste des pools d'application chargé en mémoire
      • appcmd recycle apppool DefaultAppPool
        • Recycle le DefaultAppPool

Quand un processus est recyclé, l'ancien processus s'arrête et un nouveau processus prend la relève pour continuer à traiter les requêtes des utilisateurs. Dans ce cas, les caches ASP.NET sont entièrement réinitialisés et les sessions des utilisateurs sont perdues si elles n'ont pas été externalisées.

Un AppDomain peut quant à lui être re-démarrer pour différentes raisons (liste non exhaustive) :

Lors de l'arrêt et du redémarrage d'un AppDomain, les caches ASP.NET sont également purgés, les sessions utilisateurs sont perdues (sauf si elles ont été persistés à l'extérieur du processus). Les modules sont déchargés. Cependant, vous pouvez trouver encore une « trace » de leur présence passée à l'aide de la commande « lm » en vous attachant au processus à l'aide de WinDbg.

Par exemple :    

Lm

Unloaded modules:

70370000 7037a000 App_global.asax.1entu8ls.dll

Au niveau de l'utilisation mémoire, l'arrêt d'un AppDomain aura un impact plus limité qu'un recyclage complet du processus W3WP. Vous devriez cependant constater un gain significatif au niveau de la heap managée (vous pouvez éventuellement utiliser la commande !dumpheap -stat et examiner les objets de type « Free » pour mesurer ce gain).

En synthèse le recyclage d'un processus W3WP permet de « redémarrer » complètement un processus au niveau mémoire alors que le recyclage d'un AppDomain quant à lui peu en garder des traces. Ce qui est toutefois important à souligner est que les recyclages d'AppDomain peuvent être réalisés de manière automatique ou préventive par le système ou l'administrateur. Pour identifier si des recyclages d'AppDomain interviennent dans votre environnement, utilisez le compteur de performance ASP.NET v2.0.5727\Application Restarts. Pour identifier si des recyclages de processus surviennent activer la variable LogEventOnRecycle à 255 (reportez vous à cet article pour de plus amples informations).

Votre application peut être amenée à recycler à n'importe quel moment, que ce soit en heure creuse ou en pic de charge. Par conséquent, lors de votre phase de design et dans vos tests de charge, prenez en compte cet élément important et réalisez des recyclages d'AppDomain et/ou des processus W3WP. Nous recommandons généralement que toutes les applications soient conçues afin de pouvoir continuer à fournir le même service aux utilisateurs alors que ces actions sont en cours de réalisation. Vous pouvez vous aider du script ci-dessus ainsi que de APPCMD pour générer ces recyclages.

Julien Clauzel