Redis
 sql >> Base de données >  >> NoSQL >> Redis

Lot de données définies du dictionnaire vers Redis

"juste" est un terme très relatif, et n'a pas vraiment de sens sans plus de contexte, en particulier :quelle est la taille de ces charges utiles ?

cependant, pour clarifier quelques points pour vous aider à enquêter :

  • il n'est pas nécessaire de verrouiller une IDatabase à moins que ce ne soit uniquement à vos propres fins ; SE.Redis gère la sécurité des threads en interne et est destiné à être utilisé par des threads concurrents
  • pour le moment, votre timing inclura tout le code de sérialisation (JsonConvert.SerializeObject ); cela s'additionnera, surtout si vos objets sont gros; pour obtenir une mesure décente, je vous suggère fortement de chronométrer les temps de sérialisation et de redis séparément
  • le batch.Execute() La méthode utilise une API de pipeline et n'attend pas les réponses entre les appels, donc :l'heure que vous voyez n'est pas l'effet cumulatif de la latence ; cela ne laisse que le processeur local (pour la sérialisation), la bande passante du réseau et le processeur du serveur ; les outils de la bibliothèque cliente n'ont aucun impact sur ces éléments
  • il existe un StringSet surcharge qui accepte un KeyValuePair<RedisKey, RedisValue>[]; tu pourrais choisir d'utiliser ceci au lieu d'un lot, mais la seule différence ici est qu'il s'agit du varadic MSET plutôt que plusieurs SET; dans tous les cas, vous bloquerez la connexion pour les autres appelants pendant la durée (puisque le but du lot est de rendre les commandes contiguës)
  • vous ne savez pas en fait besoin d'utiliser CreateBatch ici, surtout puisque vous verrouillez la base de données (mais je suggère toujours que vous n'avez pas besoin de le faire); le but de CreateBatch est de rendre une séquence de commandes séquentielle , mais je ne vois pas que vous en ayez besoin ici ; vous pouvez simplement utiliser _database.StringSetAsync pour chaque commande à son tour, ce qui serait aussi avoir l'avantage d'exécuter la sérialisation parallèlement à la commande précédente étant envoyée - cela vous permettrait de chevaucher la sérialisation (liée au processeur) et les opérations redis (liées à l'IO) sans aucun travail, sauf pour supprimer le CreateBatch appel; cela signifie également que vous ne monopolisez pas la connexion des autres appelants

Alors; le premier chose que je ferais serait de supprimer du code :

private static StackExchange.Redis.IDatabase _database;
static JsonSerializerSettings _redisJsonSettings = new JsonSerializerSettings {
    ContractResolver = new SerializeAllContractResolver(),
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore };

public void SetAll<T>(Dictionary<string, T> data, int cacheTime)
{
    TimeSpan expiration = new TimeSpan(0, cacheTime, 0);
    var list = new List<Task<bool>>();
    foreach (var item in data)
    {
        string serializedObject = JsonConvert.SerializeObject(
            item.Value, Formatting.Indented, _redisJsonSettings);

        list.Add(_database.StringSetAsync(item.Key, serializedObject, expiration));
    }
    Task.WhenAll(list.ToArray());
}

La deuxième chose que je ferais serait de chronométrer la sérialisation séparément du travail redis.

La troisième chose que je ferais serait de voir si je peux sérialiser en un MemoryStream à la place, idéalement un que je peux réutiliser - pour éviter la string alocation et encodage UTF-8 :

using(var ms = new MemoryStream())
{
    foreach (var item in data)
    {
        ms.Position = 0;
        ms.SetLength(0); // erase existing data
        JsonConvert.SerializeObject(ms,
            item.Value, Formatting.Indented, _redisJsonSettings);

        list.Add(_database.StringSetAsync(item.Key, ms.ToArray(), expiration));
    }
}