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

Parallele Ausführung mit StackExchange.Redis?

Derzeit verwendet Ihr Code die synchrone API (StringSet ) und wird von 10 Threads gleichzeitig geladen. Dies stellt keine nennenswerte Herausforderung für SE.Redis dar – hier funktioniert es einwandfrei. Ich vermute dass es sich wirklich um eine Zeitüberschreitung handelt, bei der der Server länger gebraucht hat, als Sie möchten, um einige der Daten zu verarbeiten, höchstwahrscheinlich auch im Zusammenhang mit der Zuweisung des Servers. Eine Möglichkeit besteht also darin, einfach das Timeout etwas zu erhöhen . Nicht viel ... versuchen Sie es mit 5 Sekunden anstelle der standardmäßigen 1 Sekunde. Wahrscheinlich arbeiten die meisten Operationen ohnehin sehr schnell.

In Bezug auf die Beschleunigung:Eine Option hier ist, nicht zu warten - d. h. Daten weiterleiten. Wenn Sie damit zufrieden sind, nicht jede einzelne Nachricht auf einen Fehlerstatus zu überprüfen, können Sie dies ganz einfach tun, indem Sie , flags: CommandFlags.FireAndForget bis zum Ende Ihres StringSet Forderung. In meinen lokalen Tests hat dies das 1M-Beispiel um 25 % beschleunigt (und ich vermute, dass ein Großteil der restlichen Zeit tatsächlich für die Zeichenfolgenserialisierung aufgewendet wird).

Das größte Problem, das ich mit dem 10-M-Beispiel hatte, war einfach der Aufwand für die Arbeit mit dem 10-M-Beispiel - zumal dies sehr viel Speicher für den redis-server benötigt und die Anwendung, die sich (um Ihr Setup zu emulieren) auf demselben Computer befinden. Dies erzeugt konkurrierenden Speicherdruck mit GC-Pausen usw. im verwalteten Code. Aber vielleicht noch wichtiger:Es dauert einfach ewig, etwas zu tun . Folglich habe ich den Code so umgestaltet, dass er parallel yield return verwendet Generatoren statt einer einzelnen Liste. Zum Beispiel:

    static IEnumerable<Person> InventPeople(int seed, int count)
    {
        for(int i = 0; i < count; i++)
        {
            int f = 1 + seed + i;
            var item = new Person
            {
                Id = f,
                Name = Path.GetRandomFileName().Replace(".", "").Substring(0, appRandom.Value.Next(3, 6)) + " " + Path.GetRandomFileName().Replace(".", "").Substring(0, new Random(Guid.NewGuid().GetHashCode()).Next(3, 6)),
                Age = f % 90,
                Friends = ParallelEnumerable.Range(0, 100).Select(n => appRandom.Value.Next(1, f)).ToArray()
            };
            yield return item;
        }
    }

    static IEnumerable<T> Batchify<T>(this IEnumerable<T> source, int count)
    {
        var list = new List<T>(count);
        foreach(var item in source)
        {
            list.Add(item);
            if(list.Count == count)
            {
                foreach (var x in list) yield return x;
                list.Clear();
            }
        }
        foreach (var item in list) yield return item;
    }

mit:

foreach (var element in InventPeople(PER_THREAD * counter1, PER_THREAD).Batchify(1000))

Hier der Zweck von Batchify soll sicherstellen, dass wir dem Server nicht zu sehr helfen, indem wir zwischen den einzelnen Vorgängen viel Zeit in Anspruch nehmen - die Daten werden in Stapeln von 1000 erstellt und jeder Stapel wird sehr schnell verfügbar gemacht.

Ich war auch besorgt über die Leistung von JSON, also wechselte ich zu JIL:

    public static string ToJSON<T>(this T obj)
    {
        return Jil.JSON.Serialize<T>(obj);
    }

und dann habe ich nur zum Spaß die JSON-Arbeit in die Stapelverarbeitung verschoben (so dass die eigentliche Verarbeitung Schleifen :

 foreach (var element in InventPeople(PER_THREAD * counter1, PER_THREAD)
     .Select(x => new { x.Id, Json = x.ToJSON() }).Batchify(1000))

Dies hat die Zeiten etwas weiter verkürzt, sodass ich 10 MB in 3 Minuten und 57 Sekunden laden kann, was einer Rate von 42.194 Rops entspricht. Die meiste Zeit wird tatsächlich lokal in der Anwendung verarbeitet. Wenn ich es so ändere, dass jeder Thread dasselbe lädt Artikel ITEMS / THREADS Mal, dann ändert sich dies zu 1 Minute 48 Sekunden - eine Rate von 92.592 Rops.

Ich bin mir nicht sicher, ob ich wirklich etwas geantwortet habe, aber die Kurzversion könnte einfach lauten:"Versuchen Sie es mit einem längeren Timeout; erwägen Sie die Verwendung von Fire-and-Forget).