sql >> Database teknologi >  >> NoSQL >> Redis

hvorfor er det så langsomt med 100.000 poster, når man bruger pipeline i redis?

Der er et par punkter, du skal overveje, før du skriver sådan et benchmark (og især et benchmark ved hjælp af JVM):

  • på de fleste (fysiske) maskiner er Redis i stand til at behandle mere end 100K ops/s, når pipelining bruges. Dit benchmark omhandler kun 100.000 varer, så det holder ikke længe nok til at give meningsfulde resultater. Ydermere er der ikke tid til, at de på hinanden følgende faser af JIT kan komme i gang.

  • den absolutte tid er ikke en særlig relevant målestok. At vise gennemløbet (dvs. antallet af operationer pr. sekund), mens benchmarket holdes kørende i mindst 10 sekunder, ville være en bedre og mere stabil metrik.

  • din indre løkke genererer en masse affald. Hvis du planlægger at benchmarke Jedis+Redis, skal du holde omkostningerne ved dit eget program lavt.

  • fordi du har defineret alt i hovedfunktionen, vil din loop ikke blive kompileret af JIT'en (afhængigt af den JVM du bruger). Kun de indre metodekald kan være. Hvis du ønsker, at JIT skal være effektiv, skal du sørge for at indkapsle din kode i metoder, der kan kompileres af JIT.

  • eventuelt vil du måske tilføje en opvarmningsfase, før du udfører den faktiske måling, for at undgå at tage højde for omkostningerne ved at køre de første iterationer med bare-bone-tolken og omkostningerne ved selve JIT'en.

Hvad angår Redis pipelining, er din pipeline alt for lang. 100K kommandoer i pipelinen betyder, at Jedis skal bygge en 6MB buffer, før han sender noget til Redis. Det betyder, at socketbufferne (på klientsiden og måske serversiden) vil være mættede, og at Redis også skal håndtere 6 MB kommunikationsbuffere.

Ydermere er dit benchmark stadig synkront (at bruge en pipeline gør den ikke på magisk vis asynkron). Med andre ord vil Jedis ikke begynde at læse svar, før den sidste forespørgsel i din pipeline er blevet sendt til Redis. Når pipelinen er for lang, har den potentiale til at blokere ting.

Overvej at begrænse størrelsen af ​​rørledningen til 100-1000 operationer. Det vil selvfølgelig generere flere rundrejser, men presset på kommunikationsstakken vil blive reduceret til et acceptabelt niveau. Overvej f.eks. følgende 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);
   }
 }

Med dette program kan du teste med eller uden pipelining. Sørg for at øge antallet af iterationer (N-parameter), når pipelining bruges, så den kører i mindst 10 sekunder. Hvis du fjerner kommentering af println i løkken, vil du indse, at programmet er langsomt i starten og vil blive hurtigere, efterhånden som JIT begynder at optimere tingene (det er derfor, programmet bør køre i mindst flere sekunder for at give et meningsfuldt resultat).

På min hardware (en gammel Athlon-boks) kan jeg få 8-9 gange mere gennemløb, når rørledningen bruges. Programmet kan forbedres yderligere ved at optimere nøgle/værdi-formatering i den indre løkke og tilføje en opvarmningsfase.




  1. Spring Data MongoDB med Java 8 LocalDate MappingException

  2. ekskluder felter i $lookup-sammenlægning

  3. Php7 Redis Client på Alpine OS

  4. MongoDB $type Aggregation Pipeline Operator