web-dev-qa-db-fra.com

Délai d'attente StackExchange.Redis et «Aucune connexion n'est disponible pour entretenir cette opération»

J'ai les problèmes suivants dans notre environnement de production (Web-Farm - 4 nœuds, en plus d'équilibreur de charge):

1) Timeout performing HGET key, inst: 3, queue: 29, qu=0, qs=29, qc=0, wr=0/0 at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor``1 processor, ServerEndPoint server) in ConnectionMultiplexer.cs:line 1699 Cela se produit 3 à 10 fois en une minute

2) No connection is available to service this operation: HGET key at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor``1 processor, ServerEndPoint server) in ConnectionMultiplexer.cs:line 1666

J'ai essayé de l'implémenter comme Marc l'a suggéré (peut-être que je l'ai mal interprété) - mieux vaut avoir moins de connexions à Redis que plusieurs. J'ai fait l'implémentation suivante:

public class SeRedisConnection
{
    private static ConnectionMultiplexer _redis;

    private static readonly object SyncLock = new object();

    public static IDatabase GetDatabase()
    {
        if (_redis == null || !_redis.IsConnected || !_redis.GetDatabase().IsConnected(default(RedisKey)))
        {
            lock (SyncLock)
            {
                try
                {
                    var configurationOptions = new ConfigurationOptions
                    {
                        AbortOnConnectFail = false
                    };
                    configurationOptions.EndPoints.Add(new DnsEndPoint(ConfigurationHelper.CacheServerHost,
                        ConfigurationHelper.CacheServerHostPort));

                    _redis = ConnectionMultiplexer.Connect(configurationOptions);
                }
                catch (Exception ex)
                {
                   IoC.Container.Resolve<IErrorLog>().Error(ex);
                    return null;
                }
            }
        }
        return _redis.GetDatabase();
    }

    public static void Dispose()
    {
        _redis.Dispose();
    }
}

En fait, disposer n'est pas utilisé actuellement. J'ai également quelques détails de l'implémentation qui pourraient provoquer un tel comportement (j'utilise uniquement des hachages): 1. Ajouter, supprimer des hachages - async 2. Obtenir -sync

Quelqu'un pourrait-il m'aider à éviter ce comportement?

Merci beaucoup d'avance!

RÉSOLU - Augmentation du délai d'expiration de la connexion client après évaluation des capacités du réseau.

MISE À JOUR 2 : En fait, cela n'a pas résolu le problème. Lorsque le volume du cache commence à augmenter, par exemple à partir de 2 Go. Ensuite, j'ai vu le même schéma en fait, ces délais d'attente se produisaient toutes les 5 minutes environ. Et nos sites ont été gelés pendant un certain temps toutes les 5 minutes jusqu'à la fin de l'opération de fourche. Ensuite, j'ai découvert qu'il y avait une option pour faire un fork (enregistrer sur le disque) toutes les x secondes:

save 900 1
save 300 10
save 60 10000

Dans mon cas, c'était "enregistrer 300 10" - enregistrer toutes les 5 minutes si au moins 10 mises à jour se produisaient. J'ai aussi découvert que la "fourchette" pouvait être très chère. La section "enregistrer" commentée a résolu le problème. Nous pouvons commenter la section "enregistrer" car nous n'utilisons que Redis comme "cache en mémoire" - nous n'avons pas besoin de persistance. Voici la configuration du port Windows de nos serveurs de cache "Redis 2.4.6": https://github.com/rgl/redis/downloads

Peut-être que cela a été résolu dans les versions récentes du port Windows de Redis dans MSOpentech: http://msopentech.com/blog/2013/04/22/redis-on-windows-stable-and-reliable/ mais je n'ai pas encore testé.

Quoi qu'il en soit, StackExchange.Redis n'a rien à voir avec ce problème et il fonctionne assez stable dans notre environnement de production, grâce à Marc Gravell.

MISE À JOUR FINALE: Redis est une solution à un seul thread - elle est finalement rapide mais quand il s'agit de libérer de la mémoire (Supprimer les éléments périmés ou expiré), les problèmes sont apparus car un thread devrait récupérer la mémoire (ce qui n'est pas une opération rapide - quel que soit l'algorithme utilisé) et le même thread devrait gérer les opérations GET, SET. Bien sûr, cela se produit lorsque nous parlons d'un environnement de production moyennement chargé. Même si vous utilisez un cluster avec des esclaves lorsque la barrière de mémoire est atteinte, il aura le même comportement.

41
George Anisimov

Il semble que dans la plupart des cas, cette exception est un problème client. Les versions précédentes de StackExchange.Redis utilisaient directement le socket Win32, ce qui a parfois un impact négatif. Le routage interne Asp.net est probablement lié à celui-ci.
La bonne nouvelle est que le réseau infra de StackExchange.Redis a été complètement réécrit récemment. La dernière version est 2.0.513. Essayez-le et il y a de fortes chances que votre problème disparaisse.

1
Bennie Zhitomirsky