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

Java benchmarks app: Add TLS flag to Lettuce/Jedis benchmarks #9

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added benchmarks/.install_and_test.sh.swp
Binary file not shown.
10 changes: 8 additions & 2 deletions benchmarks/install_and_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ function runJavaBenchmark(){
cd ${BENCH_FOLDER}/java
}

function runJavaBenchmark(){
cd ${BENCH_FOLDER}/../java
echo "./gradlew run --args=\"--resultsFile=${BENCH_FOLDER}/$1 --clients $chosenClients --host $host --port $port\""
# ./gradlew run --args="--resultsFile=../$1 --dataSize $2 --concurrentTasks $concurrentTasks --clients $chosenClients --host $host --port $port --clientCount $clientCount $tlsFlag"
./gradlew run --args="--resultsFile=${BENCH_FOLDER}/$1 --clients $chosenClients --host $host --port $port"
cd ${BENCH_FOLDER}/java
}

function runRustBenchmark(){
rustConcurrentTasks=
for value in $concurrentTasks
Expand Down Expand Up @@ -280,8 +288,6 @@ do
fi
done



flushDB

if [ $writeResultsCSV == 1 ];
Expand Down
3 changes: 0 additions & 3 deletions java/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,3 @@

# Ignore Gradle build output directory
build

# Ignore generated files (e.g. protobuf)
generated
14 changes: 3 additions & 11 deletions java/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Summary - Java Wrapper

This module contains a Java-client wrapper that connects to the `Babushka`-rust-client. The rust client connects to
redis, while this wrapper provides Java-language binding. The objective of this wrapper is to provide a thin-wrapper
This module contains a Java-client wrapper that connects to the `Babushka`-rust-client. The rust client connects to
redis, while this wrapper provides Java-language binding. The objective of this wrapper is to provide a thin-wrapper
language api to enhance performance and limit cpu cycles at scale.

## Organization
Expand All @@ -16,17 +16,9 @@ The Java client (javabushka) contains the following parts:

You can assemble the Java clients benchmarks by compiling using `./gradlew build`.

## Code style

Code style is enforced by spotless with Google Java Format. The build fails if code formatted incorrectly, but you can auto-format code with `./gradlew spotlessApply`.
Run this command before every commit to keep code in the same style.
These IDE plugins can auto-format code on file save or by single click:
* [For Intellij IDEA](https://plugins.jetbrains.com/plugin/18321-spotless-gradle)
* [For VS Code](https://marketplace.visualstudio.com/items?itemName=richardwillis.vscode-spotless-gradle)

## Benchmarks

You can run benchmarks using `./gradlew run`. You can set arguments using the args flag like:
You can run benchmarks using `./gradlew run`. You can set arguments using the args flag like:

```shell
./gradlew run --args="--clients lettuce"
Expand Down
40 changes: 40 additions & 0 deletions java/benchmarks/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

dependencies {
// Use JUnit test framework.
testImplementation 'junit:junit:4.13.2'

// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:32.1.1-jre'
implementation 'redis.clients:jedis:4.4.3'
implementation 'io.lettuce:lettuce-core:6.2.6.RELEASE'
implementation 'commons-cli:commons-cli:1.5.0'
}

// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

application {
// Define the main class for the application.
mainClass = 'javabushka.client.BenchmarkingApp'
}

tasks.withType(Test) {
testLogging {
exceptionFormat "full"
events "started", "skipped", "passed", "failed"
showStandardStreams true
}
}
251 changes: 251 additions & 0 deletions java/benchmarks/src/main/java/javabushka/client/BenchmarkingApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
package javabushka.client;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javabushka.client.jedis.JedisClient;
import javabushka.client.lettuce.LettuceAsyncClient;
import javabushka.client.utils.Benchmarking;
import javabushka.client.utils.ChosenAction;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

/**
* Benchmarking app for reporting performance of various redis-rs Java-clients
*/
public class BenchmarkingApp {

// main application entrypoint
public static void main(String[] args) {

// create the parser
CommandLineParser parser = new DefaultParser();
Options options = getOptions();
RunConfiguration runConfiguration = new RunConfiguration();
try {
// parse the command line arguments
CommandLine line = parser.parse(options, args);
runConfiguration = verifyOptions(line);
}
catch (ParseException exp) {
// oops, something went wrong
System.err.println("Parsing failed. Reason: " + exp.getMessage());
}

try {
switch (runConfiguration.clients) {
case ALL:
testJedisClientResourceSetGet(runConfiguration);
testLettuceClientResourceSetGet(runConfiguration);
System.out.println("Babushka not yet configured");
break;
case JEDIS:
testJedisClientResourceSetGet(runConfiguration);
break;
case LETTUCE:
testLettuceClientResourceSetGet(runConfiguration);
break;
case BABUSHKA:
System.out.println("Babushka not yet configured");
break;
}
} catch (IOException ioException) {
System.out.println("Error writing to results file");
ioException.printStackTrace();
}

if (runConfiguration.resultsFile.isPresent()) {
try {
runConfiguration.resultsFile.get().close();
} catch (IOException ioException) {
System.out.println("Error closing results file");
}
}

}

private static Options getOptions() {
// create the Options
Options options = new Options();

options.addOption("c", "configuration", true, "Configuration flag [Release]");
options.addOption("f", "resultsFile", true, "Result filepath []");
options.addOption("C", "concurrentTasks", true, "Number of concurrent tasks [1 10 100]");
options.addOption("l", "clients", true, "one of: all|jedis|lettuce|babushka [all]");
options.addOption("h", "host", true, "host url [localhost]");
options.addOption("p", "port", true, "port number [6379]");
options.addOption("n", "clientCount", true, "Client count [1]");
options.addOption("t", "tls", false, "with TLS [false]");

return options;
}

private static RunConfiguration verifyOptions(CommandLine line) throws ParseException {
RunConfiguration runConfiguration = new RunConfiguration();
if (line.hasOption("configuration")) {
String configuration = line.getOptionValue("configuration");
if (configuration.equalsIgnoreCase("Release") || configuration.equalsIgnoreCase("Debug")) {
runConfiguration.configuration = configuration;
} else {
throw new ParseException("Invalid run configuration (Release|Debug)");
}
}

if (line.hasOption("resultsFile")) {
try {
runConfiguration.resultsFile = Optional.of(new FileWriter(line.getOptionValue("resultsFile")));
} catch (IOException e) {
throw new ParseException("Unable to write to resultsFile.");
}
}

if (line.hasOption("concurrentTasks")) {
String concurrentTasks = line.getOptionValue("concurrentTasks");

// remove optional square brackets
if (concurrentTasks.startsWith("[") && concurrentTasks.endsWith("]")) {
concurrentTasks = concurrentTasks.substring(1, concurrentTasks.length() - 1);
}
// check if it's the correct format
if (!concurrentTasks.matches("\\d+(\\s+\\d+)?")) {
throw new ParseException("Invalid concurrentTasks");
}
// split the string into a list of integers
runConfiguration.concurrentTasks =
Arrays.stream(concurrentTasks.split("\\s+"))
.map(Integer::parseInt)
.collect(Collectors.toList());
}

if (line.hasOption("clients")) {
String clients = line.getOptionValue("clients");
if (ClientName.ALL.isEqual(clients)) {
runConfiguration.clients = ClientName.ALL;
} else if (ClientName.JEDIS.isEqual(clients)) {
runConfiguration.clients = ClientName.JEDIS;
} else if (ClientName.LETTUCE.isEqual(clients)) {
runConfiguration.clients = ClientName.LETTUCE;
} else if (ClientName.BABUSHKA.isEqual(clients)) {
runConfiguration.clients = ClientName.BABUSHKA;
} else {
throw new ParseException("Invalid clients option: all|jedis|lettuce|babushka");
}
}

if (line.hasOption("host")) {
runConfiguration.host = line.getOptionValue("host");
}

if (line.hasOption("clientCount")) {
runConfiguration.clientCount = Integer.parseInt(line.getOptionValue("clientCount"));
}

runConfiguration.tls = line.hasOption("tls");

return runConfiguration;
}

private static void testJedisClientResourceSetGet(RunConfiguration runConfiguration) throws IOException {
JedisClient jedisClient = new JedisClient();
jedisClient.connectToRedis(runConfiguration.host, runConfiguration.port, runConfiguration.tls);

int iterations = 100000;
String value = "my-value";

if (runConfiguration.resultsFile.isPresent()) {
runConfiguration.resultsFile.get().write("JEDIS client Benchmarking: ");
} else {
System.out.println("JEDIS client Benchmarking: ");
}

Map<ChosenAction, Benchmarking.Operation> actions = new HashMap<>();
actions.put(ChosenAction.GET_EXISTING, () -> jedisClient.get(Benchmarking.generateKeySet()));
actions.put(ChosenAction.GET_NON_EXISTING, () -> jedisClient.get(Benchmarking.generateKeyGet()));
actions.put(ChosenAction.SET, () -> jedisClient.set(Benchmarking.generateKeySet(), value));

Benchmarking.printResults(
Benchmarking.calculateResults(Benchmarking.getLatencies(iterations, actions)),
runConfiguration.resultsFile
);
}

private static LettuceAsyncClient initializeLettuceClient() {
LettuceAsyncClient lettuceClient = new LettuceAsyncClient();
lettuceClient.connectToRedis();
return lettuceClient;
}

private static void testLettuceClientResourceSetGet(RunConfiguration runConfiguration) throws IOException {

LettuceAsyncClient lettuceClient = new LettuceAsyncClient();
lettuceClient.connectToRedis(runConfiguration.host, runConfiguration.port, runConfiguration.tls);

int iterations = 100000;
String value = "my-value";

if (runConfiguration.resultsFile.isPresent()) {
runConfiguration.resultsFile.get().write("LETTUCE client Benchmarking: ");
} else {
System.out.println("LETTUCE client Benchmarking: ");
}

HashMap<ChosenAction, Benchmarking.Operation> actions = new HashMap<>();
actions.put(ChosenAction.GET_EXISTING, () -> lettuceClient.get(Benchmarking.generateKeySet()));
actions.put(ChosenAction.GET_NON_EXISTING, () -> lettuceClient.get(Benchmarking.generateKeyGet()));
actions.put(ChosenAction.SET, () -> lettuceClient.set(Benchmarking.generateKeySet(), value));

Benchmarking.printResults(
Benchmarking.calculateResults(Benchmarking.getLatencies(iterations, actions)),
runConfiguration.resultsFile
);
}

public enum ClientName {
JEDIS("Jedis"),
LETTUCE("Lettuce"),
BABUSHKA("Babushka"),
ALL("All");

private String name;
private ClientName(String name) {
this.name = name;
}

@Override
public String toString() { return this.name; }

public boolean isEqual(String other) {
return this.toString().equalsIgnoreCase(other);
}
}

public static class RunConfiguration {
public String configuration;
public Optional<FileWriter> resultsFile;
public List<Integer> concurrentTasks;
public ClientName clients;
public String host;
public int port;
public int clientCount;
public boolean tls;

public RunConfiguration() {
configuration = "Release";
resultsFile = Optional.empty();
concurrentTasks = List.of(1, 10, 100);
clients = ClientName.ALL;
host = "localhost";
port = 6379;
clientCount = 1;
tls = false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package javabushka.client.jedis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisClient {

public final static String DEFAULT_HOST = "localhost";
public final static int DEFAULT_PORT = 6379;
public final static boolean DEFAULT_TLS = false;

Jedis jedisResource;
public boolean someLibraryMethod() {
return true;
}

public void connectToRedis(String host, int port, boolean tls) {
JedisPool pool = new JedisPool(host, port, tls);
jedisResource = pool.getResource();
}

public void connectToRedis() {
connectToRedis(DEFAULT_HOST, DEFAULT_PORT, DEFAULT_TLS);
}

public String info() {
return jedisResource.info();
}

public String info(String section) {
return jedisResource.info(section);
}

public void set(String key, String value) {
jedisResource.set(key, value);
}

public String get(String key) {
return jedisResource.get(key);
}
}
Loading
Loading