sql >> Base de Datos >  >> NoSQL >> Redis

Lote de datos establecidos de Dictionary en Redis

"simplemente" es un término muy relativo y realmente no tiene sentido sin más contexto, en particular:¿qué tan grandes son estas cargas útiles?

sin embargo, para aclarar algunos puntos que lo ayudarán a investigar:

  • no hay necesidad de bloquear una IDatabase a menos que sea puramente para sus propios fines; SE.Redis se ocupa de la seguridad de subprocesos internamente y está diseñado para ser utilizado por subprocesos de la competencia
  • por el momento, su momento de esto incluirá todo el código de serialización (JsonConvert.SerializeObject ); esto se sumará, especialmente si tus objetos son grandes; para obtener una medida decente, le sugiero enfáticamente que cronometre la serialización y el tiempo de redis por separado
  • el batch.Execute() utiliza una API de canalización y no espera respuestas entre llamadas, por lo que:la hora que está viendo es no el efecto acumulativo de la latencia; eso deja solo la CPU local (para la serialización), el ancho de banda de la red y la CPU del servidor; las herramientas de la biblioteca del cliente no pueden afectar ninguna de esas cosas
  • hay un StringSet sobrecarga que acepta un KeyValuePair<RedisKey, RedisValue>[]; usted podría elija usar esto en lugar de un lote, pero la única diferencia aquí es que es el MSET varadic en lugar de múltiples SET; de cualquier manera, bloqueará la conexión para otras personas que llamen durante el tiempo (ya que el propósito del lote es hacer que los comandos sean contiguos)
  • usted no en realidad necesita usar CreateBatch aquí, especialmente ya que está bloqueando la base de datos (pero aún sugiero que no necesita hacer esto); el propósito de CreateBatch es hacer una secuencia de comandos secuencial , pero no veo que necesites esto aquí; simplemente podría usar _database.StringSetAsync para cada comando a su vez, que también tiene la ventaja de que estaría ejecutando la serialización en paralelo a el comando anterior que se envió:le permitiría superponer la serialización (vinculado a la CPU) y las operaciones de redis (vinculado a IO) sin ningún trabajo, excepto eliminar el CreateBatch llamar; esto también significará que no monopolizas la conexión de otras personas que llaman

Asi que; el primero lo que haría sería eliminar algún 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());
}

Lo segundo que haría sería cronometrar la serialización por separado del trabajo de redis.

Lo tercero que haría sería ver si puedo serializar a un MemoryStream en cambio, idealmente uno que pueda reutilizar, para evitar la string asignación y codificación 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));
    }
}