48 votes

AppFabric ne se remet pas bien d'un redémarrage.

Très bien, j'ai déployé AppFabric avec succès, et tout fonctionnait bien jusqu'à ce que nous commencions à avoir une exception intermittente sur le site web :

ErrorCode < ERRCA0017 >:SubStatus < ES0007 >:Il y a une défaillance temporaire. Veuillez réessayer plus tard. (La requête a échoué parce que le serveur est en état d'étranglement).

J'ai d'abord pensé que le serveur manquait de mémoire (état d'étranglement), mais j'ai finalement conclu que ce n'était pas le problème. Dans le journal des événements, j'ai constaté que DistributedCacheService.exe se plantait de temps en temps, et cela m'a conduit à une méthode simple pour reproduire l'erreur dans mon environnement de développement local :

  • Démarrez le site web, ajoutez quelques éléments dans le cache.
  • Redémarrez "AppFabric Caching Service".
  • ... et je commence à obtenir l'erreur.

Si je fais un Get-CacheClusterHealth AVANT de redémarrer le service, cela ressemble à quelque chose comme ceci :

NamedCache = MyCacheName
    Healthy              = 100,00
    UnderReconfiguration = 0,00
    NotPrimary           = 0,00
    NoWriteQuorum        = 0,00
    Throttled            = 0,00

Après le redémarrage :

Unallocated named cache fractions
---------------------------------

NamedCache = MyCacheName
    Unallocated fraction     = 100,00

Alors que j'obtiens ce résultat avec Get-CacheClusterHealth le site échoue. D'après ce que je peux dire, il se corrige de lui-même après un certain temps (10+ minutes).

Y a-t-il un moyen de remettre AppFabric sur pied plus rapidement ?

2voto

jaywayco Points 1506

En bref, la réponse est non.

Le temps de redémarrage d'un cluster augmente avec l'ajout de nœuds supplémentaires, ce qui me laisse penser que c'est un processus de synchronisation des nœuds qui prend du temps.

L'exception que vous voyez est en effet le nœud appfabric qui entre dans un état d'étranglement. Il entrera dans l'état d'étranglement en fonction de la façon dont vous avez défini les filigranes haut/bas sur le nœud. Je pense que par défaut, la marque d'eau haute est de 90%, après quoi il commencera à expulser des éléments en fonction de la politique d'expulsion définie sur le cache. Vous devriez généralement utiliser LRU (Least recently used) mais si le cache ne peut toujours pas fonctionner dans les limites fixées, il s'étranglera lui-même pour ne pas faire tomber votre serveur.

Votre application gagnerait à pouvoir gérer ces événements avec élégance. Si tous les nœuds sont répertoriés dans la configuration du cluster de votre application, celle-ci devrait passer au nœud suivant lors de la prochaine tentative d'obtention de données. Nous utilisons une boucle de réessai pour rechercher l'échec temporaire et réessayer 3 fois. Si après 3 tentatives, l'erreur persiste, nous enregistrons et retournons null, sans exception. Cela permet à l'application de tenter d'accéder à un autre nœud ou de laisser au nœud problématique le temps de se rétablir :

 private object WithRetry(Func<object> method)
    {
        int tryCount = 0;
        bool done = false;
        object result = null;
        do
        {
            try
            {
                result = method();
                done = true;
            }
            catch (DataCacheException ex)
            {
                if (ex.ErrorCode == DataCacheErrorCode.KeyDoesNotExist)
                {
                    done = true;
                }
                else if ((ex.ErrorCode == DataCacheErrorCode.Timeout ||
                ex.ErrorCode == DataCacheErrorCode.RetryLater ||
                ex.ErrorCode == DataCacheErrorCode.ConnectionTerminated)
                && tryCount < MaxTryCount)
                {                        
                    tryCount++;
                    LogRetryException(ex, tryCount);
                }
                else
                {
                    LogException(ex);
                    done = true;
                }
            }
        }
        while (!done);

 return result;
}

Et cela nous permet de faire ce qui suit :

private void AF_Put(string key, object value)
{
    WithRetry(() => defaultCache.Put(key, value));
}

ou :

private object AF_Get(string key)
{
    return WithRetry(() => defaultCache.Get(key));            
}

-4voto

bleepzter Points 2684

Ce même problème s'était produit dans le cadre d'un des projets sur lesquels je travaillais. Après deux semaines à nous gratter la tête et à tout essayer sans succès pour faire fonctionner nos services WCF (sur Azure), nous avons fini par appeler Microsoft.

Les techniciens de Microsoft nous ont fourni un (Power)Shell script qui est exécuté à partir du runtime du site et qui fait la maintenance de l'AppFabric... Le script avait des trucs que je n'avais pas du tout vus dans les livres Azure, mais il a fait le travail correctement !

Merci

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X