sql >> Databáze >  >> NoSQL >> Redis

Paralelní provádění s StackExchange.Redis?

V současné době váš kód používá synchronní API (StringSet ) a je načítáno 10 vlákny současně. Pro SE.Redis to nepředstavuje žádnou výraznou výzvu – zde to funguje dobře. Mám podezření že se skutečně jedná o časový limit, kdy serveru trvalo déle, než byste chtěli zpracovat některá data, s největší pravděpodobností také související s alokátorem serveru. Jednou z možností je tedy jednoduše trochu prodloužit časový limit . Ne moc... zkuste 5 sekund místo výchozí 1 sekundy. Většina operací pravděpodobně stejně funguje velmi rychle.

Pokud jde o urychlení:jednou z možností je nečekat - tj. uchovávat data z potrubí. Pokud jste spokojeni s tím, že nekontrolujete chybový stav každé jednotlivé zprávy, pak jednoduchým způsobem, jak to udělat, je přidat , flags: CommandFlags.FireAndForget na konec vaší StringSet volání. Při mém místním testování to urychlilo příklad 1M o 25 % (a mám podezření, že spoustu zbytku času ve skutečnosti stráví serializací řetězců).

Největší problém, který jsem měl s příkladem 10 milionů, byla prostě režie práce s příkladem 10 milionů - zvláště proto, že to zabírá obrovské množství paměti pro oba redis-server a aplikace, které (pro emulaci vašeho nastavení) jsou na stejném počítači. To vytváří konkurenční tlak na paměť s GC pauzami atd. ve spravovaném kódu. Ale možná ještě důležitější:začít cokoliv dělat trvá prostě věčnost . Následně jsem přefaktoroval kód tak, aby používal paralelní yield return generátory spíše než jeden seznam. Například:

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

s:

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

Zde je účel Batchify je zajistit, abychom serveru příliš nepomáhali tím, že bychom mezi jednotlivými operacemi zabírali značný čas – data jsou vynalezena v dávkách po 1000 a každá dávka je zpřístupněna velmi rychle.

Také jsem měl obavy o výkon JSON, tak jsem přešel na JIL:

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

a pak jsem jen pro zábavu přesunul práci JSON do dávkování (takže skutečné zpracování zacyklí:

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

Tím se časy o něco zkrátily, takže mohu načíst 10M za 3 minuty a 57 sekund, což je rychlost 42 194 rop. Většinu tohoto času je ve skutečnosti lokální zpracování uvnitř aplikace. Pokud to změním tak, aby se každé vlákno načítalo stejně položka ITEMS / THREADS krát, pak se to změní na 1 minutu 48 sekund – rychlost 92 592 rop.

Nejsem si jistý, jestli jsem na něco skutečně odpověděl, ale zkrácená verze by mohla být jednoduše „zkuste delší časový limit; zvažte použití funkce fire-and-forget).




  1. Jak efektivně provádět různé funkce s více klíči?

  2. Jak zobrazit pole dokumentu v mongo shell?

  3. Java Client pro připojení ElasticCache Redis Cache Node

  4. Jak aktualizovat hodnotu pole v Mongoose