Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

Conjunto de dados em lote do Dicionário para o Redis


"apenas" é um termo muito relativo e não faz sentido sem mais contexto, em particular:quão grandes são essas cargas?

no entanto, para esclarecer alguns pontos para ajudá-lo a investigar:
  • não há necessidade de bloquear um IDatabase a menos que seja puramente para seus próprios propósitos; O SE.Redis lida com a segurança de threads internamente e deve ser usado por threads concorrentes
  • no momento, seu tempo para isso incluirá todo o código de serialização (JsonConvert.SerializeObject ); isso aumentará, especialmente se seus objetos são grandes; para obter uma medida decente, sugiro fortemente que você cronometre os tempos de serialização e redis separadamente
  • o batch.Execute() O método usa uma API de pipeline e não espera respostas entre as chamadas, então:o horário que você está vendo é não o efeito cumulativo da latência; que deixa apenas CPU local (para serialização), largura de banda de rede e CPU do servidor; as ferramentas da biblioteca cliente não podem afetar nada disso
  • há um StringSet sobrecarga que aceita um KeyValuePair<RedisKey, RedisValue>[]; você poderia opte por usar isso em vez de um lote, mas a única diferença aqui é que é o MSET varadic em vez de múltiplos SET; de qualquer forma, você estará bloqueando a conexão para outros chamadores durante a duração (já que o objetivo do lote é tornar os comandos contíguos)
  • você não na verdade precisa usar CreateBatch aqui, especialmente já que você está bloqueando o banco de dados (mas ainda sugiro que você não precise fazer isso); o objetivo de CreateBatch é fazer uma sequência de comandos sequencial , mas não vejo que você precise disso aqui; você pode simplesmente usar _database.StringSetAsync para cada comando, o que também tem a vantagem de estar executando a serialização em paralelo com o comando anterior sendo enviado - ele permitiria sobrepor a serialização (limite da CPU) e operações de redis (vinculado ao IO) sem nenhum trabalho, exceto para excluir o CreateBatch ligar; isso também significa que você não monopoliza a conexão de outros chamadores

Então; o primeiro coisa que eu faria seria remover algum código:
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());
}

A segunda coisa que eu faria seria cronometrar a serialização separadamente para o trabalho redis.

A terceira coisa que eu faria seria ver se consigo serializar para um MemoryStream em vez disso, de preferência um que eu possa reutilizar - para evitar a string alocação e codificação 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));
    }
}