Redis
 sql >> Datenbank >  >> NoSQL >> Redis

Stapeln Sie Daten aus dem Wörterbuch in Redis

"Nur" ist ein sehr relativer Begriff und macht ohne mehr Kontext keinen Sinn, insbesondere:Wie groß sind diese Nutzlasten?

Um jedoch einige Punkte zu klären, die Ihnen bei der Untersuchung helfen:

  • Es besteht keine Notwendigkeit, eine IDatabase zu sperren es sei denn, dies dient ausschließlich Ihren eigenen Zwecken; SE.Redis befasst sich intern mit der Thread-Sicherheit und soll von konkurrierenden Threads verwendet werden
  • Im Moment umfasst Ihr Timing dafür den gesamten Serialisierungscode (JsonConvert.SerializeObject ); das wird sich summieren, besonders wenn Ihre Objekte groß sind; Um ein anständiges Maß zu erhalten, empfehle ich Ihnen dringend, die Zeit der Serialisierung und die Redis-Zeit separat festzulegen
  • der batch.Execute() -Methode verwendet eine Pipeline-API und wartet nicht auf Antworten zwischen Aufrufen, also:Die Zeit, die Sie sehen, ist nicht der kumulative Effekt der Latenz; das lässt nur die lokale CPU (für die Serialisierung), die Netzwerkbandbreite und die Server-CPU übrig; die Tools der Client-Bibliothek können diese Dinge nicht beeinflussen
  • es gibt ein StringSet -Überladung, die ein KeyValuePair<RedisKey, RedisValue>[] akzeptiert; Sie könnten entscheiden Sie sich dafür, dies anstelle eines Stapels zu verwenden, aber der einzige Unterschied besteht darin, dass es sich um das varadische MSET handelt anstatt mehrere SET; In jedem Fall blockieren Sie die Verbindung für andere Anrufer für die Dauer (da der Zweck von Batches darin besteht, die Befehle zusammenhängend zu machen)
  • Sie eigentlich nicht müssen CreateBatch verwenden hier besonders da Sie die Datenbank sperren (aber ich schlage immer noch vor, dass Sie dies nicht tun müssen); der Zweck von CreateBatch besteht darin, eine Folge von Befehlen sequenziell zu machen , aber ich sehe nicht, dass Sie das hier brauchen; Sie könnten einfach _database.StringSetAsync verwenden für jeden Befehl der Reihe nach, was auch würde haben den Vorteil, dass Sie die Serialisierung parallel zu ausführen würden der vorherige Befehl gesendet wird - es würde Ihnen erlauben, die Serialisierung (CPU-gebunden) und Redis-Operationen (IO-gebunden) ohne Arbeit zu überlappen, außer den CreateBatch zu löschen Forderung; dies bedeutet auch, dass Sie die Verbindung anderer Anrufer nicht monopolisieren

So; die erste Was ich tun würde, wäre entfernen etwas 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());
}

Das zweite, was ich tun würde, wäre, die Serialisierung getrennt von der Redis-Arbeit zu timen.

Das dritte, was ich tun würde, wäre zu sehen, ob ich zu einem MemoryStream serialisieren kann stattdessen idealerweise eine, die ich wiederverwenden kann - um den string zu vermeiden Zuordnung und UTF-8-Kodierung:

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));
    }
}