Redis
 sql >> Database >  >> NoSQL >> Redis

Batch set di dati dal dizionario in Redis

"semplicemente" è un termine molto relativo e non ha davvero senso senza più contesto, in particolare:quanto sono grandi questi carichi utili?

tuttavia, per chiarire alcuni punti per aiutarti a indagare:

  • non è necessario bloccare un IDatabase a meno che non sia puramente per i tuoi scopi; SE.Redis si occupa internamente di thread safety ed è concepito per essere utilizzato da thread concorrenti
  • al momento, la tempistica di questo includerà tutto il codice di serializzazione (JsonConvert.SerializeObject ); questo si sommerà, soprattutto se i tuoi oggetti sono grandi; per ottenere una misura decente, ti consiglio vivamente di cronometrare la serializzazione e i tempi di redis separatamente
  • il batch.Execute() utilizza un'API della pipeline e non attende le risposte tra le chiamate, quindi:il tempo che vedi non l'effetto cumulativo della latenza; ciò lascia solo la CPU locale (per la serializzazione), la larghezza di banda della rete e la CPU del server; gli strumenti della libreria client non possono influire su nessuna di queste cose
  • c'è un StringSet sovraccarico che accetta una KeyValuePair<RedisKey, RedisValue>[]; tu potresti scegli di usarlo invece di un batch, ma l'unica differenza qui è che è il varadic MSET anziché più SET; in ogni caso, bloccherai la connessione per altri chiamanti per la durata (poiché lo scopo del batch è rendere i comandi contigui)
  • non in realtà è necessario utilizzare CreateBatch qui, soprattutto dal momento che stai bloccando il database (ma suggerisco comunque che non sia necessario farlo); lo scopo di CreateBatch consiste nel creare una sequenza di comandi sequenziali , ma non vedo che tu abbia bisogno di questo qui; potresti semplicemente usare _database.StringSetAsync per ogni comando a sua volta, che sarebbe anche avere il vantaggio di eseguire la serializzazione parallelamente a il comando precedente inviato - ti consentirebbe di sovrapporre la serializzazione (rilegato alla CPU) e redis ops (rilegato all'IO) senza alcun lavoro tranne che per eliminare il CreateBatch chiamata; questo significherà anche che non monopolizzi la connessione di altri chiamanti

Così; il primo la cosa che farei sarebbe rimuovere un po' di codice:

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 seconda cosa che farei sarebbe programmare la serializzazione separatamente per il lavoro di redis.

La terza cosa che farei sarebbe vedere se riesco a serializzare su un MemoryStream invece, idealmente uno che posso riutilizzare - per evitare la string assegnazione e codifica 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));
    }
}