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

proč je to tak pomalé se 100 000 záznamy při použití pipeline v redis?

Před napsáním takového benchmarku (a zejména benchmarku pomocí JVM) musíte zvážit několik bodů:

  • na většině (fyzických) strojů je Redis schopen zpracovat více než 100K ops/s při použití pipeliningu. Váš benchmark se zabývá pouze 100 000 položkami, takže netrvá dostatečně dlouho, aby přinesl smysluplné výsledky. Navíc není čas na to, aby se spustily následné fáze JIT.

  • absolutní čas není příliš relevantní metrika. Lepší a stabilnější metrikou by bylo zobrazení propustnosti (tj. počtu operací za sekundu) při ponechání srovnávacího testu spuštěného po dobu alespoň 10 sekund.

  • vaše vnitřní smyčka generuje spoustu odpadků. Pokud plánujete srovnávat Jedis+Redis, musíte udržet režii svého vlastního programu na nízké úrovni.

  • protože jste vše definovali do hlavní funkce, vaše smyčka nebude kompilována JIT (v závislosti na JVM, které používáte). Mohou být pouze volání vnitřní metody. Pokud chcete, aby byl JIT efektivní, nezapomeňte svůj kód zapouzdřit do metod, které může JIT zkompilovat.

  • volitelně můžete chtít přidat zahřívací fázi před provedením skutečného měření, abyste se vyhnuli účtování režijních nákladů na spouštění prvních iterací s prostým interpretem a nákladů na samotný JIT.

Nyní, pokud jde o potrubí Redis, váš kanál je příliš dlouhý. 100 000 příkazů v potrubí znamená, že Jedis musí vytvořit 6 MB vyrovnávací paměti, než něco odešle do Redis. Znamená to, že vyrovnávací paměti soketů (na straně klienta a možná i na straně serveru) budou nasycené a že se Redis bude muset vypořádat také s komunikačními vyrovnávací paměti o velikosti 6 MB.

Kromě toho je váš benchmark stále synchronní (používání potrubí ho magicky nedělá asynchronní). Jinými slovy, Jedis nezačne číst odpovědi, dokud nebude poslední dotaz vašeho kanálu odeslán do Redis. Když je potrubí příliš dlouhé, má potenciál věci zablokovat.

Zvažte omezení velikosti potrubí na 100–1000 operací. Samozřejmě to bude generovat více zpátečních cest, ale tlak na komunikační zásobník se sníží na přijatelnou úroveň. Zvažte například následující program:

import redis.clients.jedis.*;
import java.util.*;

public class TestPipeline {

    /**
     * @param args
     */

    int i = 0; 
    Map<String, String> map = new HashMap<String, String>();
    ShardedJedis jedis;  

    // Number of iterations
    // Use 1000 to test with the pipeline, 100 otherwise
    static final int N = 1000;

    public TestPipeline() {
      JedisShardInfo si = new JedisShardInfo("127.0.0.1", 6379);
      List<JedisShardInfo> list = new ArrayList<JedisShardInfo>();
      list.add(si);
      jedis = new ShardedJedis(list);
    } 

    public void push( int n ) {
     ShardedJedisPipeline pipeline = jedis.pipelined();
     for ( int k = 0; k < n; k++) {
      map.put("id", "" + i);
      map.put("name", "lyj" + i);
      pipeline.hmset("m" + i, map);
      ++i;
     }
     pipeline.sync(); 
    }

    public void push2( int n ) {
     for ( int k = 0; k < n; k++) {
      map.put("id", "" + i);
      map.put("name", "lyj" + i);
      jedis.hmset("m" + i, map);
      ++i;
     }
    }

    public static void main(String[] args) {
      TestPipeline obj = new TestPipeline();
      long startTime = System.currentTimeMillis();
      for ( int j=0; j<N; j++ ) {
       // Use push2 instead to test without pipeline
       obj.push(1000); 
       // Uncomment to see the acceleration
       //System.out.println(obj.i);
     }
     long endTime = System.currentTimeMillis();
     double d = 1000.0 * obj.i;
     d /= (double)(endTime - startTime);
     System.out.println("Throughput: "+d);
   }
 }

Pomocí tohoto programu můžete testovat s nebo bez zřetězení. Při použití zřetězení nezapomeňte zvýšit počet iterací (parametr N), aby probíhalo alespoň 10 sekund. Pokud odkomentujete println ve smyčce, uvědomíte si, že program je na začátku pomalý a bude rychlejší, jak JIT začne věci optimalizovat (proto by měl program běžet alespoň několik sekund, aby poskytl smysluplný výsledek).

Na mém hardwaru (starý box Athlon) mohu získat 8-9krát větší propustnost, když se používá potrubí. Program by mohl být dále vylepšen optimalizací formátování klíč/hodnota ve vnitřní smyčce a přidáním zahřívací fáze.




  1. mongodb přidat čítač ke každému načtenému dokumentu

  2. Programově nastavit převodník MongoDb

  3. Rychlý způsob, jak najít duplikáty v indexovaném sloupci v mongodb

  4. Mongoose findOneAndUpdate a upsert nevrací žádné chyby, žádné ovlivněné dokumenty