Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add benchmarking application. No test clients yet. #629

4 changes: 1 addition & 3 deletions java/benchmarks/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id 'io.freefair.lombok'
}

repositories {
Expand All @@ -19,10 +18,9 @@ dependencies {
implementation 'io.lettuce:lettuce-core:6.2.6.RELEASE'
implementation 'commons-cli:commons-cli:1.5.0'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.13.0'
implementation group: 'org.apache.commons', name: 'commons-math3', version: '3.5'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1'

compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
}

// Apply a specific Java toolchain to ease working on different environments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,11 @@ public static void main(String[] args) {
// run testClientSetGet on JEDIS sync client
System.out.println("Run JEDIS sync client");
break;
case JEDIS_ASYNC:
// run testClientSetGet on JEDIS pseudo-async client
System.out.println("Run JEDIS pseudo-async client");
break;
case LETTUCE:
// run testClientSetGet on LETTUCE sync client
System.out.println("Run LETTUCE sync client");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's an async client

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I deleted the wrong reference. Restored.

break;
case LETTUCE_ASYNC:
// run testClientSetGet on LETTUCE async client
System.out.println("Run LETTUCE async client");
break;
case BABUSHKA_ASYNC:
case BABUSHKA:
System.out.println("Babushka async not yet configured");
break;
}
Expand Down Expand Up @@ -139,20 +131,7 @@ private static RunConfiguration verifyOptions(CommandLine line) throws ParseExce
e -> {
switch (e) {
case ALL:
return Stream.of(
ClientName.JEDIS,
ClientName.JEDIS_ASYNC,
ClientName.BABUSHKA,
ClientName.BABUSHKA_ASYNC,
ClientName.LETTUCE,
ClientName.LETTUCE_ASYNC);
case ALL_ASYNC:
return Stream.of(
ClientName.JEDIS_ASYNC,
ClientName.BABUSHKA_ASYNC,
ClientName.LETTUCE_ASYNC);
case ALL_SYNC:
return Stream.of(ClientName.JEDIS, ClientName.LETTUCE, ClientName.BABUSHKA);
return Stream.of(ClientName.JEDIS, ClientName.BABUSHKA, ClientName.LETTUCE);
default:
return Stream.of(e);
}
Expand Down Expand Up @@ -199,15 +178,10 @@ private static int[] parseIntListOption(String line) throws ParseException {
}

public enum ClientName {
JEDIS("Jedis"),
JEDIS_ASYNC("Jedis async"),
LETTUCE("Lettuce"),
LETTUCE_ASYNC("Lettuce async"),
BABUSHKA_ASYNC("Babushka async"),
BABUSHKA("Babushka"),
ALL("All"),
ALL_SYNC("All sync"),
ALL_ASYNC("All async");
JEDIS("Jedis"), // sync
LETTUCE("Lettuce"), // async
BABUSHKA("Babushka"), // async
ALL("All");

private String name;

Expand Down Expand Up @@ -242,16 +216,14 @@ public RunConfiguration() {
configuration = "Release";
resultsFile = Optional.empty();
dataSize = new int[] {100, 4000};
concurrentTasks = new int[] {100, 1000};
concurrentTasks = new int[] {1, 10, 100, 1000};
clients =
new ClientName[] {
// ClientName.LETTUCE,
// ClientName.LETTUCE_ASYNC,
ClientName.BABUSHKA_ASYNC, ClientName.BABUSHKA,
ClientName.ALL,
};
host = "localhost";
port = 6379;
clientCount = new int[] {1, 2};
clientCount = new int[] {1};
tls = false;
clusterModeEnabled = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@

import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javababushka.benchmarks.utils.ConnectionSettings;

/** A Redis client with async capabilities */
public interface AsyncClient<T> extends Client {

long DEFAULT_TIMEOUT_MILLISECOND = 1000;

Future<T> asyncConnectToRedis(ConnectionSettings connectionSettings);

Future<T> asyncSet(String key, String value);

Future<String> asyncGet(String key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

/** A Redis client interface */
public interface Client {
void connectToRedis();

void connectToRedis(ConnectionSettings connectionSettings);
shachlanAmazon marked this conversation as resolved.
Show resolved Hide resolved

default void closeConnection() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package javababushka.benchmarks.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import javababushka.benchmarks.BenchmarkingApp;
Expand All @@ -23,14 +21,6 @@ public class Benchmarking {
static final double PROB_GET_EXISTING_KEY = 0.8;
static final int SIZE_GET_KEYSPACE = 3750000;
static final int SIZE_SET_KEYSPACE = 3000000;
static final int ASYNC_OPERATION_TIMEOUT_SEC = 1;
static final double LATENCY_NORMALIZATION = 1000000.0;
static final int LATENCY_MIN = 100000;
static final int LATENCY_MAX = 10000000;
static final int LATENCY_MULTIPLIER = 10000;
static final double TPS_NORMALIZATION = 1000000000.0; // nano to seconds
// measurements are done in nano-seconds, but it should be converted to seconds later
static final double SECONDS_IN_NANO = 1e-9;
public static final double NANO_TO_SECONDS = 1e9;
shachlanAmazon marked this conversation as resolved.
Show resolved Hide resolved

private static ChosenAction randomAction() {
Expand Down Expand Up @@ -69,52 +59,17 @@ public static Pair<ChosenAction, Long> measurePerformance(Map<ChosenAction, Oper
return Pair.of(action, after - before);
}

// Assumption: latencies is sorted in ascending order
private static Long percentile(List<Long> latencies, int percentile) {
int N = latencies.size();
double n = (N - 1) * percentile / 100. + 1;
if (n == 1d) return latencies.get(0);
else if (n == N) return latencies.get(N - 1);
int k = (int) n;
double d = n - k;
return Math.round(latencies.get(k - 1) + d * (latencies.get(k) - latencies.get(k - 1)));
}

private static double stdDeviation(List<Long> latencies, Double avgLatency) {
double stdDeviation =
latencies.stream()
.mapToDouble(Long::doubleValue)
.reduce(0.0, (stdDev, latency) -> stdDev + Math.pow(latency - avgLatency, 2));
return Math.sqrt(stdDeviation / latencies.size());
}

// This has the side-effect of sorting each latencies ArrayList
public static Map<ChosenAction, LatencyResults> calculateResults(
Map<ChosenAction, List<Long>> actionLatencies) {
Map<ChosenAction, LatencyResults> results = new HashMap<>();

for (Map.Entry<ChosenAction, List<Long>> entry : actionLatencies.entrySet()) {
ChosenAction action = entry.getKey();
List<Long> latencies = entry.getValue();

if (latencies.size() == 0) {
results.put(action, new LatencyResults(0, 0, 0, 0, 0, 0));
} else {
double avgLatency =
SECONDS_IN_NANO
* latencies.stream().mapToLong(Long::longValue).sum()
/ latencies.size();
double[] latencies = entry.getValue().stream().mapToDouble(Long::doubleValue).toArray();

Collections.sort(latencies);
results.put(
action,
new LatencyResults(
avgLatency,
SECONDS_IN_NANO * percentile(latencies, 50),
SECONDS_IN_NANO * percentile(latencies, 90),
SECONDS_IN_NANO * percentile(latencies, 99),
SECONDS_IN_NANO * stdDeviation(latencies, avgLatency),
latencies.size()));
if (latencies.length != 0) {
results.put(action, new LatencyResults(latencies));
}
}

Expand Down Expand Up @@ -162,8 +117,8 @@ public static void testClientSetGet(
var clientName = clients.get(0).getName();

System.out.printf(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please log data size too

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 842a222

"%n =====> %s <===== %d clients %d concurrent %n%n",
clientName, clientCount, concurrentNum);
"%n =====> %s <===== %d clients %d concurrent %d data size %n%n",
clientName, clientCount, concurrentNum, dataSize);
AtomicInteger iterationCounter = new AtomicInteger(0);

long started = System.nanoTime();
Expand Down Expand Up @@ -260,7 +215,7 @@ public static void testClientSetGet(
concurrentNum,
tps);
}
printResults(calculatedResults, (after - started) / TPS_NORMALIZATION, iterations);
printResults(calculatedResults, (after - started) / NANO_TO_SECONDS, iterations);
}
}
}
Expand All @@ -276,26 +231,17 @@ public static Map<ChosenAction, Operation> getActionMap(
actions.put(
ChosenAction.GET_EXISTING,
async
? () ->
((AsyncClient) client)
.asyncGet(generateKeySet())
.get(ASYNC_OPERATION_TIMEOUT_SEC, TimeUnit.SECONDS)
? () -> ((AsyncClient) client).asyncGet(generateKeySet()).get()
: () -> ((SyncClient) client).get(generateKeySet()));
actions.put(
ChosenAction.GET_NON_EXISTING,
async
? () ->
((AsyncClient) client)
.asyncGet(generateKeyGet())
.get(ASYNC_OPERATION_TIMEOUT_SEC, TimeUnit.SECONDS)
? () -> ((AsyncClient) client).asyncGet(generateKeyGet()).get()
: () -> ((SyncClient) client).get(generateKeyGet()));
actions.put(
ChosenAction.SET,
async
? () ->
((AsyncClient) client)
.asyncSet(generateKeySet(), value)
.get(ASYNC_OPERATION_TIMEOUT_SEC, TimeUnit.SECONDS)
? () -> ((AsyncClient) client).asyncSet(generateKeySet(), value).get()
: () -> ((SyncClient) client).set(generateKeySet(), value));
return actions;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package javababushka.benchmarks.utils;

import lombok.AllArgsConstructor;

/** Redis-client settings */
@AllArgsConstructor
public class ConnectionSettings {
public final String host;
public final int port;
public final boolean useSsl;
public final boolean clusterMode;

public ConnectionSettings(String host, int port, boolean useSsl, boolean clusterMode) {
this.host = host;
this.port = port;
this.useSsl = useSsl;
this.clusterMode = clusterMode;
}
}
Loading