sql >> Database >  >> NoSQL >> Redis

Parallelle uitvoering met StackExchange.Redis?

Momenteel gebruikt uw code de synchrone API (StringSet ), en wordt gelijktijdig door 10 threads geladen. Dit vormt geen noemenswaardige uitdaging voor SE.Redis - het werkt hier prima. Ik vermoed dat het echt een time-out is waarbij de server er langer over heeft gedaan dan je zou willen om sommige gegevens te verwerken, hoogstwaarschijnlijk ook gerelateerd aan de allocator van de server. Een optie is dan om gewoon de time-out een beetje te verhogen . Niet veel... probeer 5 seconden in plaats van de standaard 1 seconde. Waarschijnlijk werken de meeste bewerkingen sowieso erg snel.

Met betrekking tot het versnellen:een optie hier is om niet te wachten - d.w.z. gegevens blijven pipelinen. Als u tevreden bent om niet elk afzonderlijk bericht te controleren op een foutstatus, dan is een eenvoudige manier om dit te doen het toevoegen van , flags: CommandFlags.FireAndForget aan het einde van uw StringSet telefoongesprek. In mijn lokale testen versnelde dit het 1M-voorbeeld met 25% (en ik vermoed dat veel van de rest van de tijd daadwerkelijk wordt besteed aan string-serialisatie).

Het grootste probleem dat ik had met het 10M-voorbeeld was gewoon de overhead van het werken met het 10M-voorbeeld - vooral omdat dit enorme hoeveelheden geheugen in beslag neemt voor zowel de redis-server en de applicatie, die (om uw setup te emuleren) zich op dezelfde machine bevinden. Dit zorgt voor concurrerende geheugendruk, met GC-pauzes enz. in de beheerde code. Maar misschien nog belangrijker:het duurt gewoon een eeuwigheid om iets te beginnen . Daarom heb ik de code aangepast om parallel yield return te gebruiken generatoren in plaats van een enkele lijst. Bijvoorbeeld:

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

met:

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

Hier, het doel van Batchify is om ervoor te zorgen dat we de server niet te veel helpen door aanzienlijke tijd tussen elke bewerking te nemen - de gegevens worden uitgevonden in batches van 1000 en elke batch is zeer snel beschikbaar.

Ik maakte me ook zorgen over de JSON-prestaties, dus schakelde ik over naar JIL:

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

en toen, gewoon voor de lol, heb ik het JSON-werk naar de batchverwerking verplaatst (zodat de eigenlijke verwerkingslussen:

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

Dit zorgde voor een wat kortere tijd, dus ik kan 10M laden in 3 minuten en 57 seconden, een snelheid van 42.194 rops. Het grootste deel van deze tijd is eigenlijk lokale verwerking binnen de applicatie. Als ik het zo verander dat elke thread dezelfde laadt item ITEMS / THREADS keer, dan verandert dit in 1 minuut en 48 seconden - een snelheid van 92.592 rops.

Ik weet niet zeker of ik echt iets heb geantwoord, maar de korte versie zou kunnen zijn:"probeer een langere time-out; overweeg om fire-and-forget te gebruiken).




  1. Redis probeert verbinding te maken met localhost op Heroku in plaats van REDIS_URL

  2. Over MongoDB, waarom gebruiken we het? MongoDB's terminologie en implementatie

  3. Spring RedisConnectionFactory met transactie die de verbinding met Pool niet teruggeeft en vervolgens blokkeert wanneer deze uitgeput is

  4. MongoDB 4.2 Beheer &Monitoring Zonder Vendor Lockin