Er zijn een paar punten waarmee u rekening moet houden voordat u een dergelijke benchmark schrijft (en vooral een benchmark die de JVM gebruikt):
-
op de meeste (fysieke) machines kan Redis meer dan 100K ops/s verwerken wanneer pipelining wordt gebruikt. Uw benchmark heeft alleen betrekking op 100K-items, dus het duurt niet lang genoeg om zinvolle resultaten te produceren. Bovendien is er geen tijd om de opeenvolgende fasen van het JIT in gang te zetten.
-
de absolute tijd is geen erg relevante maatstaf. Het weergeven van de doorvoer (d.w.z. het aantal bewerkingen per seconde) terwijl de benchmark ten minste 10 seconden wordt uitgevoerd, zou een betere en stabielere statistiek zijn.
-
je innerlijke lus genereert veel afval. Als je van plan bent Jedis+Redis te benchmarken, moet je de overhead van je eigen programma laag houden.
-
omdat je alles in de hoofdfunctie hebt gedefinieerd, wordt je lus niet gecompileerd door de JIT (afhankelijk van de JVM die je gebruikt). Alleen de innerlijke methodeaanroepen mogen zijn. Als je wilt dat de JIT efficiënt is, zorg er dan voor dat je je code inkapselt in methoden die door de JIT kunnen worden gecompileerd.
-
optioneel wilt u misschien een opwarmfase toevoegen voordat u de eigenlijke meting uitvoert om te voorkomen dat u de overhead van het uitvoeren van de eerste iteraties met de bare-bone-interpreter en de kosten van de JIT zelf in rekening brengt.
Wat betreft Redis-pipelining, uw pijplijn is veel te lang. 100K-opdrachten in de pijplijn betekenen dat Jedis een buffer van 6 MB moet bouwen voordat hij iets naar Redis verzendt. Het betekent dat de socketbuffers (aan de clientzijde en misschien aan de serverzijde) verzadigd zullen zijn en dat Redis ook te maken zal krijgen met 6 MB communicatiebuffers.
Bovendien is uw benchmark nog steeds synchroon (het gebruik van een pijplijn maakt het niet op magische wijze asynchroon). Met andere woorden, Jedis begint pas antwoorden te lezen als de laatste vraag van je pijplijn naar Redis is verzonden. Wanneer de pijplijn te lang is, kan deze dingen blokkeren.
Overweeg de grootte van de pijplijn te beperken tot 100-1000 bewerkingen. Het levert natuurlijk meer roundtrips op, maar de druk op de communicatiestack wordt teruggebracht tot een acceptabel niveau. Beschouw bijvoorbeeld het volgende programma:
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);
}
}
Met dit programma kunt u testen met of zonder pipelining. Zorg ervoor dat u het aantal iteraties (N-parameter) verhoogt wanneer pipelining wordt gebruikt, zodat deze ten minste 10 seconden duurt. Als je de println in de lus verwijdert, zul je je realiseren dat het programma in het begin traag is en sneller zal worden naarmate het JIT begint met het optimaliseren van dingen (daarom zou het programma minstens enkele seconden moeten draaien om een zinvol resultaat te geven).
Op mijn hardware (een oude Athlon-box) kan ik 8-9 keer meer doorvoer krijgen wanneer de pijplijn wordt gebruikt. Het programma kan verder worden verbeterd door de sleutel/waarde-opmaak in de binnenste lus te optimaliseren en een opwarmfase toe te voegen.