diff --git a/.github/workflows/pr-build-and-test.yml b/.github/workflows/pr-build-and-test.yml new file mode 100644 index 000000000..990320865 --- /dev/null +++ b/.github/workflows/pr-build-and-test.yml @@ -0,0 +1,45 @@ +name: Build and test + +on: + pull_request: + branches: + - master + push: + branches: + - master + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + + - name: Build and Verify + run: mvn --no-transfer-progress --batch-mode verify + + - name: package surefire test results + if: failure() + run: | + rm -rf test-results + mkdir test-results + find . -type d -name "*surefire*" -exec cp --parents -R {} test-results/ \; + zip -r test-results.zip test-results + - uses: actions/upload-artifact@v4 + name: upload test-results + if: failure() + with: + name: test-results + path: test-results.zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f49b598ab..000000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -dist: trusty - -notifications: - email: - recipients: - - openmessaging@googlegroups.com - on_success: change - on_failure: always - -language: java - -jdk: - - oraclejdk8 - - oraclejdk11 - -script: - - mvn clean install diff --git a/README.md b/README.md index 8247c9fe2..4056f2480 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,51 @@ -# OpenMessaging Benchmark Framework -[![Build Status](https://app.travis-ci.com/openmessaging/benchmark.svg?branch=master)](https://app.travis-ci.com/openmessaging/benchmark) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/openmessaging/benchmark.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/openmessaging/benchmark/alerts/) -[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/openmessaging/benchmark.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/openmessaging/benchmark/context:python) -[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/openmessaging/benchmark.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/openmessaging/benchmark/context:java) -[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) +# Fork of the OpenMessaging Benchmark Framework that uses sapmachine 17 docker image + +This fork is used to update the outdated offical docker hub image openmessaging/openmessaging-benchmark with sapmachine:17. +Find more in [./docker/README.md](./docker/README.md). +[![Build](https://github.com/openmessaging/benchmark/actions/workflows/pr-build-and-test.yml/badge.svg)](https://github.com/openmessaging/benchmark/actions/workflows/pr-build-and-test.yml) +[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) -**Notice:** We do not consider or plan to release any unilateral test results based on this standard. For reference, you can purchase server tests on the cloud by yourself. +**Notice:** We do not consider or plan to release any unilateral test results based on this standard. For reference, you can purchase server tests on the cloud by yourself. This repository houses user-friendly, cloud-ready benchmarking suites for the following messaging platforms: +* [Apache ActiveMQ Artemis](https://activemq.apache.org/components/artemis/) +* [Apache Bookkeeper](https://bookkeeper.apache.org) * [Apache Kafka](https://kafka.apache.org) +* [Apache Pulsar](https://pulsar.apache.org) * [Apache RocketMQ](https://rocketmq.apache.org) +* Generic [JMS](https://javaee.github.io/jms-spec/) +* [KoP (Kafka-on-Pulsar)](https://github.com/streamnative/kop) +* [NATS JetStream](https://docs.nats.io/nats-concepts/jetstream) +* [NATS Streaming (STAN)](https://docs.nats.io/legacy/stan/intro) +* [NSQ](https://nsq.io) +* [Pravega](https://pravega.io/) * [RabbitMQ](https://www.rabbitmq.com/) -* [Apache Pulsar](https://pulsar.apache.org) -* [NATS Streaming](https://nats.io/) * [Redis](https://redis.com/) -* [Pravega](https://pravega.io/) +* [MQTT](https://mqtt.org/) > More details could be found at the [official documentation](http://openmessaging.cloud/docs/benchmarks/). +## Build + +Requirements: + +* JDK 17 +* Maven 3.8.6+ + +Common build actions: + +| Action | Command | +|---------------------------------|------------------------------------------| +| Full build and test | `mvn clean verify` | +| Skip tests | `mvn clean verify -DskipTests` | +| Skip Jacoco test coverage check | `mvn clean verify -Djacoco.skip` | +| Skip Checkstyle standards check | `mvn clean verify -Dcheckstyle.skip` | +| Skip Spotless formatting check | `mvn clean verify -Dspotless.check.skip` | +| Format code | `mvn spotless:apply` | +| Generate license headers | `mvn license:format` | + +## License +Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 diff --git a/benchmark-framework/pom.xml b/benchmark-framework/pom.xml index d559e0595..698a79c9a 100644 --- a/benchmark-framework/pom.xml +++ b/benchmark-framework/pom.xml @@ -1,234 +1,208 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - - - benchmark-framework - - - 2.17.1 - - - - - ${project.groupId} - driver-api - ${project.version} - - - - org.hdrhistogram - HdrHistogram - 2.1.10 - - - - com.google.guava - guava - - - - org.apache.logging.log4j - log4j-core - ${log4j.version} - - - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-base - 2.9.3 - - - com.fasterxml.jackson.jaxrs - jackson-jaxrs-json-provider - 2.9.3 - - - com.fasterxml.jackson.core - jackson-annotations - 2.9.3 - - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - 2.9.3 - - - - org.apache.logging.log4j - log4j-slf4j-impl - ${log4j.version} - - - - com.beust - jcommander - 1.48 - - - - ${project.groupId} - driver-pulsar - ${project.version} - - - - ${project.groupId} - driver-jms - ${project.version} - - - - ${project.groupId} - driver-kafka - ${project.version} - - - - ${project.groupId} - driver-pravega - ${project.version} - - - - ${project.groupId} - driver-rocketmq - ${project.version} - - - - ${project.groupId} - driver-rabbitmq - ${project.version} - - - - ${project.groupId} - driver-artemis - ${project.version} - - - - ${project.groupId} - driver-bookkeeper - ${project.version} - - - - ${project.groupId} - driver-nats - ${project.version} - - - - ${project.groupId} - driver-nats-streaming - ${project.version} - - - - ${project.groupId} - driver-nsq - ${project.version} - - - - ${project.groupId} - driver-redis - ${project.version} - - - - org.apache.bookkeeper.stats - bookkeeper-stats-api - ${bookkeeper.version} - - - - org.apache.bookkeeper.stats - prometheus-metrics-provider - ${bookkeeper.version} - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + benchmark-framework + + + 9.4.42.v20210604 + + + + + ${project.groupId} + driver-api + ${project.version} + + + ${project.groupId} + driver-artemis + ${project.version} + + + io.netty + * + + + + + ${project.groupId} + driver-bookkeeper + ${project.version} + + + ${project.groupId} + driver-jms + ${project.version} + + + ${project.groupId} + driver-kafka + ${project.version} + + + ${project.groupId} + driver-kop + ${project.version} + + + ${project.groupId} + driver-mqtt5 + ${project.version} + + + ${project.groupId} + driver-nats + ${project.version} + + + ${project.groupId} + driver-nsq + ${project.version} + + + ${project.groupId} + driver-pravega + ${project.version} + + + ${project.groupId} + driver-pulsar + ${project.version} + + + ${project.groupId} + driver-rabbitmq + ${project.version} + + + ${project.groupId} + driver-redis + ${project.version} + + + ${project.groupId} + driver-rocketmq + ${project.version} + + + ${project.groupId} + driver-rocketmq5 + ${project.version} + + + com.beust + jcommander + + io.javalin javalin 1.3.0 - - - org.asynchttpclient - async-http-client - 2.10.4 - - - - - org.eclipse.jetty - jetty-server - 9.4.42.v20210604 - - - - junit - junit - 4.13.1 - test - - - - org.eclipse.jetty - jetty-util - 9.4.42.v20210604 - - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - 2.10 - - - build-classpath - generate-sources - - build-classpath - - - target/classpath.txt - - - - - - + + org.apache.bookkeeper.stats + prometheus-metrics-provider + ${bookkeeper.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.asynchttpclient + async-http-client + 2.12.3 + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-util + ${jetty.version} + + + org.hdrhistogram + HdrHistogram + 2.1.12 + + + ${project.groupId} + driver-nats-streaming + ${project.version} + provided + + + org.projectlombok + lombok + provided + + + com.github.stefanbirkner + system-lambda + 1.2.1 + test + + + org.assertj + assertj-core + test + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-junit-jupiter + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + build-classpath + + build-classpath + + generate-sources + + target/classpath.txt + + + + + + diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/Benchmark.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/Benchmark.java index 86ddd9e9c..cf95e116e 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/Benchmark.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/Benchmark.java @@ -1,34 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; -import java.io.File; -import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.util.stream.Collectors.toList; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; @@ -37,40 +22,63 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; - import io.openmessaging.benchmark.worker.DistributedWorkersEnsemble; +import io.openmessaging.benchmark.worker.HttpWorkerClient; import io.openmessaging.benchmark.worker.LocalWorker; import io.openmessaging.benchmark.worker.Worker; +import java.io.File; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Benchmark { static class Arguments { - @Parameter(names = {"-c", "--csv"}, description = "Print results from this directory to a csv file") + @Parameter( + names = {"-c", "--csv"}, + description = "Print results from this directory to a csv file") String resultsDir; - @Parameter(names = { "-h", "--help" }, description = "Help message", help = true) + @Parameter( + names = {"-h", "--help"}, + description = "Help message", + help = true) boolean help; - @Parameter(names = { "-d", - "--drivers" }, description = "Drivers list. eg.: pulsar/pulsar.yaml,kafka/kafka.yaml")//, required = true) + @Parameter( + names = {"-d", "--drivers"}, + description = + "Drivers list. eg.: pulsar/pulsar.yaml,kafka/kafka.yaml") // , required = true) public List drivers; - @Parameter(names = { "-w", - "--workers" }, description = "List of worker nodes. eg: http://1.2.3.4:8080,http://4.5.6.7:8080") + @Parameter( + names = {"-w", "--workers"}, + description = "List of worker nodes. eg: http://1.2.3.4:8080,http://4.5.6.7:8080") public List workers; - @Parameter(names = { "-wf", - "--workers-file" }, description = "Path to a YAML file containing the list of workers addresses") + @Parameter( + names = {"-wf", "--workers-file"}, + description = "Path to a YAML file containing the list of workers addresses") public File workersFile; - @Parameter(names = { "-x", "--extra" }, description = "Allocate extra consumer workers when your backlog builds.") + @Parameter( + names = {"-x", "--extra"}, + description = "Allocate extra consumer workers when your backlog builds.") boolean extraConsumers; - @Parameter(description = "Workloads")//, required = true) + @Parameter(description = "Workloads") // , required = true) public List workloads; - @Parameter(names = { "-o", "--output" }, description = "Output", required = false) + @Parameter( + names = {"-o", "--output"}, + description = "Output", + required = false) public String output; } @@ -92,7 +100,7 @@ public static void main(String[] args) throws Exception { System.exit(-1); } - if(arguments.resultsDir != null) { + if (arguments.resultsDir != null) { ResultsToCsv r = new ResultsToCsv(); r.writeAllResultFiles(arguments.resultsDir); System.exit(0); @@ -132,55 +140,71 @@ public static void main(String[] args) throws Exception { Worker worker; if (arguments.workers != null && !arguments.workers.isEmpty()) { - worker = new DistributedWorkersEnsemble(arguments.workers, arguments.extraConsumers); + List workers = + arguments.workers.stream().map(HttpWorkerClient::new).collect(toList()); + worker = new DistributedWorkersEnsemble(workers, arguments.extraConsumers); } else { // Use local worker implementation worker = new LocalWorker(); } - workloads.forEach((workloadName, workload) -> { - arguments.drivers.forEach(driverConfig -> { - try { - File driverConfigFile = new File(driverConfig); - DriverConfiguration driverConfiguration = mapper.readValue(driverConfigFile, - DriverConfiguration.class); - log.info("--------------- WORKLOAD : {} --- DRIVER : {}---------------", workload.name, - driverConfiguration.name); - - // Stop any left over workload - worker.stopAll(); - - worker.initializeDriver(new File(driverConfig)); - - WorkloadGenerator generator = new WorkloadGenerator(driverConfiguration.name, workload, worker); - - TestResult result = generator.run(); - - boolean useOutput = (arguments.output != null) && (arguments.output.length() > 0); - - String fileName = useOutput? arguments.output: String.format("%s-%s-%s.json", workloadName, - driverConfiguration.name, dateFormat.format(new Date())); - - log.info("Writing test result into {}", fileName); - writer.writeValue(new File(fileName), result); - - generator.close(); - } catch (Exception e) { - log.error("Failed to run the workload '{}' for driver '{}'", workload.name, driverConfig, e); - } finally { - try { - worker.stopAll(); - } catch (IOException e) { - } - } - }); - }); + workloads.forEach( + (workloadName, workload) -> { + arguments.drivers.forEach( + driverConfig -> { + try { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + File driverConfigFile = new File(driverConfig); + DriverConfiguration driverConfiguration = + mapper.readValue(driverConfigFile, DriverConfiguration.class); + log.info( + "--------------- WORKLOAD : {} --- DRIVER : {}---------------", + workload.name, + driverConfiguration.name); + + // Stop any left over workload + worker.stopAll(); + + worker.initializeDriver(new File(driverConfig)); + + WorkloadGenerator generator = + new WorkloadGenerator(driverConfiguration.name, workload, worker); + + TestResult result = generator.run(); + + boolean useOutput = (arguments.output != null) && (arguments.output.length() > 0); + + String fileName = + useOutput + ? arguments.output + : String.format( + "%s-%s-%s.json", + workloadName, + driverConfiguration.name, + dateFormat.format(new Date())); + + log.info("Writing test result into {}", fileName); + writer.writeValue(new File(fileName), result); + + generator.close(); + } catch (Exception e) { + log.error( + "Failed to run the workload '{}' for driver '{}'", + workload.name, + driverConfig, + e); + } finally { + worker.stopAll(); + } + }); + }); worker.close(); } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); static { mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); @@ -188,7 +212,5 @@ public static void main(String[] args) throws Exception { private static final ObjectWriter writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); - private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - private static final Logger log = LoggerFactory.getLogger(Benchmark.class); } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/DriverConfiguration.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/DriverConfiguration.java index 07852263b..8e6c858a3 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/DriverConfiguration.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/DriverConfiguration.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; @@ -22,5 +17,4 @@ public class DriverConfiguration { public String name; public String driverClass; - } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/RateController.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/RateController.java new file mode 100644 index 000000000..edb4b9165 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/RateController.java @@ -0,0 +1,96 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static lombok.AccessLevel.PACKAGE; + +import io.openmessaging.benchmark.utils.Env; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +class RateController { + private static final long ONE_SECOND_IN_NANOS = SECONDS.toNanos(1); + private final long publishBacklogLimit; + private final long receiveBacklogLimit; + private final double minRampingFactor; + private final double maxRampingFactor; + + @Getter(PACKAGE) + private double rampingFactor; + + private long previousTotalPublished = 0; + private long previousTotalReceived = 0; + + RateController() { + publishBacklogLimit = Env.getLong("PUBLISH_BACKLOG_LIMIT", 1_000); + receiveBacklogLimit = Env.getLong("RECEIVE_BACKLOG_LIMIT", 1_000); + minRampingFactor = Env.getDouble("MIN_RAMPING_FACTOR", 0.01); + maxRampingFactor = Env.getDouble("MAX_RAMPING_FACTOR", 1); + rampingFactor = maxRampingFactor; + } + + double nextRate(double rate, long periodNanos, long totalPublished, long totalReceived) { + long expected = (long) ((rate / ONE_SECOND_IN_NANOS) * periodNanos); + long published = totalPublished - previousTotalPublished; + long received = totalReceived - previousTotalReceived; + + previousTotalPublished = totalPublished; + previousTotalReceived = totalReceived; + + if (log.isDebugEnabled()) { + log.debug( + "Current rate: {} -- Publish rate {} -- Receive Rate: {}", + rate, + rate(published, periodNanos), + rate(received, periodNanos)); + } + + long receiveBacklog = totalPublished - totalReceived; + if (receiveBacklog > receiveBacklogLimit) { + return nextRate(periodNanos, received, expected, receiveBacklog, "Receive"); + } + + long publishBacklog = expected - published; + if (publishBacklog > publishBacklogLimit) { + return nextRate(periodNanos, published, expected, publishBacklog, "Publish"); + } + + rampUp(); + + return rate + (rate * rampingFactor); + } + + private double nextRate(long periodNanos, long actual, long expected, long backlog, String type) { + log.debug("{} backlog: {}", type, backlog); + rampDown(); + long nextExpected = Math.max(0, expected - backlog); + double nextExpectedRate = rate(nextExpected, periodNanos); + double actualRate = rate(actual, periodNanos); + return Math.min(actualRate, nextExpectedRate); + } + + private double rate(long count, long periodNanos) { + return (count / (double) periodNanos) * ONE_SECOND_IN_NANOS; + } + + private void rampUp() { + rampingFactor = Math.min(maxRampingFactor, rampingFactor * 2); + } + + private void rampDown() { + rampingFactor = Math.max(minRampingFactor, rampingFactor / 2); + } +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/ResultsToCsv.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/ResultsToCsv.java index 5b09b9ec0..9ee84ece3 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/ResultsToCsv.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/ResultsToCsv.java @@ -1,31 +1,24 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.HdrHistogram.Histogram; -import org.bouncycastle.util.test.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.*; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.text.MessageFormat; import java.time.Instant; import java.util.ArrayList; @@ -33,6 +26,9 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import org.HdrHistogram.Histogram; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ResultsToCsv { @@ -42,39 +38,46 @@ public void writeAllResultFiles(String directory) { try { File dir = new File(directory); File[] directoryListing = dir.listFiles(); + if (directoryListing == null) { + throw new IllegalArgumentException("Not a directory: " + directory); + } Arrays.sort(directoryListing); List lines = new ArrayList<>(); - lines.add("topics,partitions,message-size,producers-per-topic,consumers-per-topic," + - "prod-rate-min,prod-rate-avg,prod-rate-std-dev,prod-rate-max," + - "con-rate-min,con-rate-avg,con-rate-std-dev,con-rate-max,"); + lines.add( + "topics,partitions,message-size,producers-per-topic,consumers-per-topic," + + "prod-rate-min,prod-rate-avg,prod-rate-std-dev,prod-rate-max," + + "con-rate-min,con-rate-avg,con-rate-std-dev,con-rate-max,"); List results = new ArrayList<>(); for (File file : directoryListing) { if (file.isFile() && file.getAbsolutePath().endsWith(".json")) { ObjectMapper objectMapper = new ObjectMapper(); - TestResult tr = objectMapper.readValue(new File(file.getAbsolutePath()), TestResult.class); + TestResult tr = + objectMapper.readValue(new File(file.getAbsolutePath()), TestResult.class); results.add(tr); } } - List sortedResults = results.stream().sorted( - Comparator.comparing(TestResult::getMessageSize) - .thenComparing(TestResult::getTopics) - .thenComparing(TestResult::getPartitions)).collect(Collectors.toList()); - for(TestResult tr : sortedResults) { + List sortedResults = + results.stream() + .sorted( + Comparator.comparing(TestResult::getMessageSize) + .thenComparing(TestResult::getTopics) + .thenComparing(TestResult::getPartitions)) + .collect(Collectors.toList()); + for (TestResult tr : sortedResults) { lines.add(extractResults(tr)); } String resultsFileName = "results-" + Instant.now().getEpochSecond() + ".csv"; - FileWriter writer = new FileWriter(resultsFileName); - for (String str : lines) { - writer.write(str + System.lineSeparator()); + try (FileWriter writer = new FileWriter(resultsFileName)) { + for (String str : lines) { + writer.write(str + System.lineSeparator()); + } + log.info("Results extracted into CSV " + resultsFileName); } - writer.close(); - log.info("Results extracted into CSV " + resultsFileName); - } - catch(Exception e) { + } catch (IOException e) { log.error("Failed creating csv file.", e); } } @@ -84,38 +87,37 @@ public String extractResults(TestResult tr) { Histogram prodRateHistogram = new Histogram(10000000, 1); Histogram conRateHistogram = new Histogram(10000000, 1); - for(Double rate : tr.publishRate) { + for (Double rate : tr.publishRate) { prodRateHistogram.recordValueWithCount(rate.longValue(), 2); } - for(Double rate : tr.consumeRate) { + for (Double rate : tr.consumeRate) { conRateHistogram.recordValueWithCount(rate.longValue(), 2); } - String line = MessageFormat.format("{0,number,#},{1,number,#},{2,number,#},{3,number,#},{4,number,#}," + - "{5,number,#},{6,number,#},{7,number,#.##},{8,number,#}," + - "{9,number,#},{10,number,#},{11,number,#.##},{12,number,#}", - tr.topics, - tr.partitions, - tr.messageSize, - tr.producersPerTopic, - tr.consumersPerTopic, - prodRateHistogram.getMinNonZeroValue(), - prodRateHistogram.getMean(), - prodRateHistogram.getStdDeviation(), - prodRateHistogram.getMaxValue(), - conRateHistogram.getMinNonZeroValue(), - conRateHistogram.getMean(), - conRateHistogram.getStdDeviation(), - conRateHistogram.getMaxValue()); + String line = + MessageFormat.format( + "{0,number,#},{1,number,#},{2,number,#},{3,number,#},{4,number,#}," + + "{5,number,#},{6,number,#},{7,number,#.##},{8,number,#}," + + "{9,number,#},{10,number,#},{11,number,#.##},{12,number,#}", + tr.topics, + tr.partitions, + tr.messageSize, + tr.producersPerTopic, + tr.consumersPerTopic, + prodRateHistogram.getMinNonZeroValue(), + prodRateHistogram.getMean(), + prodRateHistogram.getStdDeviation(), + prodRateHistogram.getMaxValue(), + conRateHistogram.getMinNonZeroValue(), + conRateHistogram.getMean(), + conRateHistogram.getStdDeviation(), + conRateHistogram.getMaxValue()); return line; - } - catch(Exception e) { + } catch (Exception e) { log.error("Error writing results csv", e); throw new RuntimeException(e); } } - - } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/TestResult.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/TestResult.java index 0a52b21c0..fc9781b4d 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/TestResult.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/TestResult.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -33,6 +29,7 @@ public class TestResult { public int consumersPerTopic; public List publishRate = new ArrayList<>(); + public List publishErrorRate = new ArrayList<>(); public List consumeRate = new ArrayList<>(); public List backlog = new ArrayList<>(); @@ -45,6 +42,15 @@ public class TestResult { public List publishLatency9999pct = new ArrayList<>(); public List publishLatencyMax = new ArrayList<>(); + public List publishDelayLatencyAvg = new ArrayList<>(); + public List publishDelayLatency50pct = new ArrayList<>(); + public List publishDelayLatency75pct = new ArrayList<>(); + public List publishDelayLatency95pct = new ArrayList<>(); + public List publishDelayLatency99pct = new ArrayList<>(); + public List publishDelayLatency999pct = new ArrayList<>(); + public List publishDelayLatency9999pct = new ArrayList<>(); + public List publishDelayLatencyMax = new ArrayList<>(); + public double aggregatedPublishLatencyAvg; public double aggregatedPublishLatency50pct; public double aggregatedPublishLatency75pct; @@ -54,8 +60,19 @@ public class TestResult { public double aggregatedPublishLatency9999pct; public double aggregatedPublishLatencyMax; + public double aggregatedPublishDelayLatencyAvg; + public long aggregatedPublishDelayLatency50pct; + public long aggregatedPublishDelayLatency75pct; + public long aggregatedPublishDelayLatency95pct; + public long aggregatedPublishDelayLatency99pct; + public long aggregatedPublishDelayLatency999pct; + public long aggregatedPublishDelayLatency9999pct; + public long aggregatedPublishDelayLatencyMax; + public Map aggregatedPublishLatencyQuantiles = new TreeMap<>(); + public Map aggregatedPublishDelayLatencyQuantiles = new TreeMap<>(); + // End to end latencies (from producer to consumer) // Latencies are expressed in milliseconds (without decimals) diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workers.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workers.java index 56c5215de..fbc16e613 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workers.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workers.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; + import java.util.ArrayList; import java.util.List; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workload.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workload.java index 32f770e87..7b877a197 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workload.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/Workload.java @@ -1,38 +1,52 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; + import io.openmessaging.benchmark.utils.distributor.KeyDistributorType; +import java.util.Map; public class Workload { public String name; - /** Number of topics to create in the test */ + /** Number of topics to create in the test. */ public int topics; - /** Number of partitions each topic will contain */ + /** Number of partitions each topic will contain. */ public int partitionsPerTopic; public KeyDistributorType keyDistributor = KeyDistributorType.NO_KEY; public int messageSize; + /** + * Message size distribution for variable-sized payloads. + * Keys are size ranges (e.g., "0-256", "256-1024", "1KB-4KB"), + * values are relative weights. + * Mutually exclusive with messageSize - if set, messageSize is ignored. + */ + public Map messageSizeDistribution; + + /** + * Returns true if this workload uses a size distribution instead of fixed size. + * + * @return true if messageSizeDistribution is configured, false otherwise + */ + public boolean usesDistribution() { + return messageSizeDistribution != null && !messageSizeDistribution.isEmpty(); + } + public boolean useRandomizedPayloads; public double randomBytesRatio; public int randomizedPayloadPoolSize; @@ -48,13 +62,25 @@ public class Workload { public int producerRate; /** - * If the consumer backlog is > 0, the generator will accumulate messages until the requested amount of storage is - * retained and then it will start the consumers to drain it. + * If the consumer backlog is > 0, the generator will accumulate messages until the requested + * amount of storage is retained and then it will start the consumers to drain it. * - * The testDurationMinutes will be overruled to allow the test to complete when the consumer has drained all the - * backlog and it's on par with the producer + *

The testDurationMinutes will be overruled to allow the test to complete when the consumer + * has drained all the backlog and it's on par with the producer */ public long consumerBacklogSizeGB = 0; + /** + * The ratio of the backlog that can remain and yet the backlog still be considered empty, and + * thus the workload can complete at the end of the configured duration. In some systems it is not + * feasible for the backlog to be drained fully and thus the workload will run indefinitely. In + * such circumstances, one may be content to achieve a partial drain such as 99% of the backlog. + * The value should be on somewhere between 0.0 and 1.0, where 1.0 indicates that the backlog + * should be fully drained, and 0.0 indicates a best effort, where the workload will complete + * after the specified time irrespective of how much of the backlog has been drained. + */ + public double backlogDrainRatio = 1.0; public int testDurationMinutes; + + public int warmupDurationMinutes = 1; } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java index 592bfa973..86a2b1a73 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/WorkloadGenerator.java @@ -1,42 +1,26 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark; -import io.openmessaging.benchmark.utils.RandomGenerator; -import java.io.IOException; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.lang.ArrayUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.util.concurrent.TimeUnit.MINUTES; import io.netty.util.concurrent.DefaultThreadFactory; import io.openmessaging.benchmark.utils.PaddingDecimalFormat; +import io.openmessaging.benchmark.utils.RandomGenerator; import io.openmessaging.benchmark.utils.Timer; import io.openmessaging.benchmark.utils.payload.FilePayloadReader; +import io.openmessaging.benchmark.utils.payload.MessageSizeDistribution; import io.openmessaging.benchmark.utils.payload.PayloadReader; import io.openmessaging.benchmark.worker.Worker; import io.openmessaging.benchmark.worker.commands.ConsumerAssignment; @@ -46,6 +30,18 @@ import io.openmessaging.benchmark.worker.commands.ProducerWorkAssignment; import io.openmessaging.benchmark.worker.commands.TopicSubscription; import io.openmessaging.benchmark.worker.commands.TopicsInfo; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class WorkloadGenerator implements AutoCloseable { @@ -53,8 +49,8 @@ public class WorkloadGenerator implements AutoCloseable { private final Workload workload; private final Worker worker; - private final ExecutorService executor = Executors - .newCachedThreadPool(new DefaultThreadFactory("messaging-benchmark")); + private final ExecutorService executor = + Executors.newCachedThreadPool(new DefaultThreadFactory("messaging-benchmark")); private volatile boolean runCompleted = false; private volatile boolean needToWaitForBacklogDraining = false; @@ -67,13 +63,15 @@ public WorkloadGenerator(String driverName, Workload workload, Worker worker) { this.worker = worker; if (workload.consumerBacklogSizeGB > 0 && workload.producerRate == 0) { - throw new IllegalArgumentException("Cannot probe producer sustainable rate when building backlog"); + throw new IllegalArgumentException( + "Cannot probe producer sustainable rate when building backlog"); } } public TestResult run() throws Exception { Timer timer = new Timer(); - List topics = worker.createTopics(new TopicsInfo(workload.topics, workload.partitionsPerTopic)); + List topics = + worker.createTopics(new TopicsInfo(workload.topics, workload.partitionsPerTopic)); log.info("Created {} topics in {} ms", topics.size(), timer.elapsedMillis()); createConsumers(topics); @@ -87,60 +85,86 @@ public TestResult run() throws Exception { // Producer rate is 0 and we need to discover the sustainable rate targetPublishRate = 10000; - executor.execute(() -> { - // Run background controller to adjust rate - try { - findMaximumSustainableRate(targetPublishRate); - } catch (IOException e) { - log.warn("Failure in finding max sustainable rate", e); - } - }); + executor.execute( + () -> { + // Run background controller to adjust rate + try { + findMaximumSustainableRate(targetPublishRate); + } catch (IOException e) { + log.warn("Failure in finding max sustainable rate", e); + } + }); } - final PayloadReader payloadReader = new FilePayloadReader(workload.messageSize); - ProducerWorkAssignment producerWorkAssignment = new ProducerWorkAssignment(); producerWorkAssignment.keyDistributorType = workload.keyDistributor; producerWorkAssignment.publishRate = targetPublishRate; producerWorkAssignment.payloadData = new ArrayList<>(); - if(workload.useRandomizedPayloads) { - // create messages that are part random and part zeros - // better for testing effects of compression + if (workload.usesDistribution()) { + // Distribution mode: create one payload per bucket with weighted selection at runtime + MessageSizeDistribution dist = new MessageSizeDistribution(workload.messageSizeDistribution); + List sizes = dist.getBucketMaxSizes(); + Random r = new Random(); + + log.info( + "Creating {} payloads for size distribution (max sizes: {}, weighted avg: {} bytes)", + sizes.size(), + sizes, + dist.getAvgSize()); + + for (int size : sizes) { + byte[] payload = new byte[size]; + if (workload.useRandomizedPayloads) { + int randomBytes = (int) (size * workload.randomBytesRatio); + r.nextBytes(payload); + // Zero out non-random portion for compressibility testing + for (int j = randomBytes; j < size; j++) { + payload[j] = 0; + } + } + producerWorkAssignment.payloadData.add(payload); + } + producerWorkAssignment.payloadWeights = dist.getWeights(); + + } else if (workload.useRandomizedPayloads) { + // Existing fixed-size randomized payload logic Random r = new Random(); - int randomBytes = (int)(workload.messageSize * workload.randomBytesRatio); + int randomBytes = (int) (workload.messageSize * workload.randomBytesRatio); int zerodBytes = workload.messageSize - randomBytes; - for(int i = 0; i 0) { + log.info("----- Starting warm-up traffic ({}m) ------", workload.warmupDurationMinutes); + printAndCollectStats(workload.warmupDurationMinutes, TimeUnit.MINUTES); + } if (workload.consumerBacklogSizeGB > 0) { - executor.execute(() -> { - try { - buildAndDrainBacklog(topics); - } catch (IOException e) { - e.printStackTrace(); - } - }); + executor.execute( + () -> { + try { + buildAndDrainBacklog(workload.testDurationMinutes); + } catch (IOException e) { + e.printStackTrace(); + } + }); } worker.resetStats(); - log.info("----- Starting benchmark traffic ------"); + log.info("----- Starting benchmark traffic ({}m)------", workload.testDurationMinutes); TestResult result = printAndCollectStats(workload.testDurationMinutes, TimeUnit.MINUTES); runCompleted = true; @@ -151,7 +175,8 @@ public TestResult run() throws Exception { private void ensureTopicsAreReady() throws IOException { log.info("Waiting for consumers to be ready"); - // This is work around the fact that there's no way to have a consumer ready in Kafka without first publishing + // This is work around the fact that there's no way to have a consumer ready in Kafka without + // first publishing // some message on the topic, which will then trigger the partitions assignment to the consumers int expectedMessages = workload.topics * workload.subscriptionsPerTopic; @@ -159,12 +184,18 @@ private void ensureTopicsAreReady() throws IOException { // In this case we just publish 1 message and then wait for consumers to receive the data worker.probeProducers(); - while (true) { + long start = System.currentTimeMillis(); + long end = start + 60 * 1000; + while (System.currentTimeMillis() < end) { CountersStats stats = worker.getCountersStats(); - + + log.info( + "Waiting for topics to be ready -- Sent: {}, Received: {}", + stats.messagesSent, + stats.messagesReceived); if (stats.messagesReceived < expectedMessages) { try { - Thread.sleep(100); + Thread.sleep(2_000); } catch (InterruptedException e) { throw new RuntimeException(e); } @@ -173,26 +204,26 @@ private void ensureTopicsAreReady() throws IOException { } } - log.info("All consumers are ready"); + if (System.currentTimeMillis() >= end) { + throw new RuntimeException("Timed out waiting for consumers to be ready"); + } else { + log.info("All consumers are ready"); + } } /** - * Adjust the publish rate to a level that is sustainable, meaning that we can consume all the messages that are - * being produced + * Adjust the publish rate to a level that is sustainable, meaning that we can consume all the + * messages that are being produced. + * + * @param currentRate */ private void findMaximumSustainableRate(double currentRate) throws IOException { - double maxRate = Double.MAX_VALUE; // Discovered max sustainable rate - double minRate = 0.1; - CountersStats stats = worker.getCountersStats(); - long localTotalMessagesSentCounter = stats.messagesSent; - long localTotalMessagesReceivedCounter = stats.messagesReceived; - int controlPeriodMillis = 3000; long lastControlTimestamp = System.nanoTime(); - int successfulPeriods = 0; + RateController rateController = new RateController(); while (!runCompleted) { // Check every few seconds and adjust the rate @@ -205,84 +236,13 @@ private void findMaximumSustainableRate(double currentRate) throws IOException { // Consider multiple copies when using multiple subscriptions stats = worker.getCountersStats(); long currentTime = System.nanoTime(); - long totalMessagesSent = stats.messagesSent; - long totalMessagesReceived = stats.messagesReceived; - long messagesPublishedInPeriod = totalMessagesSent - localTotalMessagesSentCounter; - long messagesReceivedInPeriod = totalMessagesReceived - localTotalMessagesReceivedCounter; - double publishRateInLastPeriod = messagesPublishedInPeriod / (double) (currentTime - lastControlTimestamp) - * TimeUnit.SECONDS.toNanos(1); - double receiveRateInLastPeriod = messagesReceivedInPeriod / (double) (currentTime - lastControlTimestamp) - * TimeUnit.SECONDS.toNanos(1); - - if (log.isDebugEnabled()) { - log.debug( - "total-send: {} -- total-received: {} -- int-sent: {} -- int-received: {} -- sent-rate: {} -- received-rate: {}", - totalMessagesSent, totalMessagesReceived, messagesPublishedInPeriod, messagesReceivedInPeriod, - publishRateInLastPeriod, receiveRateInLastPeriod); - } + long periodNanos = currentTime - lastControlTimestamp; - localTotalMessagesSentCounter = totalMessagesSent; - localTotalMessagesReceivedCounter = totalMessagesReceived; lastControlTimestamp = currentTime; - if (log.isDebugEnabled()) { - log.debug("Current rate: {} -- Publish rate {} -- Consume Rate: {} -- min-rate: {} -- max-rate: {}", - dec.format(currentRate), dec.format(publishRateInLastPeriod), - dec.format(receiveRateInLastPeriod), dec.format(minRate), dec.format(maxRate)); - } - - if (publishRateInLastPeriod < currentRate * 0.95) { - // Producer is not able to publish as fast as requested - maxRate = currentRate * 1.1; - currentRate = minRate + (currentRate - minRate) / 2; - - log.debug("Publishers are not meeting requested rate. reducing to {}", currentRate); - } else if (receiveRateInLastPeriod < publishRateInLastPeriod * 0.98) { - // If the consumers are building backlog, we should slow down publish rate - maxRate = currentRate; - currentRate = minRate + (currentRate - minRate) / 2; - log.debug("Consumers are not meeting requested rate. reducing to {}", currentRate); - - // Slows the publishes to let the consumer time to absorb the backlog - worker.adjustPublishRate(minRate / 10); - while (true) { - stats = worker.getCountersStats(); - long backlog = workload.subscriptionsPerTopic * stats.messagesSent - stats.messagesReceived; - if (backlog < 1000) { - break; - } - - try { - Thread.sleep(100); - } catch (InterruptedException e) { - return; - } - } - - log.debug("Resuming load at reduced rate"); - worker.adjustPublishRate(currentRate); - - try { - // Wait some more time for the publish rate to catch up - Thread.sleep(500); - } catch (InterruptedException e) { - return; - } - - stats = worker.getCountersStats(); - localTotalMessagesSentCounter = stats.messagesSent; - localTotalMessagesReceivedCounter = stats.messagesReceived; - - } else if (currentRate < maxRate) { - minRate = currentRate; - currentRate = Math.min(currentRate * 2, maxRate); - log.debug("No bottleneck found, increasing the rate to {}", currentRate); - } else if (++successfulPeriods > 3) { - minRate = currentRate * 0.95; - maxRate = currentRate * 1.05; - successfulPeriods = 0; - } - + currentRate = + rateController.nextRate( + currentRate, periodNanos, stats.messagesSent, stats.messagesReceived); worker.adjustPublishRate(currentRate); } } @@ -296,12 +256,13 @@ public void close() throws Exception { private void createConsumers(List topics) throws IOException { ConsumerAssignment consumerAssignment = new ConsumerAssignment(); - for(String topic: topics){ - for(int i = 0; i < workload.subscriptionsPerTopic; i++){ - String subscriptionName = String.format("sub-%03d-%s", i, RandomGenerator.getRandomString()); + for (String topic : topics) { + for (int i = 0; i < workload.subscriptionsPerTopic; i++) { + String subscriptionName = + String.format("sub-%03d-%s", i, RandomGenerator.getRandomString()); for (int j = 0; j < workload.consumerPerSubscription; j++) { - consumerAssignment.topicsSubscriptions - .add(new TopicSubscription(topic, subscriptionName)); + consumerAssignment.topicsSubscriptions.add( + new TopicSubscription(topic, subscriptionName)); } } } @@ -311,7 +272,10 @@ private void createConsumers(List topics) throws IOException { Timer timer = new Timer(); worker.createConsumers(consumerAssignment); - log.info("Created {} consumers in {} ms", consumerAssignment.topicsSubscriptions.size(), timer.elapsedMillis()); + log.info( + "Created {} consumers in {} ms", + consumerAssignment.topicsSubscriptions.size(), + timer.elapsedMillis()); } private void createProducers(List topics) throws IOException { @@ -319,7 +283,7 @@ private void createProducers(List topics) throws IOException { // Add the topic multiple times, one for each producer for (int i = 0; i < workload.producersPerTopic; i++) { - topics.forEach(fullListOfTopics::add); + fullListOfTopics.addAll(topics); } Collections.shuffle(fullListOfTopics); @@ -330,18 +294,26 @@ private void createProducers(List topics) throws IOException { log.info("Created {} producers in {} ms", fullListOfTopics.size(), timer.elapsedMillis()); } - private void buildAndDrainBacklog(List topics) throws IOException { + private void buildAndDrainBacklog(int testDurationMinutes) throws IOException { + Timer timer = new Timer(); log.info("Stopping all consumers to build backlog"); worker.pauseConsumers(); this.needToWaitForBacklogDraining = true; + // Use average size when distribution is configured, otherwise fixed messageSize + int effectiveMessageSize = + workload.usesDistribution() + ? new MessageSizeDistribution(workload.messageSizeDistribution).getAvgSize() + : workload.messageSize; + long requestedBacklogSize = workload.consumerBacklogSizeGB * 1024 * 1024 * 1024; while (true) { CountersStats stats = worker.getCountersStats(); - long currentBacklogSize = (workload.subscriptionsPerTopic * stats.messagesSent - stats.messagesReceived) - * workload.messageSize; + long currentBacklogSize = + (workload.subscriptionsPerTopic * stats.messagesSent - stats.messagesReceived) + * effectiveMessageSize; if (currentBacklogSize >= requestedBacklogSize) { break; @@ -354,17 +326,29 @@ private void buildAndDrainBacklog(List topics) throws IOException { } } + log.info("--- Completed backlog build in {} s ---", timer.elapsedSeconds()); + timer = new Timer(); log.info("--- Start draining backlog ---"); worker.resumeConsumers(); - final long minBacklog = 1000; + long backlogMessageCapacity = requestedBacklogSize / effectiveMessageSize; + long backlogEmptyLevel = (long) ((1.0 - workload.backlogDrainRatio) * backlogMessageCapacity); + final long minBacklog = Math.max(1000L, backlogEmptyLevel); while (true) { CountersStats stats = worker.getCountersStats(); - long currentBacklog = workload.subscriptionsPerTopic * stats.messagesSent - stats.messagesReceived; + long currentBacklog = + workload.subscriptionsPerTopic * stats.messagesSent - stats.messagesReceived; if (currentBacklog <= minBacklog) { - log.info("--- Completed backlog draining ---"); + log.info("--- Completed backlog draining in {} s ---", timer.elapsedSeconds()); + + try { + Thread.sleep(MINUTES.toMillis(testDurationMinutes)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + needToWaitForBacklogDraining = false; return; } @@ -377,6 +361,7 @@ private void buildAndDrainBacklog(List topics) throws IOException { } } + @SuppressWarnings({"checkstyle:LineLength", "checkstyle:MethodLength"}) private TestResult printAndCollectStats(long testDurations, TimeUnit unit) throws IOException { long startTime = System.nanoTime(); @@ -390,7 +375,11 @@ private TestResult printAndCollectStats(long testDurations, TimeUnit unit) throw result.driver = driverName; result.topics = workload.topics; result.partitions = workload.partitionsPerTopic; - result.messageSize = workload.messageSize; + // Use average size when distribution is configured + result.messageSize = + workload.usesDistribution() + ? new MessageSizeDistribution(workload.messageSizeDistribution).getAvgSize() + : workload.messageSize; result.producersPerTopic = workload.producersPerTopic; result.consumersPerTopic = workload.consumerPerSubscription; @@ -408,25 +397,38 @@ private TestResult printAndCollectStats(long testDurations, TimeUnit unit) throw double publishRate = stats.messagesSent / elapsed; double publishThroughput = stats.bytesSent / elapsed / 1024 / 1024; + double errorRate = stats.messageSendErrors / elapsed; double consumeRate = stats.messagesReceived / elapsed; double consumeThroughput = stats.bytesReceived / elapsed / 1024 / 1024; - long currentBacklog = workload.subscriptionsPerTopic * stats.totalMessagesSent - - stats.totalMessagesReceived; + long currentBacklog = + Math.max( + 0L, + workload.subscriptionsPerTopic * stats.totalMessagesSent + - stats.totalMessagesReceived); log.info( - "Pub rate {} msg/s / {} MB/s | Cons rate {} msg/s / {} MB/s | Backlog: {} K | Pub Latency (ms) avg: {} - 50%: {} - 99%: {} - 99.9%: {} - Max: {}", - rateFormat.format(publishRate), throughputFormat.format(publishThroughput), - rateFormat.format(consumeRate), throughputFormat.format(consumeThroughput), + "Pub rate {} msg/s / {} MB/s | Pub err {} err/s | Cons rate {} msg/s / {} MB/s | Backlog: {} K | Pub Latency (ms) avg: {} - 50%: {} - 99%: {} - 99.9%: {} - Max: {} | Pub Delay Latency (us) avg: {} - 50%: {} - 99%: {} - 99.9%: {} - Max: {}", + rateFormat.format(publishRate), + throughputFormat.format(publishThroughput), + rateFormat.format(errorRate), + rateFormat.format(consumeRate), + throughputFormat.format(consumeThroughput), dec.format(currentBacklog / 1000.0), // dec.format(microsToMillis(stats.publishLatency.getMean())), dec.format(microsToMillis(stats.publishLatency.getValueAtPercentile(50))), dec.format(microsToMillis(stats.publishLatency.getValueAtPercentile(99))), dec.format(microsToMillis(stats.publishLatency.getValueAtPercentile(99.9))), - throughputFormat.format(microsToMillis(stats.publishLatency.getMaxValue()))); + throughputFormat.format(microsToMillis(stats.publishLatency.getMaxValue())), + dec.format(stats.publishDelayLatency.getMean()), + dec.format(stats.publishDelayLatency.getValueAtPercentile(50)), + dec.format(stats.publishDelayLatency.getValueAtPercentile(99)), + dec.format(stats.publishDelayLatency.getValueAtPercentile(99.9)), + throughputFormat.format(stats.publishDelayLatency.getMaxValue())); result.publishRate.add(publishRate); + result.publishErrorRate.add(errorRate); result.consumeRate.add(consumeRate); result.backlog.add(currentBacklog); result.publishLatencyAvg.add(microsToMillis(stats.publishLatency.getMean())); @@ -434,58 +436,119 @@ private TestResult printAndCollectStats(long testDurations, TimeUnit unit) throw result.publishLatency75pct.add(microsToMillis(stats.publishLatency.getValueAtPercentile(75))); result.publishLatency95pct.add(microsToMillis(stats.publishLatency.getValueAtPercentile(95))); result.publishLatency99pct.add(microsToMillis(stats.publishLatency.getValueAtPercentile(99))); - result.publishLatency999pct.add(microsToMillis(stats.publishLatency.getValueAtPercentile(99.9))); - result.publishLatency9999pct.add(microsToMillis(stats.publishLatency.getValueAtPercentile(99.99))); + result.publishLatency999pct.add( + microsToMillis(stats.publishLatency.getValueAtPercentile(99.9))); + result.publishLatency9999pct.add( + microsToMillis(stats.publishLatency.getValueAtPercentile(99.99))); result.publishLatencyMax.add(microsToMillis(stats.publishLatency.getMaxValue())); + result.publishDelayLatencyAvg.add(stats.publishDelayLatency.getMean()); + result.publishDelayLatency50pct.add(stats.publishDelayLatency.getValueAtPercentile(50)); + result.publishDelayLatency75pct.add(stats.publishDelayLatency.getValueAtPercentile(75)); + result.publishDelayLatency95pct.add(stats.publishDelayLatency.getValueAtPercentile(95)); + result.publishDelayLatency99pct.add(stats.publishDelayLatency.getValueAtPercentile(99)); + result.publishDelayLatency999pct.add(stats.publishDelayLatency.getValueAtPercentile(99.9)); + result.publishDelayLatency9999pct.add(stats.publishDelayLatency.getValueAtPercentile(99.99)); + result.publishDelayLatencyMax.add(stats.publishDelayLatency.getMaxValue()); + result.endToEndLatencyAvg.add(microsToMillis(stats.endToEndLatency.getMean())); - result.endToEndLatency50pct.add(microsToMillis(stats.endToEndLatency.getValueAtPercentile(50))); - result.endToEndLatency75pct.add(microsToMillis(stats.endToEndLatency.getValueAtPercentile(75))); - result.endToEndLatency95pct.add(microsToMillis(stats.endToEndLatency.getValueAtPercentile(95))); - result.endToEndLatency99pct.add(microsToMillis(stats.endToEndLatency.getValueAtPercentile(99))); - result.endToEndLatency999pct.add(microsToMillis(stats.endToEndLatency.getValueAtPercentile(99.9))); - result.endToEndLatency9999pct.add(microsToMillis(stats.endToEndLatency.getValueAtPercentile(99.99))); + result.endToEndLatency50pct.add( + microsToMillis(stats.endToEndLatency.getValueAtPercentile(50))); + result.endToEndLatency75pct.add( + microsToMillis(stats.endToEndLatency.getValueAtPercentile(75))); + result.endToEndLatency95pct.add( + microsToMillis(stats.endToEndLatency.getValueAtPercentile(95))); + result.endToEndLatency99pct.add( + microsToMillis(stats.endToEndLatency.getValueAtPercentile(99))); + result.endToEndLatency999pct.add( + microsToMillis(stats.endToEndLatency.getValueAtPercentile(99.9))); + result.endToEndLatency9999pct.add( + microsToMillis(stats.endToEndLatency.getValueAtPercentile(99.99))); result.endToEndLatencyMax.add(microsToMillis(stats.endToEndLatency.getMaxValue())); if (now >= testEndTime && !needToWaitForBacklogDraining) { CumulativeLatencies agg = worker.getCumulativeLatencies(); log.info( - "----- Aggregated Pub Latency (ms) avg: {} - 50%: {} - 95%: {} - 99%: {} - 99.9%: {} - 99.99%: {} - Max: {}", + "----- Aggregated Pub Latency (ms) avg: {} - 50%: {} - 95%: {} - 99%: {} - 99.9%: {} - 99.99%: {} - Max: {} | Pub Delay (us) avg: {} - 50%: {} - 95%: {} - 99%: {} - 99.9%: {} - 99.99%: {} - Max: {}", dec.format(agg.publishLatency.getMean() / 1000.0), dec.format(agg.publishLatency.getValueAtPercentile(50) / 1000.0), dec.format(agg.publishLatency.getValueAtPercentile(95) / 1000.0), dec.format(agg.publishLatency.getValueAtPercentile(99) / 1000.0), dec.format(agg.publishLatency.getValueAtPercentile(99.9) / 1000.0), dec.format(agg.publishLatency.getValueAtPercentile(99.99) / 1000.0), - throughputFormat.format(agg.publishLatency.getMaxValue() / 1000.0)); + throughputFormat.format(agg.publishLatency.getMaxValue() / 1000.0), + dec.format(agg.publishDelayLatency.getMean()), + dec.format(agg.publishDelayLatency.getValueAtPercentile(50)), + dec.format(agg.publishDelayLatency.getValueAtPercentile(95)), + dec.format(agg.publishDelayLatency.getValueAtPercentile(99)), + dec.format(agg.publishDelayLatency.getValueAtPercentile(99.9)), + dec.format(agg.publishDelayLatency.getValueAtPercentile(99.99)), + throughputFormat.format(agg.publishDelayLatency.getMaxValue())); result.aggregatedPublishLatencyAvg = agg.publishLatency.getMean() / 1000.0; result.aggregatedPublishLatency50pct = agg.publishLatency.getValueAtPercentile(50) / 1000.0; result.aggregatedPublishLatency75pct = agg.publishLatency.getValueAtPercentile(75) / 1000.0; result.aggregatedPublishLatency95pct = agg.publishLatency.getValueAtPercentile(95) / 1000.0; result.aggregatedPublishLatency99pct = agg.publishLatency.getValueAtPercentile(99) / 1000.0; - result.aggregatedPublishLatency999pct = agg.publishLatency.getValueAtPercentile(99.9) / 1000.0; - result.aggregatedPublishLatency9999pct = agg.publishLatency.getValueAtPercentile(99.99) / 1000.0; + result.aggregatedPublishLatency999pct = + agg.publishLatency.getValueAtPercentile(99.9) / 1000.0; + result.aggregatedPublishLatency9999pct = + agg.publishLatency.getValueAtPercentile(99.99) / 1000.0; result.aggregatedPublishLatencyMax = agg.publishLatency.getMaxValue() / 1000.0; - result.aggregatedEndToEndLatencyAvg = agg.endToEndLatency.getMean() / 1000.0; - result.aggregatedEndToEndLatency50pct = agg.endToEndLatency.getValueAtPercentile(50) / 1000.0; - result.aggregatedEndToEndLatency75pct = agg.endToEndLatency.getValueAtPercentile(75) / 1000.0; - result.aggregatedEndToEndLatency95pct = agg.endToEndLatency.getValueAtPercentile(95) / 1000.0; - result.aggregatedEndToEndLatency99pct = agg.endToEndLatency.getValueAtPercentile(99) / 1000.0; - result.aggregatedEndToEndLatency999pct = agg.endToEndLatency.getValueAtPercentile(99.9) / 1000.0; - result.aggregatedEndToEndLatency9999pct = agg.endToEndLatency.getValueAtPercentile(99.99) / 1000.0; - result.aggregatedEndToEndLatencyMax = agg.endToEndLatency.getMaxValue() / 1000.0; - - agg.publishLatency.percentiles(100).forEach(value -> { - result.aggregatedPublishLatencyQuantiles.put(value.getPercentile(), - value.getValueIteratedTo() / 1000.0); - }); - - agg.endToEndLatency.percentiles(100).forEach(value -> { - result.aggregatedEndToEndLatencyQuantiles.put(value.getPercentile(), - microsToMillis(value.getValueIteratedTo())); - }); + result.aggregatedPublishDelayLatencyAvg = agg.publishDelayLatency.getMean(); + result.aggregatedPublishDelayLatency50pct = + agg.publishDelayLatency.getValueAtPercentile(50); + result.aggregatedPublishDelayLatency75pct = + agg.publishDelayLatency.getValueAtPercentile(75); + result.aggregatedPublishDelayLatency95pct = + agg.publishDelayLatency.getValueAtPercentile(95); + result.aggregatedPublishDelayLatency99pct = + agg.publishDelayLatency.getValueAtPercentile(99); + result.aggregatedPublishDelayLatency999pct = + agg.publishDelayLatency.getValueAtPercentile(99.9); + result.aggregatedPublishDelayLatency9999pct = + agg.publishDelayLatency.getValueAtPercentile(99.99); + result.aggregatedPublishDelayLatencyMax = agg.publishDelayLatency.getMaxValue(); + + result.aggregatedEndToEndLatencyAvg = agg.endToEndLatency.getMean() / 1000.0; + result.aggregatedEndToEndLatency50pct = + agg.endToEndLatency.getValueAtPercentile(50) / 1000.0; + result.aggregatedEndToEndLatency75pct = + agg.endToEndLatency.getValueAtPercentile(75) / 1000.0; + result.aggregatedEndToEndLatency95pct = + agg.endToEndLatency.getValueAtPercentile(95) / 1000.0; + result.aggregatedEndToEndLatency99pct = + agg.endToEndLatency.getValueAtPercentile(99) / 1000.0; + result.aggregatedEndToEndLatency999pct = + agg.endToEndLatency.getValueAtPercentile(99.9) / 1000.0; + result.aggregatedEndToEndLatency9999pct = + agg.endToEndLatency.getValueAtPercentile(99.99) / 1000.0; + result.aggregatedEndToEndLatencyMax = agg.endToEndLatency.getMaxValue() / 1000.0; + + agg.publishLatency + .percentiles(100) + .forEach( + value -> { + result.aggregatedPublishLatencyQuantiles.put( + value.getPercentile(), value.getValueIteratedTo() / 1000.0); + }); + + agg.publishDelayLatency + .percentiles(100) + .forEach( + value -> { + result.aggregatedPublishDelayLatencyQuantiles.put( + value.getPercentile(), value.getValueIteratedTo()); + }); + + agg.endToEndLatency + .percentiles(100) + .forEach( + value -> { + result.aggregatedEndToEndLatencyQuantiles.put( + value.getPercentile(), microsToMillis(value.getValueIteratedTo())); + }); break; } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Env.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Env.java new file mode 100644 index 000000000..366b2ca12 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Env.java @@ -0,0 +1,34 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + + +import java.util.Optional; +import java.util.function.Function; + +public final class Env { + private Env() {} + + public static long getLong(String key, long defaultValue) { + return get(key, Long::parseLong, defaultValue); + } + + public static double getDouble(String key, double defaultValue) { + return get(key, Double::parseDouble, defaultValue); + } + + public static T get(String key, Function function, T defaultValue) { + return Optional.ofNullable(System.getenv(key)).map(function).orElse(defaultValue); + } +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/ListPartition.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/ListPartition.java index 37b679e37..01a1ae51e 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/ListPartition.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/ListPartition.java @@ -1,35 +1,31 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils; + import java.util.ArrayList; import java.util.List; public class ListPartition { /** - * partition a list to specified size + * partition a list to specified size. * * @param originList * @param size * @param - * @return + * @return the partitioned list */ public static List> partitionList(List originList, int size) { @@ -60,5 +56,4 @@ public static List> partitionList(List originList, int size) { } return resultList; } - } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/PaddingDecimalFormat.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/PaddingDecimalFormat.java index 5fef088d1..a598ddb2a 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/PaddingDecimalFormat.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/PaddingDecimalFormat.java @@ -1,24 +1,19 @@ - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils; + import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.FieldPosition; @@ -28,8 +23,11 @@ public class PaddingDecimalFormat extends DecimalFormat { private int minimumLength; /** - * Creates a PaddingDecimalFormat using the given pattern and minimum minimumLength and the symbols for the default - * locale. + * Creates a PaddingDecimalFormat using the given pattern and minimum minimumLength and the + * symbols for the default locale. + * + * @param pattern + * @param minLength */ public PaddingDecimalFormat(String pattern, int minLength) { super(pattern); @@ -38,6 +36,10 @@ public PaddingDecimalFormat(String pattern, int minLength) { /** * Creates a PaddingDecimalFormat using the given pattern, symbols and minimum minimumLength. + * + * @param pattern + * @param symbols + * @param minLength */ public PaddingDecimalFormat(String pattern, DecimalFormatSymbols symbols, int minLength) { super(pattern, symbols); diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/RandomGenerator.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/RandomGenerator.java index 563377f19..13c4f501c 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/RandomGenerator.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/RandomGenerator.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils; + import com.google.common.io.BaseEncoding; import java.util.Random; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Timer.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Timer.java index 533ca92e6..bb3ac28c0 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Timer.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/Timer.java @@ -1,34 +1,45 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils; + import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; public class Timer { private final long startTime; + private final Supplier nanoClock; + + Timer(Supplier nanoClock) { + this.nanoClock = nanoClock; + startTime = this.nanoClock.get(); + } public Timer() { - startTime = System.nanoTime(); + this(System::nanoTime); } public double elapsedMillis() { - long now = System.nanoTime(); - return (now - startTime) / (double) TimeUnit.MILLISECONDS.toNanos(1); + return elapsed(TimeUnit.MILLISECONDS); + } + + public double elapsedSeconds() { + return elapsed(TimeUnit.SECONDS); + } + + private double elapsed(TimeUnit unit) { + long now = nanoClock.get(); + return (now - startTime) / (double) unit.toNanos(1); } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/UniformRateLimiter.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/UniformRateLimiter.java new file mode 100644 index 000000000..1fc69b15c --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/UniformRateLimiter.java @@ -0,0 +1,82 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.locks.LockSupport; +import java.util.function.Supplier; + +/** + * Provides a next operation time for rate limited operation streams.
+ * The rate limiter is thread safe and can be shared by all threads. + */ +public final class UniformRateLimiter { + + private static final AtomicLongFieldUpdater V_TIME_UPDATER = + AtomicLongFieldUpdater.newUpdater(UniformRateLimiter.class, "virtualTime"); + private static final AtomicLongFieldUpdater START_UPDATER = + AtomicLongFieldUpdater.newUpdater(UniformRateLimiter.class, "start"); + private static final double ONE_SEC_IN_NS = SECONDS.toNanos(1); + private volatile long start = Long.MIN_VALUE; + private volatile long virtualTime; + private final double opsPerSec; + private final long intervalNs; + private final Supplier nanoClock; + + UniformRateLimiter(final double opsPerSec, Supplier nanoClock) { + if (Double.isNaN(opsPerSec) || Double.isInfinite(opsPerSec)) { + throw new IllegalArgumentException("opsPerSec cannot be Nan or Infinite"); + } + if (opsPerSec <= 0) { + throw new IllegalArgumentException("opsPerSec must be greater then 0"); + } + this.opsPerSec = opsPerSec; + intervalNs = Math.round(ONE_SEC_IN_NS / opsPerSec); + this.nanoClock = nanoClock; + } + + public UniformRateLimiter(final double opsPerSec) { + this(opsPerSec, System::nanoTime); + } + + public double getOpsPerSec() { + return opsPerSec; + } + + public long getIntervalNs() { + return intervalNs; + } + + public long acquire() { + final long currOpIndex = V_TIME_UPDATER.getAndIncrement(this); + long start = this.start; + if (start == Long.MIN_VALUE) { + start = nanoClock.get(); + if (!START_UPDATER.compareAndSet(this, Long.MIN_VALUE, start)) { + start = this.start; + assert start != Long.MIN_VALUE; + } + } + return start + currOpIndex * intervalNs; + } + + public static void uninterruptibleSleepNs(final long intendedTime) { + long sleepNs; + while ((sleepNs = (intendedTime - System.nanoTime())) > 0) { + LockSupport.parkNanos(sleepNs); + } + } +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributor.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributor.java index a56fc9621..14576c985 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributor.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributor.java @@ -1,25 +1,33 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.distributor; -import com.google.common.io.BaseEncoding; +import com.google.common.io.BaseEncoding; import java.util.Random; public abstract class KeyDistributor { @@ -28,11 +36,11 @@ public abstract class KeyDistributor { private static final int KEY_BYTE_SIZE = 7; private static final String[] randomKeys = new String[UNIQUE_COUNT]; - private static final Random random = new Random(); static { // Generate a number of random keys to be used when publishing byte[] buffer = new byte[KEY_BYTE_SIZE]; + Random random = new Random(); for (int i = 0; i < randomKeys.length; i++) { random.nextBytes(buffer); randomKeys[i] = BaseEncoding.base64Url().omitPadding().encode(buffer); @@ -61,8 +69,9 @@ public static KeyDistributor build(KeyDistributorType keyType) { case RANDOM_NANO: keyDistributor = new RandomNano(); break; + default: + throw new IllegalStateException("Unexpected KeyDistributorType: " + keyType); } return keyDistributor; } - } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributorType.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributorType.java index db953a3c0..3cb1cf1c0 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributorType.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyDistributorType.java @@ -1,39 +1,42 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.distributor; + import com.fasterxml.jackson.annotation.JsonEnumDefaultValue; public enum KeyDistributorType { + /** Key distributor that returns null keys to have default publish semantics. */ @JsonEnumDefaultValue - /** - * Key distributor that returns null keys to have default publish semantics - */ NO_KEY, - /** - * Genarate a finite number of "keys" and cycle through them in round-robin fashion - */ + /** Genarate a finite number of "keys" and cycle through them in round-robin fashion. */ KEY_ROUND_ROBIN, - /** - * Random distribution based on System.nanoTime() - */ + /** Random distribution based on System.nanoTime(). */ RANDOM_NANO, } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyRoundRobin.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyRoundRobin.java index 749e3e864..bb600e2ca 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyRoundRobin.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/KeyRoundRobin.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.distributor; + import javax.annotation.concurrent.NotThreadSafe; @NotThreadSafe diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/NoKeyDistributor.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/NoKeyDistributor.java index d9c8d29ac..593f0e5d4 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/NoKeyDistributor.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/NoKeyDistributor.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.distributor; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/RandomNano.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/RandomNano.java index 5cc1c8f61..cedbf1b1a 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/RandomNano.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/distributor/RandomNano.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.distributor; + import javax.annotation.concurrent.ThreadSafe; @ThreadSafe diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/FilePayloadReader.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/FilePayloadReader.java index c9a02c35d..2fe60e052 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/FilePayloadReader.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/FilePayloadReader.java @@ -1,29 +1,24 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.payload; +import static java.nio.file.Files.readAllBytes; + import java.io.File; import java.io.IOException; import java.text.MessageFormat; -import static java.nio.file.Files.readAllBytes; - public class FilePayloadReader implements PayloadReader { private final int expectedLength; @@ -46,8 +41,10 @@ public byte[] load(String resourceName) { private void checkPayloadLength(byte[] payload) { if (expectedLength != payload.length) { - throw new PayloadException(MessageFormat.format("Payload length mismatch. Actual is: {0}, but expected: {1} ", - payload.length, expectedLength)); + throw new PayloadException( + MessageFormat.format( + "Payload length mismatch. Actual is: {0}, but expected: {1} ", + payload.length, expectedLength)); } } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/MessageSizeDistribution.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/MessageSizeDistribution.java new file mode 100644 index 000000000..56355e4b6 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/MessageSizeDistribution.java @@ -0,0 +1,220 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils.payload; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Parses and represents a message size distribution from workload config. + * Creates one payload size per bucket and provides weights for runtime selection. + * + *

Example configuration: + *

+ * messageSizeDistribution:
+ *   "0-256": 234
+ *   "256-1024": 456
+ *   "1024-4096": 678
+ * 
+ */ +public class MessageSizeDistribution { + + private final List buckets; + private final int totalWeight; + + /** + * Represents a single size bucket with min/max range and weight. + */ + public static class Bucket { + public final int minSize; + public final int maxSize; + public final int weight; + + Bucket(int minSize, int maxSize, int weight) { + this.minSize = minSize; + this.maxSize = maxSize; + this.weight = weight; + } + + /** + * Returns midpoint of range as the representative size for this bucket. + * + * @return the representative size (midpoint of min and max) + */ + public int getRepresentativeSize() { + return (minSize + maxSize) / 2; + } + } + + public MessageSizeDistribution(Map config) { + if (config == null || config.isEmpty()) { + throw new IllegalArgumentException("Distribution config cannot be null or empty"); + } + + List parsed = new ArrayList<>(); + int total = 0; + + for (Map.Entry e : config.entrySet()) { + int[] range = parseRange(e.getKey()); + int weight = e.getValue(); + if (weight < 0) { + throw new IllegalArgumentException("Weight cannot be negative: " + weight); + } + parsed.add(new Bucket(range[0], range[1], weight)); + total += weight; + } + + this.buckets = parsed; + this.totalWeight = total; + + if (totalWeight <= 0) { + throw new IllegalArgumentException("Distribution weights must sum to a positive value"); + } + } + + private int[] parseRange(String range) { + if (range == null || range.isEmpty()) { + throw new IllegalArgumentException("Range cannot be null or empty"); + } + + // Find the last hyphen that separates min and max (to handle negative numbers if any) + int lastHyphen = range.lastIndexOf('-'); + if (lastHyphen <= 0) { + throw new IllegalArgumentException("Invalid range format (expected 'min-max'): " + range); + } + + String minPart = range.substring(0, lastHyphen); + String maxPart = range.substring(lastHyphen + 1); + + int minSize = parseSize(minPart); + int maxSize = parseSize(maxPart); + + if (minSize < 0) { + throw new IllegalArgumentException("Min size cannot be negative: " + minSize); + } + if (maxSize < minSize) { + throw new IllegalArgumentException( + "Max size must be >= min size: " + minSize + " > " + maxSize); + } + + return new int[] {minSize, maxSize}; + } + + private int parseSize(String s) { + s = s.trim().toUpperCase(); + int mult = 1; + + if (s.endsWith("KB")) { + mult = 1024; + s = s.substring(0, s.length() - 2); + } else if (s.endsWith("MB")) { + mult = 1024 * 1024; + s = s.substring(0, s.length() - 2); + } else if (s.endsWith("B")) { + s = s.substring(0, s.length() - 1); + } + + try { + return Integer.parseInt(s.trim()) * mult; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid size format: " + s, e); + } + } + + /** + * Returns list of representative sizes, one per bucket (for payload generation). + * + * @return list of representative sizes + */ + public List getBucketSizes() { + List sizes = new ArrayList<>(); + for (Bucket b : buckets) { + sizes.add(b.getRepresentativeSize()); + } + return sizes; + } + + /** + * Returns list of max sizes, one per bucket (for payload generation). + * Using max sizes ensures the system is tested with the largest messages in each bucket range. + * + * @return list of max sizes per bucket + */ + public List getBucketMaxSizes() { + List sizes = new ArrayList<>(); + for (Bucket b : buckets) { + sizes.add(b.maxSize); + } + return sizes; + } + + /** + * Returns weights array matching bucket order (for runtime selection). + * + * @return array of weights for each bucket + */ + public int[] getWeights() { + int[] weights = new int[buckets.size()]; + for (int i = 0; i < buckets.size(); i++) { + weights[i] = buckets.get(i).weight; + } + return weights; + } + + /** + * Returns cumulative weights array for O(log n) binary search selection. + * + * @return array of cumulative weights + */ + public int[] getCumulativeWeights() { + int[] cumulative = new int[buckets.size()]; + int sum = 0; + for (int i = 0; i < buckets.size(); i++) { + sum += buckets.get(i).weight; + cumulative[i] = sum; + } + return cumulative; + } + + public int getTotalWeight() { + return totalWeight; + } + + public int getMaxSize() { + return buckets.stream().mapToInt(b -> b.maxSize).max().orElse(0); + } + + /** + * Returns weighted average size across all buckets. + * + * @return the weighted average size + */ + public int getAvgSize() { + long sum = 0; + for (Bucket b : buckets) { + sum += (long) b.getRepresentativeSize() * b.weight; + } + return (int) (sum / totalWeight); + } + + public int getBucketCount() { + return buckets.size(); + } + + public List getBuckets() { + return buckets; + } +} + diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadException.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadException.java index 6abfca696..a3887ac31 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadException.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadException.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.payload; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadReader.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadReader.java index cf00c9d38..97d82aa80 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadReader.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/utils/payload/PayloadReader.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.utils.payload; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/BenchmarkWorker.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/BenchmarkWorker.java index 3587ba81b..8723384cf 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/BenchmarkWorker.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/BenchmarkWorker.java @@ -1,53 +1,52 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker; -import org.apache.bookkeeper.stats.Stats; -import org.apache.bookkeeper.stats.StatsProvider; -import org.apache.bookkeeper.stats.prometheus.PrometheusMetricsProvider; -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.ParameterException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; - import io.javalin.Javalin; +import org.apache.bookkeeper.stats.Stats; +import org.apache.bookkeeper.stats.StatsProvider; +import org.apache.bookkeeper.stats.prometheus.PrometheusMetricsProvider; +import org.apache.commons.configuration.CompositeConfiguration; +import org.apache.commons.configuration.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -/** - * A benchmark worker that listen for tasks to perform - */ +/** A benchmark worker that listen for tasks to perform. */ public class BenchmarkWorker { static class Arguments { - @Parameter(names = { "-h", "--help" }, description = "Help message", help = true) + @Parameter( + names = {"-h", "--help"}, + description = "Help message", + help = true) boolean help; - @Parameter(names = { "-p", "--port" }, description = "HTTP port to listen on") + @Parameter( + names = {"-p", "--port"}, + description = "HTTP port to listen on") public int httpPort = 8080; - @Parameter(names = { "-sp", "--stats-port" }, description = "Stats port to listen on") + @Parameter( + names = {"-sp", "--stats-port"}, + description = "Stats port to listen on") public int statsPort = 8081; } @@ -76,9 +75,8 @@ public static void main(String[] args) throws Exception { StatsProvider provider = Stats.get(); provider.start(conf); - Runtime.getRuntime().addShutdownHook(new Thread( - () -> provider.stop(), - "benchmark-worker-shutdown-thread")); + Runtime.getRuntime() + .addShutdownHook(new Thread(() -> provider.stop(), "benchmark-worker-shutdown-thread")); // Dump configuration variables log.info("Starting benchmark with config: {}", writer.writeValueAsString(arguments)); diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsemble.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsemble.java index c56119a1d..c41a0da51 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsemble.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsemble.java @@ -1,52 +1,25 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker; -import static java.util.stream.Collectors.toList; -import static org.asynchttpclient.Dsl.asyncHttpClient; - -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.zip.DataFormatException; - -import org.HdrHistogram.Histogram; -import org.apache.pulsar.common.util.FutureUtil; -import org.asynchttpclient.AsyncHttpClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static java.util.Collections.unmodifiableList; +import static java.util.stream.Collectors.joining; import com.beust.jcommander.internal.Maps; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; - -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; import io.openmessaging.benchmark.utils.ListPartition; import io.openmessaging.benchmark.worker.commands.ConsumerAssignment; import io.openmessaging.benchmark.worker.commands.CountersStats; @@ -55,281 +28,266 @@ import io.openmessaging.benchmark.worker.commands.ProducerWorkAssignment; import io.openmessaging.benchmark.worker.commands.TopicSubscription; import io.openmessaging.benchmark.worker.commands.TopicsInfo; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DistributedWorkersEnsemble implements Worker { - - private final List workers; - private final List producerWorkers; - private final List consumerWorkers; - - private final AsyncHttpClient httpClient = asyncHttpClient(); + private final Thread shutdownHook = new Thread(this::stopAll); + private final List workers; + private final List producerWorkers; + private final List consumerWorkers; + private final Worker leader; private int numberOfUsedProducerWorkers; - public DistributedWorkersEnsemble(List workers, boolean extraConsumerWorkers) { + public DistributedWorkersEnsemble(List workers, boolean extraConsumerWorkers) { Preconditions.checkArgument(workers.size() > 1); + this.workers = unmodifiableList(workers); + leader = workers.get(0); + int numberOfProducerWorkers = getNumberOfProducerWorkers(workers, extraConsumerWorkers); + List> partitions = + Lists.partition(Lists.reverse(workers), workers.size() - numberOfProducerWorkers); + this.producerWorkers = partitions.get(1); + this.consumerWorkers = partitions.get(0); + + log.info( + "Workers list - producers: [{}]", + producerWorkers.stream().map(Worker::id).collect(joining(","))); + log.info( + "Workers list - consumers: {}", + consumerWorkers.stream().map(Worker::id).collect(joining(","))); + + Runtime.getRuntime().addShutdownHook(shutdownHook); + } - this.workers = workers; - - // For driver-jms extra consumers are required. - // If there is an odd number of workers then allocate the extra to consumption. - int numberOfProducerWorkers = extraConsumerWorkers ? (workers.size() + 2) / 3 : workers.size() / 2; - List> partitions = Lists.partition(Lists.reverse(workers), workers.size() - numberOfProducerWorkers); - this.producerWorkers = partitions.get(1); - this.consumerWorkers = partitions.get(0); - - log.info("Workers list - producers: {}", producerWorkers); - log.info("Workers list - consumers: {}", consumerWorkers); + /* + * For driver-jms extra consumers are required. If there is an odd number of workers then allocate the extra + * to consumption. + */ + @VisibleForTesting + static int getNumberOfProducerWorkers(List workers, boolean extraConsumerWorkers) { + return extraConsumerWorkers ? (workers.size() + 2) / 3 : workers.size() / 2; } @Override public void initializeDriver(File configurationFile) throws IOException { - byte[] confFileContent = Files.readAllBytes(Paths.get(configurationFile.toString())); - sendPost(workers, "/initialize-driver", confFileContent); + workers.parallelStream() + .forEach( + w -> { + try { + w.initializeDriver(configurationFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override @SuppressWarnings("unchecked") public List createTopics(TopicsInfo topicsInfo) throws IOException { - // Create all topics from a single worker node - return (List) post(workers.get(0), "/create-topics", writer.writeValueAsBytes(topicsInfo), List.class) - .join(); + return leader.createTopics(topicsInfo); } @Override public void createProducers(List topics) { - List> topicsPerProducer = ListPartition.partitionList(topics, - producerWorkers.size()); - Map> topicsPerProducerMap = Maps.newHashMap(); + List> topicsPerProducer = + ListPartition.partitionList(topics, producerWorkers.size()); + Map> topicsPerProducerMap = Maps.newHashMap(); int i = 0; for (List assignedTopics : topicsPerProducer) { topicsPerProducerMap.put(producerWorkers.get(i++), assignedTopics); } // Number of actually used workers might be less than available workers - numberOfUsedProducerWorkers = i; - - List> futures = topicsPerProducerMap.keySet().stream().map(producer -> { - try { - return sendPost(producer, "/create-producers", - writer.writeValueAsBytes(topicsPerProducerMap.get(producer))); - } catch (Exception e) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(e); - return future; - } - }).collect(toList()); - - FutureUtil.waitForAll(futures).join(); + numberOfUsedProducerWorkers = + (int) topicsPerProducerMap.values().stream().filter(t -> !t.isEmpty()).count(); + log.debug( + "Producing worker count: {} of {}", numberOfUsedProducerWorkers, producerWorkers.size()); + topicsPerProducerMap.entrySet().parallelStream() + .forEach( + e -> { + try { + e.getKey().createProducers(e.getValue()); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + }); } @Override public void startLoad(ProducerWorkAssignment producerWorkAssignment) throws IOException { // Reduce the publish rate across all the brokers - producerWorkAssignment.publishRate /= numberOfUsedProducerWorkers; - sendPost(producerWorkers, "/start-load", writer.writeValueAsBytes(producerWorkAssignment)); + double newRate = producerWorkAssignment.publishRate / numberOfUsedProducerWorkers; + log.debug("Setting worker assigned publish rate to {} msgs/sec", newRate); + // Reduce the publish rate across all the brokers + producerWorkers.parallelStream() + .forEach( + w -> { + try { + w.startLoad(producerWorkAssignment.withPublishRate(newRate)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override public void probeProducers() throws IOException { - sendPost(producerWorkers, "/probe-producers", new byte[0]); + producerWorkers.parallelStream() + .forEach( + w -> { + try { + w.probeProducers(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override public void adjustPublishRate(double publishRate) throws IOException { - // Reduce the publish rate across all the brokers - publishRate /= numberOfUsedProducerWorkers; - sendPost(producerWorkers, "/adjust-publish-rate", writer.writeValueAsBytes(publishRate)); + double newRate = publishRate / numberOfUsedProducerWorkers; + log.debug("Adjusting producer publish rate to {} msgs/sec", newRate); + producerWorkers.parallelStream() + .forEach( + w -> { + try { + w.adjustPublishRate(newRate); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override public void stopAll() { - sendPost(workers, "/stop-all", new byte[0]); + workers.parallelStream().forEach(Worker::stopAll); + } + + @Override + public String id() { + return "Ensemble[" + workers.stream().map(Worker::id).collect(joining(",")) + "]"; } @Override public void pauseConsumers() throws IOException { - sendPost(consumerWorkers, "/pause-consumers", new byte[0]); + consumerWorkers.parallelStream() + .forEach( + w -> { + try { + w.pauseConsumers(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override public void resumeConsumers() throws IOException { - sendPost(consumerWorkers, "/resume-consumers", new byte[0]); + consumerWorkers.parallelStream() + .forEach( + w -> { + try { + w.resumeConsumers(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override public void createConsumers(ConsumerAssignment overallConsumerAssignment) { - List> subscriptionsPerConsumer = ListPartition.partitionList( - overallConsumerAssignment.topicsSubscriptions, - consumerWorkers.size()); - Map topicsPerWorkerMap = Maps.newHashMap(); + List> subscriptionsPerConsumer = + ListPartition.partitionList( + overallConsumerAssignment.topicsSubscriptions, consumerWorkers.size()); + Map topicsPerWorkerMap = Maps.newHashMap(); int i = 0; for (List tsl : subscriptionsPerConsumer) { - ConsumerAssignment individualAssignement = new ConsumerAssignment(); - individualAssignement.topicsSubscriptions = tsl; - topicsPerWorkerMap.put(consumerWorkers.get(i++), individualAssignement); + ConsumerAssignment individualAssignment = new ConsumerAssignment(); + individualAssignment.topicsSubscriptions = tsl; + topicsPerWorkerMap.put(consumerWorkers.get(i++), individualAssignment); } - - List> futures = topicsPerWorkerMap.keySet().stream().map(consumer -> { - try { - return sendPost(consumer, "/create-consumers", - writer.writeValueAsBytes(topicsPerWorkerMap.get(consumer))); - } catch (Exception e) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(e); - return future; - } - }).collect(toList()); - - FutureUtil.waitForAll(futures).join(); + topicsPerWorkerMap.entrySet().parallelStream() + .forEach( + e -> { + try { + e.getKey().createConsumers(e.getValue()); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + }); } @Override public PeriodStats getPeriodStats() { - List individualStats = get(workers, "/period-stats", PeriodStats.class); - PeriodStats stats = new PeriodStats(); - individualStats.forEach(is -> { - stats.messagesSent += is.messagesSent; - stats.bytesSent += is.bytesSent; - stats.messagesReceived += is.messagesReceived; - stats.bytesReceived += is.bytesReceived; - stats.totalMessagesSent += is.totalMessagesSent; - stats.totalMessagesReceived += is.totalMessagesReceived; - - try { - stats.publishLatency.add(Histogram.decodeFromCompressedByteBuffer( - ByteBuffer.wrap(is.publishLatencyBytes), TimeUnit.SECONDS.toMicros(30))); - - stats.endToEndLatency.add(Histogram.decodeFromCompressedByteBuffer( - ByteBuffer.wrap(is.endToEndLatencyBytes), TimeUnit.HOURS.toMicros(12))); - } catch (ArrayIndexOutOfBoundsException | DataFormatException e) { - throw new RuntimeException(e); - } - }); - - return stats; + return workers.parallelStream() + .map( + w -> { + try { + return w.getPeriodStats(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .reduce(new PeriodStats(), PeriodStats::plus); } @Override public CumulativeLatencies getCumulativeLatencies() { - List individualStats = get(workers, "/cumulative-latencies", CumulativeLatencies.class); - - CumulativeLatencies stats = new CumulativeLatencies(); - individualStats.forEach(is -> { - try { - stats.publishLatency.add(Histogram.decodeFromCompressedByteBuffer( - ByteBuffer.wrap(is.publishLatencyBytes), TimeUnit.SECONDS.toMicros(30))); - } catch (Exception e) { - log.error("Failed to decode publish latency: {}", - ByteBufUtil.prettyHexDump(Unpooled.wrappedBuffer(is.publishLatencyBytes))); - throw new RuntimeException(e); - } - - try { - stats.endToEndLatency.add(Histogram.decodeFromCompressedByteBuffer( - ByteBuffer.wrap(is.endToEndLatencyBytes), TimeUnit.HOURS.toMicros(12))); - } catch (Exception e) { - log.error("Failed to decode end-to-end latency: {}", - ByteBufUtil.prettyHexDump(Unpooled.wrappedBuffer(is.endToEndLatencyBytes))); - throw new RuntimeException(e); - } - }); - - return stats; - + return workers.parallelStream() + .map( + w -> { + try { + return w.getCumulativeLatencies(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .reduce(new CumulativeLatencies(), CumulativeLatencies::plus); } @Override public CountersStats getCountersStats() throws IOException { - List individualStats = get(workers, "/counters-stats", CountersStats.class); - - CountersStats stats = new CountersStats(); - individualStats.forEach(is -> { - stats.messagesSent += is.messagesSent; - stats.messagesReceived += is.messagesReceived; - }); - - return stats; + return workers.parallelStream() + .map( + w -> { + try { + return w.getCountersStats(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .reduce(new CountersStats(), CountersStats::plus); } @Override public void resetStats() throws IOException { - sendPost(workers, "/reset-stats", new byte[0]); - } - - /** - * Send a request to multiple hosts and wait for all responses - */ - private void sendPost(List hosts, String path, byte[] body) { - FutureUtil.waitForAll(hosts.stream().map(w -> sendPost(w, path, body)).collect(toList())).join(); - } - - private CompletableFuture sendPost(String host, String path, byte[] body) { - return httpClient.preparePost(host + path).setBody(body).execute().toCompletableFuture().thenApply(x -> { - if (x.getStatusCode() != 200) { - log.error("Failed to do HTTP post request to {}{} -- code: {}", host, path, x.getStatusCode()); - } - Preconditions.checkArgument(x.getStatusCode() == 200); - return (Void) null; - }); - } - - private List get(List hosts, String path, Class clazz) { - List> futures = hosts.stream().map(w -> get(w, path, clazz)).collect(toList()); - - CompletableFuture> resultFuture = new CompletableFuture<>(); - FutureUtil.waitForAll(futures).thenRun(() -> { - resultFuture.complete(futures.stream().map(CompletableFuture::join).collect(toList())); - }).exceptionally(ex -> { - resultFuture.completeExceptionally(ex); - return null; - }); - - return resultFuture.join(); - } - - private CompletableFuture get(String host, String path, Class clazz) { - return httpClient.prepareGet(host + path).execute().toCompletableFuture().thenApply(response -> { - try { - if (response.getStatusCode() != 200) { - log.error("Failed to do HTTP get request to {}{} -- code: {}", host, path, response.getStatusCode()); - } - Preconditions.checkArgument(response.getStatusCode() == 200); - return mapper.readValue(response.getResponseBody(), clazz); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - - private CompletableFuture post(String host, String path, byte[] body, Class clazz) { - return httpClient.preparePost(host + path).setBody(body).execute().toCompletableFuture().thenApply(response -> { - try { - if (response.getStatusCode() != 200) { - log.error("Failed to do HTTP post request to {}{} -- code: {}", host, path, response.getStatusCode()); - } - Preconditions.checkArgument(response.getStatusCode() == 200); - return mapper.readValue(response.getResponseBody(), clazz); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); + workers.parallelStream() + .forEach( + w -> { + try { + w.resetStats(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } @Override public void close() throws Exception { - httpClient.close(); - } - - private static final ObjectWriter writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); - - private static final ObjectMapper mapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - static { - mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); + Runtime.getRuntime().removeShutdownHook(shutdownHook); + for (Worker w : workers) { + try { + w.close(); + } catch (Exception ignored) { + log.trace("Ignored error while closing worker {}", w, ignored); + } + } } private static final Logger log = LoggerFactory.getLogger(DistributedWorkersEnsemble.class); - } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/HttpWorkerClient.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/HttpWorkerClient.java new file mode 100644 index 000000000..513b04178 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/HttpWorkerClient.java @@ -0,0 +1,231 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker; + +import static io.openmessaging.benchmark.worker.WorkerHandler.ADJUST_PUBLISH_RATE; +import static io.openmessaging.benchmark.worker.WorkerHandler.COUNTERS_STATS; +import static io.openmessaging.benchmark.worker.WorkerHandler.CREATE_CONSUMERS; +import static io.openmessaging.benchmark.worker.WorkerHandler.CREATE_PRODUCERS; +import static io.openmessaging.benchmark.worker.WorkerHandler.CREATE_TOPICS; +import static io.openmessaging.benchmark.worker.WorkerHandler.CUMULATIVE_LATENCIES; +import static io.openmessaging.benchmark.worker.WorkerHandler.INITIALIZE_DRIVER; +import static io.openmessaging.benchmark.worker.WorkerHandler.PAUSE_CONSUMERS; +import static io.openmessaging.benchmark.worker.WorkerHandler.PERIOD_STATS; +import static io.openmessaging.benchmark.worker.WorkerHandler.PROBE_PRODUCERS; +import static io.openmessaging.benchmark.worker.WorkerHandler.RESET_STATS; +import static io.openmessaging.benchmark.worker.WorkerHandler.RESUME_CONSUMERS; +import static io.openmessaging.benchmark.worker.WorkerHandler.START_LOAD; +import static io.openmessaging.benchmark.worker.WorkerHandler.STOP_ALL; +import static org.asynchttpclient.Dsl.asyncHttpClient; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.google.common.base.Preconditions; +import io.openmessaging.benchmark.worker.commands.ConsumerAssignment; +import io.openmessaging.benchmark.worker.commands.CountersStats; +import io.openmessaging.benchmark.worker.commands.CumulativeLatencies; +import io.openmessaging.benchmark.worker.commands.PeriodStats; +import io.openmessaging.benchmark.worker.commands.ProducerWorkAssignment; +import io.openmessaging.benchmark.worker.commands.TopicsInfo; +import io.openmessaging.benchmark.worker.jackson.ObjectMappers; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.Dsl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HttpWorkerClient implements Worker { + + private static final byte[] EMPTY_BODY = new byte[0]; + private static final int HTTP_OK = 200; + + private final AsyncHttpClient httpClient; + private final String host; + + public HttpWorkerClient(String host) { + this(asyncHttpClient(Dsl.config().setReadTimeout(600000).setRequestTimeout(600000)), host); + } + + HttpWorkerClient(AsyncHttpClient httpClient, String host) { + this.httpClient = httpClient; + this.host = host; + } + + @Override + public void initializeDriver(File configurationFile) throws IOException { + byte[] confFileContent = Files.readAllBytes(Paths.get(configurationFile.toString())); + sendPost(INITIALIZE_DRIVER, confFileContent); + } + + @SuppressWarnings("unchecked") + @Override + public List createTopics(TopicsInfo topicsInfo) throws IOException { + return (List) post(CREATE_TOPICS, writer.writeValueAsBytes(topicsInfo), List.class); + } + + @Override + public void createProducers(List topics) throws IOException { + sendPost(CREATE_PRODUCERS, writer.writeValueAsBytes(topics)); + } + + @Override + public void createConsumers(ConsumerAssignment consumerAssignment) throws IOException { + sendPost(CREATE_CONSUMERS, writer.writeValueAsBytes(consumerAssignment)); + } + + @Override + public void probeProducers() throws IOException { + sendPost(PROBE_PRODUCERS); + } + + @Override + public void startLoad(ProducerWorkAssignment producerWorkAssignment) throws IOException { + log.debug( + "Setting worker assigned publish rate to {} msgs/sec", producerWorkAssignment.publishRate); + sendPost(START_LOAD, writer.writeValueAsBytes(producerWorkAssignment)); + } + + @Override + public void adjustPublishRate(double publishRate) throws IOException { + log.debug("Adjusting worker publish rate to {} msgs/sec", publishRate); + sendPost(ADJUST_PUBLISH_RATE, writer.writeValueAsBytes(publishRate)); + } + + @Override + public void pauseConsumers() throws IOException { + sendPost(PAUSE_CONSUMERS); + } + + @Override + public void resumeConsumers() throws IOException { + sendPost(RESUME_CONSUMERS); + } + + @Override + public CountersStats getCountersStats() throws IOException { + return get(COUNTERS_STATS, CountersStats.class); + } + + @Override + public PeriodStats getPeriodStats() throws IOException { + return get(PERIOD_STATS, PeriodStats.class); + } + + @Override + public CumulativeLatencies getCumulativeLatencies() throws IOException { + return get(CUMULATIVE_LATENCIES, CumulativeLatencies.class); + } + + @Override + public void resetStats() throws IOException { + sendPost(RESET_STATS); + } + + @Override + public void stopAll() { + sendPost(STOP_ALL); + } + + @Override + public String id() { + return host; + } + + @Override + public void close() throws Exception { + httpClient.close(); + } + + private void sendPost(String path) { + sendPost(path, EMPTY_BODY); + } + + private void sendPost(String path, byte[] body) { + httpClient + .preparePost(host + path) + .setBody(body) + .execute() + .toCompletableFuture() + .thenApply( + response -> { + if (response.getStatusCode() != HTTP_OK) { + log.error( + "Failed to do HTTP post request to {}{} -- code: {}", + host, + path, + response.getStatusCode()); + } + Preconditions.checkArgument(response.getStatusCode() == HTTP_OK); + return (Void) null; + }) + .join(); + } + + private T get(String path, Class clazz) { + return httpClient + .prepareGet(host + path) + .execute() + .toCompletableFuture() + .thenApply( + response -> { + try { + if (response.getStatusCode() != HTTP_OK) { + log.error( + "Failed to do HTTP get request to {}{} -- code: {}", + host, + path, + response.getStatusCode()); + } + Preconditions.checkArgument(response.getStatusCode() == HTTP_OK); + return mapper.readValue(response.getResponseBody(), clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .join(); + } + + private T post(String path, byte[] body, Class clazz) { + return httpClient + .preparePost(host + path) + .setBody(body) + .execute() + .toCompletableFuture() + .thenApply( + response -> { + try { + if (response.getStatusCode() != HTTP_OK) { + log.error( + "Failed to do HTTP post request to {}{} -- code: {}", + host, + path, + response.getStatusCode()); + } + Preconditions.checkArgument(response.getStatusCode() == HTTP_OK); + return mapper.readValue(response.getResponseBody(), clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .join(); + } + + private static final ObjectMapper mapper = ObjectMappers.DEFAULT.mapper(); + private static final ObjectWriter writer = ObjectMappers.DEFAULT.writer(); + private static final Logger log = LoggerFactory.getLogger(HttpWorkerClient.class); +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/LocalWorker.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/LocalWorker.java index 5c5ad560b..af64369c4 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/LocalWorker.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/LocalWorker.java @@ -1,59 +1,37 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker; import static java.util.stream.Collectors.toList; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.LongAdder; -import java.util.function.Function; - -import org.HdrHistogram.Recorder; -import org.apache.bookkeeper.stats.Counter; -import org.apache.bookkeeper.stats.NullStatsLogger; -import org.apache.bookkeeper.stats.OpStatsLogger; -import org.apache.bookkeeper.stats.StatsLogger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.RateLimiter; - import io.netty.util.concurrent.DefaultThreadFactory; import io.openmessaging.benchmark.DriverConfiguration; import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkDriver.ConsumerInfo; +import io.openmessaging.benchmark.driver.BenchmarkDriver.ProducerInfo; +import io.openmessaging.benchmark.driver.BenchmarkDriver.TopicInfo; import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.openmessaging.benchmark.driver.ConsumerCallback; import io.openmessaging.benchmark.utils.RandomGenerator; import io.openmessaging.benchmark.utils.Timer; +import io.openmessaging.benchmark.utils.UniformRateLimiter; import io.openmessaging.benchmark.utils.distributor.KeyDistributor; import io.openmessaging.benchmark.worker.commands.ConsumerAssignment; import io.openmessaging.benchmark.worker.commands.CountersStats; @@ -61,45 +39,36 @@ import io.openmessaging.benchmark.worker.commands.PeriodStats; import io.openmessaging.benchmark.worker.commands.ProducerWorkAssignment; import io.openmessaging.benchmark.worker.commands.TopicsInfo; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import org.apache.bookkeeper.stats.NullStatsLogger; +import org.apache.bookkeeper.stats.StatsLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class LocalWorker implements Worker, ConsumerCallback { private BenchmarkDriver benchmarkDriver = null; - - private List producers = new ArrayList<>(); - private List consumers = new ArrayList<>(); - - private final RateLimiter rateLimiter = RateLimiter.create(1.0); - - private final ExecutorService executor = Executors.newCachedThreadPool(new DefaultThreadFactory("local-worker")); - - // stats - - private final StatsLogger statsLogger; - - private final LongAdder messagesSent = new LongAdder(); - private final LongAdder bytesSent = new LongAdder(); - private final Counter messagesSentCounter; - private final Counter bytesSentCounter; - - private final LongAdder messagesReceived = new LongAdder(); - private final LongAdder bytesReceived = new LongAdder(); - private final Counter messagesReceivedCounter; - private final Counter bytesReceivedCounter; - - private final LongAdder totalMessagesSent = new LongAdder(); - private final LongAdder totalMessagesReceived = new LongAdder(); - - private final Recorder publishLatencyRecorder = new Recorder(TimeUnit.SECONDS.toMicros(60), 5); - private final Recorder cumulativePublishLatencyRecorder = new Recorder(TimeUnit.SECONDS.toMicros(60), 5); - private final OpStatsLogger publishLatencyStats; - - private final Recorder endToEndLatencyRecorder = new Recorder(TimeUnit.HOURS.toMicros(12), 5); - private final Recorder endToEndCumulativeLatencyRecorder = new Recorder(TimeUnit.HOURS.toMicros(12), 5); - private final OpStatsLogger endToEndLatencyStats; - + private final List producers = new ArrayList<>(); + private final List consumers = new ArrayList<>(); + private volatile MessageProducer messageProducer; + private final ExecutorService executor = + Executors.newCachedThreadPool(new DefaultThreadFactory("local-worker")); + private final WorkerStats stats; private boolean testCompleted = false; - private boolean consumersArePaused = false; public LocalWorker() { @@ -107,17 +76,8 @@ public LocalWorker() { } public LocalWorker(StatsLogger statsLogger) { - this.statsLogger = statsLogger; - - StatsLogger producerStatsLogger = statsLogger.scope("producer"); - this.messagesSentCounter = producerStatsLogger.getCounter("messages_sent"); - this.bytesSentCounter = producerStatsLogger.getCounter("bytes_sent"); - this.publishLatencyStats = producerStatsLogger.getOpStatsLogger("produce_latency"); - - StatsLogger consumerStatsLogger = statsLogger.scope("consumer"); - this.messagesReceivedCounter = consumerStatsLogger.getCounter("messages_recv"); - this.bytesReceivedCounter = consumerStatsLogger.getCounter("bytes_recv"); - this.endToEndLatencyStats = consumerStatsLogger.getOpStatsLogger("e2e_latency"); + stats = new WorkerStats(statsLogger); + updateMessageProducer(1.0); } @Override @@ -125,58 +85,78 @@ public void initializeDriver(File driverConfigFile) throws IOException { Preconditions.checkArgument(benchmarkDriver == null); testCompleted = false; - DriverConfiguration driverConfiguration = mapper.readValue(driverConfigFile, DriverConfiguration.class); + DriverConfiguration driverConfiguration = + mapper.readValue(driverConfigFile, DriverConfiguration.class); log.info("Driver: {}", writer.writeValueAsString(driverConfiguration)); try { - benchmarkDriver = (BenchmarkDriver) Class.forName(driverConfiguration.driverClass).newInstance(); - benchmarkDriver.initialize(driverConfigFile, statsLogger); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + benchmarkDriver = + (BenchmarkDriver) Class.forName(driverConfiguration.driverClass).newInstance(); + benchmarkDriver.initialize(driverConfigFile, stats.getStatsLogger()); + } catch (InstantiationException + | IllegalAccessException + | ClassNotFoundException + | InterruptedException e) { throw new RuntimeException(e); } } @Override public List createTopics(TopicsInfo topicsInfo) { - List> futures = new ArrayList<>(); - Timer timer = new Timer(); - String topicPrefix = benchmarkDriver.getTopicNamePrefix(); + List topicInfos = + IntStream.range(0, topicsInfo.numberOfTopics) + .mapToObj( + i -> new TopicInfo(generateTopicName(i), topicsInfo.numberOfPartitionsPerTopic)) + .collect(toList()); - List topics = new ArrayList<>(); - for (int i = 0; i < topicsInfo.numberOfTopics; i++) { - String topic = String.format("%s-%s-%04d", topicPrefix, RandomGenerator.getRandomString(), i); - topics.add(topic); - futures.add(benchmarkDriver.createTopic(topic, topicsInfo.numberOfPartitionsPerTopic)); - } + benchmarkDriver.createTopics(topicInfos).join(); - futures.forEach(CompletableFuture::join); + List topics = topicInfos.stream().map(TopicInfo::getTopic).collect(toList()); log.info("Created {} topics in {} ms", topics.size(), timer.elapsedMillis()); return topics; } + private String generateTopicName(int i) { + return String.format( + "%s-%07d-%s", benchmarkDriver.getTopicNamePrefix(), i, RandomGenerator.getRandomString()); + } + @Override public void createProducers(List topics) { Timer timer = new Timer(); + AtomicInteger index = new AtomicInteger(); - List> futures = topics.stream() - .map(topic -> benchmarkDriver.createProducer(topic)).collect(toList()); + producers.addAll( + benchmarkDriver + .createProducers( + topics.stream() + .map(t -> new ProducerInfo(index.getAndIncrement(), t)) + .collect(toList())) + .join()); - futures.forEach(f -> producers.add(f.join())); log.info("Created {} producers in {} ms", producers.size(), timer.elapsedMillis()); } @Override public void createConsumers(ConsumerAssignment consumerAssignment) { Timer timer = new Timer(); + AtomicInteger index = new AtomicInteger(); + + consumers.addAll( + benchmarkDriver + .createConsumers( + consumerAssignment.topicsSubscriptions.stream() + .map( + c -> + new ConsumerInfo( + index.getAndIncrement(), c.topic, c.subscription, this)) + .collect(toList())) + .join()); - List> futures = consumerAssignment.topicsSubscriptions.stream() - .map(ts -> benchmarkDriver.createConsumer(ts.topic, ts.subscription, this)).collect(toList()); - - futures.forEach(f -> consumers.add(f.join())); log.info("Created {} consumers in {} ms", consumers.size(), timer.elapsedMillis()); } @@ -184,104 +164,119 @@ public void createConsumers(ConsumerAssignment consumerAssignment) { public void startLoad(ProducerWorkAssignment producerWorkAssignment) { int processors = Runtime.getRuntime().availableProcessors(); - rateLimiter.setRate(producerWorkAssignment.publishRate); + updateMessageProducer(producerWorkAssignment.publishRate); Map> processorAssignment = new TreeMap<>(); int processorIdx = 0; for (BenchmarkProducer p : producers) { - processorAssignment.computeIfAbsent(processorIdx, x -> new ArrayList()).add(p); + processorAssignment + .computeIfAbsent(processorIdx, x -> new ArrayList()) + .add(p); processorIdx = (processorIdx + 1) % processors; } - processorAssignment.values().forEach(producers -> submitProducersToExecutor(producers, - KeyDistributor.build(producerWorkAssignment.keyDistributorType), producerWorkAssignment.payloadData)); + processorAssignment + .values() + .forEach( + producers -> + submitProducersToExecutor( + producers, + KeyDistributor.build(producerWorkAssignment.keyDistributorType), + producerWorkAssignment.payloadData, + producerWorkAssignment.payloadWeights)); } @Override public void probeProducers() throws IOException { - producers.forEach(producer -> producer.sendAsync(Optional.of("key"), new byte[10]) - .thenRun(() -> totalMessagesSent.increment())); + producers.forEach( + producer -> + producer.sendAsync(Optional.of("key"), new byte[10]).thenRun(stats::recordMessageSent)); } - private void submitProducersToExecutor(List producers, KeyDistributor keyDistributor, List payloads) { - executor.submit(() -> { - int payloadCount = payloads.size(); - Random r = new Random(); - byte[] firstPayload = payloads.get(0); - - try { - while (!testCompleted) { - producers.forEach(producer -> { - rateLimiter.acquire(); - byte[] payloadData = payloadCount == 0 ? firstPayload : payloads.get(r.nextInt(payloadCount)); - final long sendTime = System.nanoTime(); - producer.sendAsync(Optional.ofNullable(keyDistributor.next()), payloadData) - .thenRun(() -> { - messagesSent.increment(); - totalMessagesSent.increment(); - messagesSentCounter.inc(); - bytesSent.add(payloadData.length); - bytesSentCounter.add(payloadData.length); - - long latencyMicros = TimeUnit.NANOSECONDS.toMicros(System.nanoTime() - sendTime); - publishLatencyRecorder.recordValue(latencyMicros); - cumulativePublishLatencyRecorder.recordValue(latencyMicros); - publishLatencyStats.registerSuccessfulEvent(latencyMicros, TimeUnit.MICROSECONDS); - }).exceptionally(ex -> { - log.warn("Write error on message", ex); - return null; - }); - }); - } - } catch (Throwable t) { - log.error("Got error", t); + private void submitProducersToExecutor( + List producers, + KeyDistributor keyDistributor, + List payloads, + int[] weights) { + + // Build cumulative weights for O(log n) weighted selection if weights are provided + final int[] cumulative; + final int totalWeight; + if (weights != null && weights.length > 0) { + cumulative = new int[weights.length]; + int sum = 0; + for (int i = 0; i < weights.length; i++) { + sum += weights[i]; + cumulative[i] = sum; } - }); + totalWeight = sum; + } else { + cumulative = null; + totalWeight = payloads.size(); + } + + final int payloadCount = payloads.size(); + + executor.submit( + () -> { + try { + ThreadLocalRandom r = ThreadLocalRandom.current(); + while (!testCompleted) { + producers.forEach( + p -> { + int idx; + if (cumulative != null) { + // Weighted selection via binary search + int target = r.nextInt(totalWeight); + idx = Arrays.binarySearch(cumulative, target + 1); + if (idx < 0) { + idx = -idx - 1; + } + idx = Math.min(idx, payloadCount - 1); + } else { + // Uniform selection (backward compatible) + idx = r.nextInt(payloadCount); + } + messageProducer.sendMessage( + p, + Optional.ofNullable(keyDistributor.next()), + payloads.get(idx)); + }); + } + } catch (Throwable t) { + log.error("Got error", t); + } + }); } @Override public void adjustPublishRate(double publishRate) { - if(publishRate < 1.0) { - rateLimiter.setRate(1.0); + if (publishRate < 1.0) { + updateMessageProducer(1.0); return; } - rateLimiter.setRate(publishRate); + updateMessageProducer(publishRate); + } + + private void updateMessageProducer(double publishRate) { + messageProducer = new MessageProducer(new UniformRateLimiter(publishRate), stats); } @Override public PeriodStats getPeriodStats() { - PeriodStats stats = new PeriodStats(); - - stats.messagesSent = messagesSent.sumThenReset(); - stats.bytesSent = bytesSent.sumThenReset(); - - stats.messagesReceived = messagesReceived.sumThenReset(); - stats.bytesReceived = bytesReceived.sumThenReset(); - - stats.totalMessagesSent = totalMessagesSent.sum(); - stats.totalMessagesReceived = totalMessagesReceived.sum(); - - stats.publishLatency = publishLatencyRecorder.getIntervalHistogram(); - stats.endToEndLatency = endToEndLatencyRecorder.getIntervalHistogram(); - return stats; + return stats.toPeriodStats(); } @Override public CumulativeLatencies getCumulativeLatencies() { - CumulativeLatencies latencies = new CumulativeLatencies(); - latencies.publishLatency = cumulativePublishLatencyRecorder.getIntervalHistogram(); - latencies.endToEndLatency = endToEndCumulativeLatencyRecorder.getIntervalHistogram(); - return latencies; + return stats.toCumulativeLatencies(); } @Override public CountersStats getCountersStats() throws IOException { - CountersStats stats = new CountersStats(); - stats.messagesSent = totalMessagesSent.sum(); - stats.messagesReceived = totalMessagesReceived.sum(); - return stats; + return stats.toCountersStats(); } @Override @@ -295,19 +290,9 @@ public void messageReceived(ByteBuffer data, long publishTimestamp) { } public void internalMessageReceived(int size, long publishTimestamp) { - messagesReceived.increment(); - totalMessagesReceived.increment(); - messagesReceivedCounter.inc(); - bytesReceived.add(size); - bytesReceivedCounter.add(size); - long now = System.currentTimeMillis(); long endToEndLatencyMicros = TimeUnit.MILLISECONDS.toMicros(now - publishTimestamp); - if (endToEndLatencyMicros > 0) { - endToEndCumulativeLatencyRecorder.recordValue(endToEndLatencyMicros); - endToEndLatencyRecorder.recordValue(endToEndLatencyMicros); - endToEndLatencyStats.registerSuccessfulEvent(endToEndLatencyMicros, TimeUnit.MICROSECONDS); - } + stats.recordMessageReceived(size, endToEndLatencyMicros); while (consumersArePaused) { try { @@ -332,28 +317,14 @@ public void resumeConsumers() throws IOException { @Override public void resetStats() throws IOException { - publishLatencyRecorder.reset(); - cumulativePublishLatencyRecorder.reset(); - endToEndLatencyRecorder.reset(); - endToEndCumulativeLatencyRecorder.reset(); + stats.resetLatencies(); } @Override - public void stopAll() throws IOException { + public void stopAll() { testCompleted = true; consumersArePaused = false; - - publishLatencyRecorder.reset(); - cumulativePublishLatencyRecorder.reset(); - endToEndLatencyRecorder.reset(); - endToEndCumulativeLatencyRecorder.reset(); - - messagesSent.reset(); - bytesSent.reset(); - messagesReceived.reset(); - bytesReceived.reset(); - totalMessagesSent.reset(); - totalMessagesReceived.reset(); + stats.reset(); try { Thread.sleep(100); @@ -377,6 +348,11 @@ public void stopAll() throws IOException { } } + @Override + public String id() { + return "local"; + } + @Override public void close() throws Exception { executor.shutdown(); @@ -384,8 +360,9 @@ public void close() throws Exception { private static final ObjectWriter writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); static { mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/MessageProducer.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/MessageProducer.java new file mode 100644 index 000000000..bf1191ef9 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/MessageProducer.java @@ -0,0 +1,63 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker; + +import static io.openmessaging.benchmark.utils.UniformRateLimiter.uninterruptibleSleepNs; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.utils.UniformRateLimiter; +import java.util.Optional; +import java.util.function.Supplier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MessageProducer { + + private final WorkerStats stats; + private UniformRateLimiter rateLimiter; + private Supplier nanoClock; + + MessageProducer(UniformRateLimiter rateLimiter, WorkerStats stats) { + this(System::nanoTime, rateLimiter, stats); + } + + MessageProducer(Supplier nanoClock, UniformRateLimiter rateLimiter, WorkerStats stats) { + this.nanoClock = nanoClock; + this.rateLimiter = rateLimiter; + this.stats = stats; + } + + public void sendMessage(BenchmarkProducer producer, Optional key, byte[] payload) { + final long intendedSendTime = rateLimiter.acquire(); + uninterruptibleSleepNs(intendedSendTime); + final long sendTime = nanoClock.get(); + producer + .sendAsync(key, payload) + .thenRun(() -> success(payload.length, intendedSendTime, sendTime)) + .exceptionally(this::failure); + } + + private void success(long payloadLength, long intendedSendTime, long sendTime) { + long nowNs = nanoClock.get(); + stats.recordProducerSuccess(payloadLength, intendedSendTime, sendTime, nowNs); + } + + private Void failure(Throwable t) { + stats.recordProducerFailure(); + log.warn("Write error on message", t); + return null; + } + + private static final Logger log = LoggerFactory.getLogger(MessageProducer.class); +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/Worker.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/Worker.java index d7bcb96d9..60b0f15d7 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/Worker.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/Worker.java @@ -1,26 +1,18 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker; -import java.io.File; -import java.io.IOException; -import java.util.List; import io.openmessaging.benchmark.worker.commands.ConsumerAssignment; import io.openmessaging.benchmark.worker.commands.CountersStats; @@ -28,6 +20,9 @@ import io.openmessaging.benchmark.worker.commands.PeriodStats; import io.openmessaging.benchmark.worker.commands.ProducerWorkAssignment; import io.openmessaging.benchmark.worker.commands.TopicsInfo; +import java.io.File; +import java.io.IOException; +import java.util.List; public interface Worker extends AutoCloseable { @@ -57,5 +52,7 @@ public interface Worker extends AutoCloseable { void resetStats() throws IOException; - void stopAll() throws IOException; + void stopAll(); + + String id(); } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerHandler.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerHandler.java index dcf63fdda..f7142cf9f 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerHandler.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerHandler.java @@ -1,66 +1,70 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker; -import java.io.File; -import java.nio.ByteBuffer; -import java.util.List; -import org.apache.bookkeeper.stats.StatsLogger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; import com.google.common.io.Files; - import io.javalin.Context; import io.javalin.Javalin; import io.openmessaging.benchmark.worker.commands.ConsumerAssignment; -import io.openmessaging.benchmark.worker.commands.CumulativeLatencies; -import io.openmessaging.benchmark.worker.commands.PeriodStats; import io.openmessaging.benchmark.worker.commands.ProducerWorkAssignment; import io.openmessaging.benchmark.worker.commands.TopicsInfo; +import io.openmessaging.benchmark.worker.jackson.ObjectMappers; +import java.io.File; +import java.util.List; +import org.apache.bookkeeper.stats.StatsLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @SuppressWarnings("unchecked") public class WorkerHandler { + public static final String INITIALIZE_DRIVER = "/initialize-driver"; + public static final String CREATE_TOPICS = "/create-topics"; + public static final String CREATE_PRODUCERS = "/create-producers"; + public static final String PROBE_PRODUCERS = "/probe-producers"; + public static final String CREATE_CONSUMERS = "/create-consumers"; + public static final String PAUSE_CONSUMERS = "/pause-consumers"; + public static final String RESUME_CONSUMERS = "/resume-consumers"; + public static final String START_LOAD = "/start-load"; + public static final String ADJUST_PUBLISH_RATE = "/adjust-publish-rate"; + public static final String STOP_ALL = "/stop-all"; + public static final String PERIOD_STATS = "/period-stats"; + public static final String CUMULATIVE_LATENCIES = "/cumulative-latencies"; + public static final String COUNTERS_STATS = "/counters-stats"; + public static final String RESET_STATS = "/reset-stats"; private final Worker localWorker; public WorkerHandler(Javalin app, StatsLogger statsLogger) { this.localWorker = new LocalWorker(statsLogger); - app.post("/initialize-driver", this::handleInitializeDriver); - app.post("/create-topics", this::handleCreateTopics); - app.post("/create-producers", this::handleCreateProducers); - app.post("/probe-producers", this::handleProbeProducers); - app.post("/create-consumers", this::handleCreateConsumers); - app.post("/pause-consumers", this::handlePauseConsumers); - app.post("/resume-consumers", this::handleResumeConsumers); - app.post("/start-load", this::handleStartLoad); - app.post("/adjust-publish-rate", this::handleAdjustPublishRate); - app.post("/stop-all", this::handleStopAll); - app.get("/period-stats", this::handlePeriodStats); - app.get("/cumulative-latencies", this::handleCumulativeLatencies); - app.get("/counters-stats", this::handleCountersStats); - app.post("/reset-stats", this::handleResetStats); + app.post(INITIALIZE_DRIVER, this::handleInitializeDriver); + app.post(CREATE_TOPICS, this::handleCreateTopics); + app.post(CREATE_PRODUCERS, this::handleCreateProducers); + app.post(PROBE_PRODUCERS, this::handleProbeProducers); + app.post(CREATE_CONSUMERS, this::handleCreateConsumers); + app.post(PAUSE_CONSUMERS, this::handlePauseConsumers); + app.post(RESUME_CONSUMERS, this::handleResumeConsumers); + app.post(START_LOAD, this::handleStartLoad); + app.post(ADJUST_PUBLISH_RATE, this::handleAdjustPublishRate); + app.post(STOP_ALL, this::handleStopAll); + app.get(PERIOD_STATS, this::handlePeriodStats); + app.get(CUMULATIVE_LATENCIES, this::handleCumulativeLatencies); + app.get(COUNTERS_STATS, this::handleCountersStats); + app.post(RESET_STATS, this::handleResetStats); } private void handleInitializeDriver(Context ctx) throws Exception { @@ -92,7 +96,8 @@ private void handleProbeProducers(Context ctx) throws Exception { private void handleCreateConsumers(Context ctx) throws Exception { ConsumerAssignment consumerAssignment = mapper.readValue(ctx.body(), ConsumerAssignment.class); - log.info("Received create consumers request for topics: {}", consumerAssignment.topicsSubscriptions); + log.info( + "Received create consumers request for topics: {}", consumerAssignment.topicsSubscriptions); localWorker.createConsumers(consumerAssignment); } @@ -105,9 +110,12 @@ private void handleResumeConsumers(Context ctx) throws Exception { } private void handleStartLoad(Context ctx) throws Exception { - ProducerWorkAssignment producerWorkAssignment = mapper.readValue(ctx.body(), ProducerWorkAssignment.class); + ProducerWorkAssignment producerWorkAssignment = + mapper.readValue(ctx.body(), ProducerWorkAssignment.class); - log.info("Start load publish-rate: {} msg/s -- payload-size: {}", producerWorkAssignment.publishRate, + log.info( + "Start load publish-rate: {} msg/s -- payload-size: {}", + producerWorkAssignment.publishRate, producerWorkAssignment.payloadData.get(0).length); localWorker.startLoad(producerWorkAssignment); @@ -125,45 +133,11 @@ private void handleStopAll(Context ctx) throws Exception { } private void handlePeriodStats(Context ctx) throws Exception { - PeriodStats stats = localWorker.getPeriodStats(); - - // Serialize histograms - synchronized (histogramSerializationBuffer) { - histogramSerializationBuffer.clear(); - stats.publishLatency.encodeIntoCompressedByteBuffer(histogramSerializationBuffer); - stats.publishLatencyBytes = new byte[histogramSerializationBuffer.position()]; - histogramSerializationBuffer.flip(); - histogramSerializationBuffer.get(stats.publishLatencyBytes); - - histogramSerializationBuffer.clear(); - stats.endToEndLatency.encodeIntoCompressedByteBuffer(histogramSerializationBuffer); - stats.endToEndLatencyBytes = new byte[histogramSerializationBuffer.position()]; - histogramSerializationBuffer.flip(); - histogramSerializationBuffer.get(stats.endToEndLatencyBytes); - } - - ctx.result(writer.writeValueAsString(stats)); + ctx.result(writer.writeValueAsString(localWorker.getPeriodStats())); } private void handleCumulativeLatencies(Context ctx) throws Exception { - CumulativeLatencies stats = localWorker.getCumulativeLatencies(); - - // Serialize histograms - synchronized (histogramSerializationBuffer) { - histogramSerializationBuffer.clear(); - stats.publishLatency.encodeIntoCompressedByteBuffer(histogramSerializationBuffer); - stats.publishLatencyBytes = new byte[histogramSerializationBuffer.position()]; - histogramSerializationBuffer.flip(); - histogramSerializationBuffer.get(stats.publishLatencyBytes); - - histogramSerializationBuffer.clear(); - stats.endToEndLatency.encodeIntoCompressedByteBuffer(histogramSerializationBuffer); - stats.endToEndLatencyBytes = new byte[histogramSerializationBuffer.position()]; - histogramSerializationBuffer.flip(); - histogramSerializationBuffer.get(stats.endToEndLatencyBytes); - } - - ctx.result(writer.writeValueAsString(stats)); + ctx.result(writer.writeValueAsString(localWorker.getCumulativeLatencies())); } private void handleCountersStats(Context ctx) throws Exception { @@ -175,17 +149,8 @@ private void handleResetStats(Context ctx) throws Exception { localWorker.resetStats(); } - private final ByteBuffer histogramSerializationBuffer = ByteBuffer.allocate(1024 * 1024); - private static final Logger log = LoggerFactory.getLogger(WorkerHandler.class); - private static final ObjectMapper mapper = new ObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - - static { - mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); - } - - private static final ObjectWriter writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); - + private static final ObjectMapper mapper = ObjectMappers.DEFAULT.mapper(); + private static final ObjectWriter writer = ObjectMappers.DEFAULT.writer(); } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerStats.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerStats.java new file mode 100644 index 000000000..68b9d5345 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/WorkerStats.java @@ -0,0 +1,186 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker; + + +import io.openmessaging.benchmark.worker.commands.CountersStats; +import io.openmessaging.benchmark.worker.commands.CumulativeLatencies; +import io.openmessaging.benchmark.worker.commands.PeriodStats; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.LongAdder; +import org.HdrHistogram.Recorder; +import org.apache.bookkeeper.stats.Counter; +import org.apache.bookkeeper.stats.OpStatsLogger; +import org.apache.bookkeeper.stats.StatsLogger; + +public class WorkerStats { + + private final StatsLogger statsLogger; + + private final OpStatsLogger publishDelayLatencyStats; + + private final Recorder endToEndLatencyRecorder = new Recorder(TimeUnit.HOURS.toMicros(12), 5); + private final Recorder endToEndCumulativeLatencyRecorder = + new Recorder(TimeUnit.HOURS.toMicros(12), 5); + private final OpStatsLogger endToEndLatencyStats; + + private final LongAdder messagesSent = new LongAdder(); + private final LongAdder messageSendErrors = new LongAdder(); + private final LongAdder bytesSent = new LongAdder(); + private final Counter messageSendErrorCounter; + private final Counter messagesSentCounter; + private final Counter bytesSentCounter; + + private final LongAdder messagesReceived = new LongAdder(); + private final LongAdder bytesReceived = new LongAdder(); + private final Counter messagesReceivedCounter; + private final Counter bytesReceivedCounter; + + private final LongAdder totalMessagesSent = new LongAdder(); + private final LongAdder totalMessageSendErrors = new LongAdder(); + private final LongAdder totalMessagesReceived = new LongAdder(); + + private static final long highestTrackableValue = TimeUnit.SECONDS.toMicros(60); + private final Recorder publishLatencyRecorder = new Recorder(highestTrackableValue, 5); + private final Recorder cumulativePublishLatencyRecorder = new Recorder(highestTrackableValue, 5); + private final OpStatsLogger publishLatencyStats; + + private final Recorder publishDelayLatencyRecorder = new Recorder(highestTrackableValue, 5); + private final Recorder cumulativePublishDelayLatencyRecorder = + new Recorder(highestTrackableValue, 5); + + WorkerStats(StatsLogger statsLogger) { + this.statsLogger = statsLogger; + + StatsLogger producerStatsLogger = statsLogger.scope("producer"); + this.messagesSentCounter = producerStatsLogger.getCounter("messages_sent"); + this.messageSendErrorCounter = producerStatsLogger.getCounter("message_send_errors"); + this.bytesSentCounter = producerStatsLogger.getCounter("bytes_sent"); + this.publishDelayLatencyStats = producerStatsLogger.getOpStatsLogger("producer_delay_latency"); + this.publishLatencyStats = producerStatsLogger.getOpStatsLogger("produce_latency"); + + StatsLogger consumerStatsLogger = statsLogger.scope("consumer"); + this.messagesReceivedCounter = consumerStatsLogger.getCounter("messages_recv"); + this.bytesReceivedCounter = consumerStatsLogger.getCounter("bytes_recv"); + this.endToEndLatencyStats = consumerStatsLogger.getOpStatsLogger("e2e_latency"); + } + + public StatsLogger getStatsLogger() { + return statsLogger; + } + + public void recordMessageSent() { + totalMessagesSent.increment(); + } + + public void recordMessageReceived(long payloadLength, long endToEndLatencyMicros) { + messagesReceived.increment(); + totalMessagesReceived.increment(); + messagesReceivedCounter.inc(); + bytesReceived.add(payloadLength); + bytesReceivedCounter.add(payloadLength); + + if (endToEndLatencyMicros > 0) { + endToEndCumulativeLatencyRecorder.recordValue(endToEndLatencyMicros); + endToEndLatencyRecorder.recordValue(endToEndLatencyMicros); + endToEndLatencyStats.registerSuccessfulEvent(endToEndLatencyMicros, TimeUnit.MICROSECONDS); + } + } + + public PeriodStats toPeriodStats() { + PeriodStats stats = new PeriodStats(); + + stats.messagesSent = messagesSent.sumThenReset(); + stats.messageSendErrors = messageSendErrors.sumThenReset(); + stats.bytesSent = bytesSent.sumThenReset(); + + stats.messagesReceived = messagesReceived.sumThenReset(); + stats.bytesReceived = bytesReceived.sumThenReset(); + + stats.totalMessagesSent = totalMessagesSent.sum(); + stats.totalMessageSendErrors = totalMessageSendErrors.sum(); + stats.totalMessagesReceived = totalMessagesReceived.sum(); + + stats.publishLatency = publishLatencyRecorder.getIntervalHistogram(); + stats.publishDelayLatency = publishDelayLatencyRecorder.getIntervalHistogram(); + stats.endToEndLatency = endToEndLatencyRecorder.getIntervalHistogram(); + return stats; + } + + public CumulativeLatencies toCumulativeLatencies() { + CumulativeLatencies latencies = new CumulativeLatencies(); + latencies.publishLatency = cumulativePublishLatencyRecorder.getIntervalHistogram(); + latencies.publishDelayLatency = cumulativePublishDelayLatencyRecorder.getIntervalHistogram(); + latencies.endToEndLatency = endToEndCumulativeLatencyRecorder.getIntervalHistogram(); + return latencies; + } + + public CountersStats toCountersStats() throws IOException { + CountersStats stats = new CountersStats(); + stats.messagesSent = totalMessagesSent.sum(); + stats.messageSendErrors = totalMessageSendErrors.sum(); + stats.messagesReceived = totalMessagesReceived.sum(); + return stats; + } + + public void resetLatencies() { + publishLatencyRecorder.reset(); + cumulativePublishLatencyRecorder.reset(); + publishDelayLatencyRecorder.reset(); + cumulativePublishDelayLatencyRecorder.reset(); + endToEndLatencyRecorder.reset(); + endToEndCumulativeLatencyRecorder.reset(); + } + + public void reset() { + resetLatencies(); + + messagesSent.reset(); + messageSendErrors.reset(); + bytesSent.reset(); + messagesReceived.reset(); + bytesReceived.reset(); + totalMessagesSent.reset(); + totalMessagesReceived.reset(); + } + + public void recordProducerFailure() { + messageSendErrors.increment(); + messageSendErrorCounter.inc(); + totalMessageSendErrors.increment(); + } + + public void recordProducerSuccess( + long payloadLength, long intendedSendTimeNs, long sendTimeNs, long nowNs) { + messagesSent.increment(); + totalMessagesSent.increment(); + messagesSentCounter.inc(); + bytesSent.add(payloadLength); + bytesSentCounter.add(payloadLength); + + final long latencyMicros = + Math.min(highestTrackableValue, TimeUnit.NANOSECONDS.toMicros(nowNs - sendTimeNs)); + publishLatencyRecorder.recordValue(latencyMicros); + cumulativePublishLatencyRecorder.recordValue(latencyMicros); + publishLatencyStats.registerSuccessfulEvent(latencyMicros, TimeUnit.MICROSECONDS); + + final long sendDelayMicros = + Math.min( + highestTrackableValue, TimeUnit.NANOSECONDS.toMicros(sendTimeNs - intendedSendTimeNs)); + publishDelayLatencyRecorder.recordValue(sendDelayMicros); + cumulativePublishDelayLatencyRecorder.recordValue(sendDelayMicros); + publishDelayLatencyStats.registerSuccessfulEvent(sendDelayMicros, TimeUnit.MICROSECONDS); + } +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ConsumerAssignment.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ConsumerAssignment.java index edb7961f6..9d97642ec 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ConsumerAssignment.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ConsumerAssignment.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; + import java.util.ArrayList; import java.util.List; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CountersStats.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CountersStats.java index 0d4c7e8ac..6ddc593e1 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CountersStats.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CountersStats.java @@ -1,24 +1,32 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; public class CountersStats { public long messagesSent; public long messagesReceived; + public long messageSendErrors; + + public CountersStats plus(CountersStats toAdd) { + CountersStats result = new CountersStats(); + result.messagesSent += this.messagesSent; + result.messagesReceived += this.messagesReceived; + result.messageSendErrors += this.messageSendErrors; + + result.messagesSent += toAdd.messagesSent; + result.messagesReceived += toAdd.messagesReceived; + result.messageSendErrors += toAdd.messageSendErrors; + return result; + } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CumulativeLatencies.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CumulativeLatencies.java index 7cff435ff..e9afea679 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CumulativeLatencies.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/CumulativeLatencies.java @@ -1,36 +1,40 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; -import java.util.concurrent.TimeUnit; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.SECONDS; import org.HdrHistogram.Histogram; -import com.fasterxml.jackson.annotation.JsonIgnore; - public class CumulativeLatencies { - @JsonIgnore - public Histogram publishLatency = new Histogram(TimeUnit.SECONDS.toMicros(60), 5); - public byte[] publishLatencyBytes; + public Histogram publishLatency = new Histogram(SECONDS.toMicros(60), 5); + public Histogram publishDelayLatency = new Histogram(SECONDS.toMicros(60), 5); + public Histogram endToEndLatency = new Histogram(HOURS.toMicros(12), 5); + + public CumulativeLatencies plus(CumulativeLatencies toAdd) { + CumulativeLatencies result = new CumulativeLatencies(); + + result.publishLatency.add(this.publishLatency); + result.publishDelayLatency.add(this.publishDelayLatency); + result.endToEndLatency.add(this.endToEndLatency); + + result.publishLatency.add(toAdd.publishLatency); + result.publishDelayLatency.add(toAdd.publishDelayLatency); + result.endToEndLatency.add(toAdd.endToEndLatency); - @JsonIgnore - public Histogram endToEndLatency = new Histogram(TimeUnit.HOURS.toMicros(12), 5); - public byte[] endToEndLatencyBytes; + return result; + } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/PeriodStats.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/PeriodStats.java index f5b5704ab..3f06f6925 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/PeriodStats.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/PeriodStats.java @@ -1,44 +1,66 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; -import java.util.concurrent.TimeUnit; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.SECONDS; import org.HdrHistogram.Histogram; -import com.fasterxml.jackson.annotation.JsonIgnore; - public class PeriodStats { public long messagesSent = 0; + public long messageSendErrors = 0; public long bytesSent = 0; public long messagesReceived = 0; public long bytesReceived = 0; public long totalMessagesSent = 0; + public long totalMessageSendErrors = 0; public long totalMessagesReceived = 0; - @JsonIgnore - public Histogram publishLatency = new Histogram(TimeUnit.SECONDS.toMicros(60), 5); - public byte[] publishLatencyBytes; + public Histogram publishLatency = new Histogram(SECONDS.toMicros(60), 5); + public Histogram publishDelayLatency = new Histogram(SECONDS.toMicros(60), 5); + public Histogram endToEndLatency = new Histogram(HOURS.toMicros(12), 5); + + public PeriodStats plus(PeriodStats toAdd) { + PeriodStats result = new PeriodStats(); + + result.messagesSent += this.messagesSent; + result.messageSendErrors += this.messageSendErrors; + result.bytesSent += this.bytesSent; + result.messagesReceived += this.messagesReceived; + result.bytesReceived += this.bytesReceived; + result.totalMessagesSent += this.totalMessagesSent; + result.totalMessageSendErrors += this.totalMessageSendErrors; + result.totalMessagesReceived += this.totalMessagesReceived; + result.publishLatency.add(this.publishLatency); + result.publishDelayLatency.add(this.publishDelayLatency); + result.endToEndLatency.add(this.endToEndLatency); + + result.messagesSent += toAdd.messagesSent; + result.messageSendErrors += toAdd.messageSendErrors; + result.bytesSent += toAdd.bytesSent; + result.messagesReceived += toAdd.messagesReceived; + result.bytesReceived += toAdd.bytesReceived; + result.totalMessagesSent += toAdd.totalMessagesSent; + result.totalMessageSendErrors += toAdd.totalMessageSendErrors; + result.totalMessagesReceived += toAdd.totalMessagesReceived; + result.publishLatency.add(toAdd.publishLatency); + result.publishDelayLatency.add(toAdd.publishDelayLatency); + result.endToEndLatency.add(toAdd.endToEndLatency); - @JsonIgnore - public Histogram endToEndLatency = new Histogram(TimeUnit.HOURS.toMicros(12), 5); - public byte[] endToEndLatencyBytes; + return result; + } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ProducerWorkAssignment.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ProducerWorkAssignment.java index ac8041dfb..319bd7cc8 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ProducerWorkAssignment.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/ProducerWorkAssignment.java @@ -1,32 +1,43 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; -import io.openmessaging.benchmark.utils.distributor.KeyDistributorType; +import io.openmessaging.benchmark.utils.distributor.KeyDistributorType; import java.util.List; public class ProducerWorkAssignment { - + public List payloadData; - + + /** + * Weights for weighted payload selection. If null, uniform random selection is used. + * Each weight corresponds to the payload at the same index in payloadData. + * Used for message size distribution feature. + */ + public int[] payloadWeights; + public double publishRate; public KeyDistributorType keyDistributorType; + + public ProducerWorkAssignment withPublishRate(double publishRate) { + ProducerWorkAssignment copy = new ProducerWorkAssignment(); + copy.keyDistributorType = this.keyDistributorType; + copy.payloadData = this.payloadData; + copy.payloadWeights = this.payloadWeights; + copy.publishRate = publishRate; + return copy; + } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicSubscription.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicSubscription.java index 8dc0d7d30..bd9bf9989 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicSubscription.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicSubscription.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; @@ -22,12 +17,22 @@ public class TopicSubscription { public String topic; public String subscription; - public TopicSubscription() { - } + public TopicSubscription() {} public TopicSubscription(String topic, String subscription) { this.topic = topic; this.subscription = subscription; } + @Override + public String toString() { + return "TopicSubscription{" + + "topic='" + + topic + + '\'' + + ", subscription='" + + subscription + + '\'' + + '}'; + } } diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicsInfo.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicsInfo.java index 34bc968e5..90545c725 100644 --- a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicsInfo.java +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/commands/TopicsInfo.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.worker.commands; @@ -22,8 +17,7 @@ public class TopicsInfo { public int numberOfTopics; public int numberOfPartitionsPerTopic; - public TopicsInfo() { - } + public TopicsInfo() {} public TopicsInfo(int numberOfTopics, int numberOfPartitionsPerTopic) { this.numberOfTopics = numberOfTopics; diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/HistogramDeserializer.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/HistogramDeserializer.java new file mode 100644 index 000000000..6aa562bed --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/HistogramDeserializer.java @@ -0,0 +1,61 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.jackson; + + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.util.ByteBufferBackedOutputStream; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.Unpooled; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import org.HdrHistogram.Histogram; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HistogramDeserializer extends StdDeserializer { + + private final ThreadLocal threadBuffer = + ThreadLocal.withInitial(() -> ByteBuffer.allocate(8 * 1024 * 1024)); + + public HistogramDeserializer() { + super(Histogram.class); + } + + @Override + public Histogram deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) + throws IOException, JacksonException { + ByteBuffer buffer = threadBuffer.get(); + buffer.clear(); + try (OutputStream os = new ByteBufferBackedOutputStream(buffer)) { + jsonParser.readBinaryValue(os); + buffer.flip(); + // Long.MIN_VALUE used so that Histogram will defer to the value encoded in the histogram + // value. This assumes that it is acceptable for the deserialized value we create to + // share the same parameters of the source histogram that was serialized. + return Histogram.decodeFromCompressedByteBuffer(buffer, Long.MIN_VALUE); + } catch (Exception e) { + log.error( + "Failed to decode publish delay latency: {}", + ByteBufUtil.prettyHexDump(Unpooled.wrappedBuffer(buffer))); + throw new RuntimeException(e); + } + } + + private static final Logger log = LoggerFactory.getLogger(HistogramDeserializer.class); +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/HistogramSerializer.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/HistogramSerializer.java new file mode 100644 index 000000000..c1c253f16 --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/HistogramSerializer.java @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.jackson; + + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.nio.ByteBuffer; +import org.HdrHistogram.Histogram; + +public class HistogramSerializer extends StdSerializer { + + private final ThreadLocal threadBuffer = + ThreadLocal.withInitial(() -> ByteBuffer.allocate(8 * 1024 * 1024)); + + public HistogramSerializer() { + super(Histogram.class); + } + + static byte[] toByteArray(ByteBuffer buffer) { + byte[] encodedBuffer = new byte[buffer.remaining()]; + buffer.get(encodedBuffer); + return encodedBuffer; + } + + static ByteBuffer serializeHistogram(Histogram histo, ByteBuffer buffer) { + buffer.clear(); + while (true) { + final int outBytes = histo.encodeIntoCompressedByteBuffer(buffer); + Preconditions.checkState(outBytes == buffer.position()); + final int capacity = buffer.capacity(); + if (outBytes < capacity) { + // encoding succesful + break; + } + // We filled the entire buffer, an indication that the buffer was not + // large enough, so we double the buffer and try again. + // See: https://github.com/HdrHistogram/HdrHistogram/issues/201 + buffer = ByteBuffer.allocate(capacity * 2); + } + buffer.flip(); + return buffer; + } + + @Override + public void serialize( + Histogram histogram, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + ByteBuffer buffer = threadBuffer.get(); + ByteBuffer newBuffer = serializeHistogram(histogram, buffer); + if (newBuffer != buffer) { + threadBuffer.set(newBuffer); + } + jsonGenerator.writeBinary(toByteArray(newBuffer)); + } +} diff --git a/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/ObjectMappers.java b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/ObjectMappers.java new file mode 100644 index 000000000..680a5dccc --- /dev/null +++ b/benchmark-framework/src/main/java/io/openmessaging/benchmark/worker/jackson/ObjectMappers.java @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.jackson; + + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.HdrHistogram.Histogram; + +public enum ObjectMappers { + DEFAULT; + + private static final ObjectMapper mapper = + new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + static { + mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); + SimpleModule module = new SimpleModule(); + module.addSerializer(Histogram.class, new HistogramSerializer()); + module.addDeserializer(Histogram.class, new HistogramDeserializer()); + mapper.registerModule(module); + } + + private static final ObjectWriter writer = mapper.writerWithDefaultPrettyPrinter(); + + public ObjectMapper mapper() { + return mapper; + } + + public ObjectWriter writer() { + return writer; + } +} diff --git a/benchmark-framework/src/main/resources/log4j2.yaml b/benchmark-framework/src/main/resources/log4j2.yaml index d2d565e1e..3083a28e3 100644 --- a/benchmark-framework/src/main/resources/log4j2.yaml +++ b/benchmark-framework/src/main/resources/log4j2.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # Configuration: @@ -26,13 +21,22 @@ Configuration: name: Console target: SYSTEM_OUT PatternLayout: - Pattern: "%d{HH:mm:ss.SSS} [%t] %-4level - %msg%n" - + Pattern: "%d{HH:mm:ss.SSS} [%t] %-4level %c{1} - %msg%n" + RollingFile: + name: RollingFile + fileName: benchmark-worker.log + filePattern: benchmark-worker.log.%d{yyyy-MM-dd-hh-mm-ss}.gz + PatternLayout: + Pattern: "%d{HH:mm:ss.SSS} [%t] %-4level %c{1} - %msg%n" + Policies: + SizeBasedTriggeringPolicy: + size: 100MB + DefaultRollOverStrategy: + max: 10 Loggers: Root: level: info additivity: false AppenderRef: - ref: Console - - \ No newline at end of file + - ref: Console + - ref: RollingFile diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/RateControllerTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/RateControllerTest.java new file mode 100644 index 000000000..6f014f019 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/RateControllerTest.java @@ -0,0 +1,70 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class RateControllerTest { + private final RateController rateController = new RateController(); + private double rate = 10_000; + private long periodNanos = SECONDS.toNanos(1); + + @Test + void receiveBacklog() { + assertThat(rateController.getRampingFactor()).isEqualTo(1); + + // no backlog + rate = rateController.nextRate(rate, periodNanos, 10_000, 10_000); + assertThat(rate).isEqualTo(20_000); + assertThat(rateController.getRampingFactor()).isEqualTo(1); + + // receive backlog + rate = rateController.nextRate(rate, periodNanos, 20_000, 15_000); + assertThat(rate).isEqualTo(5_000); + assertThat(rateController.getRampingFactor()).isEqualTo(0.5); + } + + @Test + void publishBacklog() { + assertThat(rateController.getRampingFactor()).isEqualTo(1); + + // no backlog + rate = rateController.nextRate(rate, periodNanos, 10_000, 10_000); + assertThat(rate).isEqualTo(20_000); + assertThat(rateController.getRampingFactor()).isEqualTo(1); + + // publish backlog + rate = rateController.nextRate(rate, periodNanos, 15_000, 20_000); + assertThat(rate).isEqualTo(5_000); + assertThat(rateController.getRampingFactor()).isEqualTo(0.5); + } + + @Test + void rampUp() { + assertThat(rateController.getRampingFactor()).isEqualTo(1); + + // receive backlog + rate = rateController.nextRate(rate, periodNanos, 10_000, 5_000); + assertThat(rate).isEqualTo(5_000); + assertThat(rateController.getRampingFactor()).isEqualTo(0.5); + + // no backlog + rate = rateController.nextRate(rate, periodNanos, 20_000, 20_000); + assertThat(rate).isEqualTo(10_000); + assertThat(rateController.getRampingFactor()).isEqualTo(1); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/EnvTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/EnvTest.java new file mode 100644 index 000000000..cf62b85dd --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/EnvTest.java @@ -0,0 +1,59 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + +import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class EnvTest { + private static final String ENV_KEY = "KEY"; + + @Test + void envLong() throws Exception { + withEnvironmentVariable(ENV_KEY, "2") + .execute( + () -> { + assertThat(Env.getLong(ENV_KEY, 1)).isEqualTo(2); + }); + } + + @Test + void envLongDefault() throws Exception { + withEnvironmentVariable(ENV_KEY, null) + .execute( + () -> { + assertThat(Env.getLong(ENV_KEY, 1)).isEqualTo(1); + }); + } + + @Test + void envDouble() throws Exception { + withEnvironmentVariable(ENV_KEY, "2.34") + .execute( + () -> { + assertThat(Env.getDouble(ENV_KEY, 1.23)).isEqualTo(2.34); + }); + } + + @Test + void envDoubleDefault() throws Exception { + withEnvironmentVariable(ENV_KEY, null) + .execute( + () -> { + assertThat(Env.getDouble(ENV_KEY, 1.23)).isEqualTo(1.23); + }); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/ListPartitionTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/ListPartitionTest.java new file mode 100644 index 000000000..a7472df95 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/ListPartitionTest.java @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class ListPartitionTest { + + @Test + void partitionList() { + List list = asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + List> lists = ListPartition.partitionList(list, 3); + assertThat(lists) + .satisfies( + s -> { + assertThat(s).hasSize(3); + assertThat(s.get(0)).isEqualTo(asList(1, 4, 7, 10)); + assertThat(s.get(1)).isEqualTo(asList(2, 5, 8)); + assertThat(s.get(2)).isEqualTo(asList(3, 6, 9)); + }); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/PaddingDecimalFormatTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/PaddingDecimalFormatTest.java new file mode 100644 index 000000000..be1b9a532 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/PaddingDecimalFormatTest.java @@ -0,0 +1,29 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class PaddingDecimalFormatTest { + + @Test + void format() { + PaddingDecimalFormat format = new PaddingDecimalFormat("0.0", 7); + assertThat(format.format(1L)).isEqualTo(" 1.0"); + assertThat(format.format(1000L)).isEqualTo(" 1000.0"); + assertThat(format.format(10000000L)).isEqualTo("10000000.0"); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/TimerTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/TimerTest.java new file mode 100644 index 000000000..87004e332 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/TimerTest.java @@ -0,0 +1,42 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.function.Supplier; +import org.junit.jupiter.api.Test; + +class TimerTest { + + @Test + void elapsedMillis() { + Supplier mockClock = mock(Supplier.class); + when(mockClock.get()).thenReturn(MILLISECONDS.toNanos(1), MILLISECONDS.toNanos(3)); + Timer timer = new Timer(mockClock); + assertThat(timer.elapsedMillis()).isEqualTo(2.0d); + } + + @Test + void elapsedSeconds() { + Supplier mockClock = mock(Supplier.class); + when(mockClock.get()).thenReturn(SECONDS.toNanos(1), SECONDS.toNanos(3)); + Timer timer = new Timer(mockClock); + assertThat(timer.elapsedSeconds()).isEqualTo(2.0d); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/UniformRateLimiterTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/UniformRateLimiterTest.java new file mode 100644 index 000000000..a9b90462e --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/UniformRateLimiterTest.java @@ -0,0 +1,66 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.function.Supplier; +import org.junit.jupiter.api.Test; + +class UniformRateLimiterTest { + + @Test + void getOpsPerSec() { + assertThat(new UniformRateLimiter(1000).getOpsPerSec()).isEqualTo(1000.0d); + } + + @Test + void getIntervalNs() { + assertThat(new UniformRateLimiter(1000).getIntervalNs()).isEqualTo(SECONDS.toNanos(1) / 1000); + } + + @Test + void acquireSlowSingleThread() { + Supplier mockClock = mock(Supplier.class); + when(mockClock.get()).thenReturn(SECONDS.toNanos(2)); + UniformRateLimiter rateLimiter = new UniformRateLimiter(1000, mockClock); + assertThat(rateLimiter.acquire()).isEqualTo(2000000000L); + assertThat(rateLimiter.acquire()).isEqualTo(2001000000L); + assertThat(rateLimiter.acquire()).isEqualTo(2002000000L); + } + + @Test + void uninterruptibleSleepNs() { + long start = System.nanoTime(); + long expectedEnd = start + MILLISECONDS.toNanos(100); + UniformRateLimiter.uninterruptibleSleepNs(expectedEnd); + long end = System.nanoTime(); + assertThat(end).isGreaterThan(expectedEnd); + } + + @Test + void cinitExceptions() { + assertThatCode(() -> new UniformRateLimiter(Double.NaN)) + .isInstanceOf(IllegalArgumentException.class); + assertThatCode(() -> new UniformRateLimiter(1.0d / 0.0d)) + .isInstanceOf(IllegalArgumentException.class); + assertThatCode(() -> new UniformRateLimiter(-0.1)).isInstanceOf(IllegalArgumentException.class); + assertThatCode(() -> new UniformRateLimiter(0.0)).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/payload/MessageSizeDistributionTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/payload/MessageSizeDistributionTest.java new file mode 100644 index 000000000..affa77536 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/utils/payload/MessageSizeDistributionTest.java @@ -0,0 +1,222 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.utils.payload; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class MessageSizeDistributionTest { + + @Test + void parsesBasicRanges() { + Map config = new LinkedHashMap<>(); + config.put("0-256", 100); + config.put("256-1024", 200); + config.put("1024-4096", 300); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + + assertThat(dist.getBucketCount()).isEqualTo(3); + assertThat(dist.getTotalWeight()).isEqualTo(600); + } + + @Test + void parsesSizeSuffixes() { + Map config = new LinkedHashMap<>(); + config.put("0-1KB", 100); + config.put("1KB-1MB", 200); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + List sizes = dist.getBucketSizes(); + + // Midpoint of 0-1024 = 512 + assertThat(sizes.get(0)).isEqualTo(512); + // Midpoint of 1024-1048576 = 524800 + assertThat(sizes.get(1)).isEqualTo(524800); + } + + @Test + void calculatesBucketSizesAsMidpoint() { + Map config = new LinkedHashMap<>(); + config.put("0-100", 1); + config.put("100-200", 1); + config.put("200-300", 1); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + List sizes = dist.getBucketSizes(); + + assertThat(sizes).containsExactly(50, 150, 250); + } + + @Test + void calculatesWeightsArray() { + Map config = new LinkedHashMap<>(); + config.put("0-256", 234); + config.put("256-1024", 456); + config.put("1024-4096", 678); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + int[] weights = dist.getWeights(); + + assertThat(weights).containsExactly(234, 456, 678); + } + + @Test + void calculatesCumulativeWeights() { + Map config = new LinkedHashMap<>(); + config.put("0-256", 100); + config.put("256-1024", 200); + config.put("1024-4096", 300); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + int[] cumulative = dist.getCumulativeWeights(); + + assertThat(cumulative).containsExactly(100, 300, 600); + } + + @Test + void calculatesAverageSize() { + Map config = new LinkedHashMap<>(); + config.put("0-100", 1); // midpoint 50, weight 1 + config.put("100-200", 1); // midpoint 150, weight 1 + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + + // (50 * 1 + 150 * 1) / 2 = 100 + assertThat(dist.getAvgSize()).isEqualTo(100); + } + + @Test + void calculatesMaxSize() { + Map config = new LinkedHashMap<>(); + config.put("0-256", 100); + config.put("256-1024", 200); + config.put("1024-5000", 300); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + + assertThat(dist.getMaxSize()).isEqualTo(5000); + } + + @Test + void handlesProductionDistribution() { + // Real production distribution from the plan + Map config = new LinkedHashMap<>(); + config.put("0-256", 234); + config.put("256-1024", 456); + config.put("1024-4096", 678); + config.put("4096-16384", 312); + config.put("16384-65536", 98); + config.put("65536-262144", 45); + config.put("262144-1048576", 18); + config.put("1048576-5242880", 6); + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + + assertThat(dist.getBucketCount()).isEqualTo(8); + assertThat(dist.getTotalWeight()).isEqualTo(1847); + assertThat(dist.getMaxSize()).isEqualTo(5242880); // 5MB + assertThat(dist.getBucketSizes()).hasSize(8); + assertThat(dist.getWeights()).hasSize(8); + } + + @Test + void throwsOnEmptyConfig() { + assertThatThrownBy(() -> new MessageSizeDistribution(new HashMap<>())) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void throwsOnNullConfig() { + assertThatThrownBy(() -> new MessageSizeDistribution(null)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void throwsOnInvalidRangeFormat() { + Map config = new HashMap<>(); + config.put("invalid", 100); + + assertThatThrownBy(() -> new MessageSizeDistribution(config)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void throwsOnNegativeWeight() { + Map config = new HashMap<>(); + config.put("0-100", -1); + + assertThatThrownBy(() -> new MessageSizeDistribution(config)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void throwsOnZeroTotalWeight() { + Map config = new HashMap<>(); + config.put("0-100", 0); + config.put("100-200", 0); + + assertThatThrownBy(() -> new MessageSizeDistribution(config)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void throwsOnInvalidMinMax() { + Map config = new HashMap<>(); + config.put("200-100", 1); // max < min + + assertThatThrownBy(() -> new MessageSizeDistribution(config)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void weightedSelectionProducesCorrectDistribution() { + Map config = new LinkedHashMap<>(); + config.put("0-100", 100); // 50% weight + config.put("100-200", 100); // 50% weight + + MessageSizeDistribution dist = new MessageSizeDistribution(config); + int[] cumulative = dist.getCumulativeWeights(); + int totalWeight = dist.getTotalWeight(); + + // Simulate weighted selection like LocalWorker does + int[] counts = new int[2]; + int iterations = 100000; + + for (int i = 0; i < iterations; i++) { + int target = i % totalWeight; // Deterministic for testing + int idx = Arrays.binarySearch(cumulative, target + 1); + if (idx < 0) { + idx = -idx - 1; + } + idx = Math.min(idx, 1); + counts[idx]++; + } + + // Each bucket should get approximately 50% of selections + double ratio0 = (double) counts[0] / iterations; + double ratio1 = (double) counts[1] / iterations; + + assertThat(ratio0).isBetween(0.49, 0.51); + assertThat(ratio1).isBetween(0.49, 0.51); + } +} + diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsembleTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsembleTest.java new file mode 100644 index 000000000..c6f4805a1 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/DistributedWorkersEnsembleTest.java @@ -0,0 +1,56 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class DistributedWorkersEnsembleTest { + + @ParameterizedTest + @MethodSource("producerCountExpectations") + void getNumberOfProducerWorkers(int workerCount, boolean extraConsumers, int expected) { + List workers = mock(List.class); + when(workers.size()).thenReturn(workerCount); + assertThat(DistributedWorkersEnsemble.getNumberOfProducerWorkers(workers, extraConsumers)) + .isEqualTo(expected); + } + + private static Stream producerCountExpectations() { + return Stream.of( + Arguments.of(2, true, 1), + Arguments.of(3, true, 1), + Arguments.of(4, true, 2), + Arguments.of(5, true, 2), + Arguments.of(6, true, 2), + Arguments.of(7, true, 3), + Arguments.of(8, true, 3), + Arguments.of(9, true, 3), + Arguments.of(2, false, 1), + Arguments.of(3, false, 1), + Arguments.of(4, false, 2), + Arguments.of(5, false, 2), + Arguments.of(6, false, 3), + Arguments.of(7, false, 3), + Arguments.of(8, false, 4), + Arguments.of(9, false, 4)); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/CountersStatsTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/CountersStatsTest.java new file mode 100644 index 000000000..699304de0 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/CountersStatsTest.java @@ -0,0 +1,60 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.commands; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class CountersStatsTest { + + @Test + void plus() { + CountersStats one = new CountersStats(); + one.messagesSent = 1; + one.messageSendErrors = 10; + one.messagesReceived = 100; + CountersStats two = new CountersStats(); + two.messagesSent = 2; + two.messageSendErrors = 20; + two.messagesReceived = 200; + + CountersStats result = one.plus(two); + assertThat(result) + .satisfies( + r -> { + assertThat(r.messagesSent).isEqualTo(3); + assertThat(r.messageSendErrors).isEqualTo(30); + assertThat(r.messagesReceived).isEqualTo(300); + }); + } + + @Test + void zeroPlus() { + CountersStats zero = new CountersStats(); + CountersStats two = new CountersStats(); + two.messagesSent = 2; + two.messageSendErrors = 20; + two.messagesReceived = 200; + + CountersStats result = zero.plus(two); + assertThat(result) + .satisfies( + r -> { + assertThat(r.messagesSent).isEqualTo(2); + assertThat(r.messageSendErrors).isEqualTo(20); + assertThat(r.messagesReceived).isEqualTo(200); + }); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/CumulativeLatenciesTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/CumulativeLatenciesTest.java new file mode 100644 index 000000000..5919739ff --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/CumulativeLatenciesTest.java @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.commands; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class CumulativeLatenciesTest { + + @Test + void zeroPlus() { + CumulativeLatencies one = new CumulativeLatencies(); + CumulativeLatencies two = new CumulativeLatencies(); + CumulativeLatencies result = one.plus(two); + assertThat(result) + .satisfies( + r -> { + assertThat(r.publishLatency).isEqualTo(two.publishLatency); + assertThat(r.publishDelayLatency).isEqualTo(two.publishDelayLatency); + assertThat(r.endToEndLatency).isEqualTo(two.endToEndLatency); + }); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/PeriodStatsTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/PeriodStatsTest.java new file mode 100644 index 000000000..01c3e04b5 --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/commands/PeriodStatsTest.java @@ -0,0 +1,95 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.commands; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class PeriodStatsTest { + + @Test + void plus() { + PeriodStats one = new PeriodStats(); + one.messagesSent = 1; + one.messageSendErrors = 2; + one.bytesSent = 3; + one.messagesReceived = 4; + one.bytesReceived = 5; + one.totalMessagesSent = 6; + one.totalMessageSendErrors = 7; + one.totalMessagesReceived = 8; + PeriodStats two = new PeriodStats(); + two.messagesSent = 10; + two.messageSendErrors = 20; + two.bytesSent = 30; + two.messagesReceived = 40; + two.bytesReceived = 50; + two.totalMessagesSent = 60; + two.totalMessageSendErrors = 70; + two.totalMessagesReceived = 80; + PeriodStats result = one.plus(two); + assertThat(result) + .satisfies( + r -> { + assertThat(r.messagesSent).isEqualTo(11); + assertThat(r.messageSendErrors).isEqualTo(22); + assertThat(r.bytesSent).isEqualTo(33); + assertThat(r.messagesReceived).isEqualTo(44); + assertThat(r.bytesReceived).isEqualTo(55); + assertThat(r.totalMessagesSent).isEqualTo(66); + assertThat(r.totalMessageSendErrors).isEqualTo(77); + assertThat(r.totalMessagesReceived).isEqualTo(88); + + two.publishLatency.add(one.publishLatency); + two.publishDelayLatency.add(one.publishDelayLatency); + two.endToEndLatency.add(one.endToEndLatency); + + assertThat(r.publishLatency).isEqualTo(two.publishLatency); + assertThat(r.publishDelayLatency).isEqualTo(two.publishDelayLatency); + assertThat(r.endToEndLatency).isEqualTo(two.endToEndLatency); + }); + } + + @Test + void zeroPlus() { + PeriodStats one = new PeriodStats(); + PeriodStats two = new PeriodStats(); + two.messagesSent = 10; + two.messageSendErrors = 20; + two.bytesSent = 30; + two.messagesReceived = 40; + two.bytesReceived = 50; + two.totalMessagesSent = 60; + two.totalMessageSendErrors = 70; + two.totalMessagesReceived = 80; + PeriodStats result = one.plus(two); + assertThat(result) + .satisfies( + r -> { + assertThat(r.messagesSent).isEqualTo(10); + assertThat(r.messageSendErrors).isEqualTo(20); + assertThat(r.bytesSent).isEqualTo(30); + assertThat(r.messagesReceived).isEqualTo(40); + assertThat(r.bytesReceived).isEqualTo(50); + assertThat(r.totalMessagesSent).isEqualTo(60); + assertThat(r.totalMessageSendErrors).isEqualTo(70); + assertThat(r.totalMessagesReceived).isEqualTo(80); + + assertThat(r.publishLatency).isEqualTo(two.publishLatency); + assertThat(r.publishDelayLatency).isEqualTo(two.publishDelayLatency); + assertThat(r.endToEndLatency).isEqualTo(two.endToEndLatency); + }); + } +} diff --git a/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/jackson/HistogramSerDeTest.java b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/jackson/HistogramSerDeTest.java new file mode 100644 index 000000000..9769eac6f --- /dev/null +++ b/benchmark-framework/src/test/java/io/openmessaging/benchmark/worker/jackson/HistogramSerDeTest.java @@ -0,0 +1,106 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.worker.jackson; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Random; +import org.HdrHistogram.Histogram; +import org.junit.jupiter.api.Test; + +class HistogramSerDeTest { + + @Test + void deserialize() throws IOException { + Histogram value = new Histogram(100_000, 3); + value.recordValue(1); + value.recordValue(100); + value.recordValue(10_000); + + ObjectMapper mapper = new ObjectMapper(); + SimpleModule module = new SimpleModule(); + module.addSerializer(Histogram.class, new HistogramSerializer()); + module.addDeserializer(Histogram.class, new HistogramDeserializer()); + mapper.registerModule(module); + + byte[] serialized = mapper.writeValueAsBytes(value); + Histogram deserialized = mapper.readValue(serialized, Histogram.class); + + assertThat(deserialized).isEqualTo(value); + } + + /** + * Create a random histogram and insert the given number of samples. + * + * @param samples the number of samples to record into the histogram + * @return a Histogram with the given number of samples + */ + private Histogram randomHisto(int samples) { + Random r = new Random(0xBADBEEF); + Histogram h = new org.HdrHistogram.Histogram(5); + for (int i = 0; i < samples; i++) { + h.recordValue(r.nextInt(10000000)); + } + + return h; + } + + byte[] serializeRandomHisto(int samples, int initialBufferSize) throws Exception { + ByteBuffer inbuffer = ByteBuffer.allocate(initialBufferSize); + Histogram inHisto = randomHisto(samples); + byte[] serialBytes = + HistogramSerializer.toByteArray(HistogramSerializer.serializeHistogram(inHisto, inbuffer)); + + // check roundtrip + Histogram outHisto = + Histogram.decodeFromCompressedByteBuffer(ByteBuffer.wrap(serialBytes), Long.MIN_VALUE); + assertThat(inHisto).isEqualTo(outHisto); + + return serialBytes; + } + + @Test + public void testHistogram() throws Exception { + + // in the worker it's 8 MB but it takes a while to make a histogram that big + final int bufSize = 1002; + + int samples = 300; + + // we do an exponential search to fit the crossover point where we need to grow the buffer + while (true) { + byte[] serialBytes = serializeRandomHisto(samples, bufSize); + // System.out.println("Samples: " + samples + ", histogram size: " + serialBytes.length); + if (serialBytes.length >= bufSize) { + break; + } + samples *= 1.05; + } + + // then walk backwards across the point linearly with increment of 1 to check the boundary + // carefully + while (true) { + samples--; + byte[] serialBytes = serializeRandomHisto(samples, bufSize); + // System.out.println("Samples: " + samples + ", histogram size: " + serialBytes.length); + if (serialBytes.length < bufSize - 10) { + break; + } + } + } +} diff --git a/benchmark-framework/src/test/resources/log4j2.yaml b/benchmark-framework/src/test/resources/log4j2.yaml new file mode 100644 index 000000000..7ed3f311f --- /dev/null +++ b/benchmark-framework/src/test/resources/log4j2.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Configuration: + status: INFO + name: messaging-benchmark + + Appenders: + Console: + name: Console + target: SYSTEM_OUT + PatternLayout: + Pattern: "%d{HH:mm:ss.SSS} [%t] %-4level %c{1} - %msg%n" + Loggers: + Logger: + - name: io.openmessaging + level: debug + Root: + level: info + additivity: false + AppenderRef: + - ref: Console diff --git a/bin/benchmark b/bin/benchmark index c5452d973..555893496 100755 --- a/bin/benchmark +++ b/bin/benchmark @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # if [ -d "./lib" ]; then @@ -32,4 +27,4 @@ fi JVM_MEM="${HEAP_OPTS} -XX:+UseG1GC" JVM_GC_LOG=" -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=64m -Xloggc:/dev/shm/benchmark-client-gc_%p.log" -java -server -cp $CLASSPATH $JVM_MEM io.openmessaging.benchmark.Benchmark $* +java -server -cp $CLASSPATH $JVM_MEM io.openmessaging.benchmark.Benchmark "$@" diff --git a/bin/benchmark-worker b/bin/benchmark-worker index 8447a4cc0..164f45b80 100755 --- a/bin/benchmark-worker +++ b/bin/benchmark-worker @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # if [ -d "./lib" ]; then @@ -31,5 +26,12 @@ fi JVM_MEM="${HEAP_OPTS} -XX:+UseG1GC" JVM_GC_LOG=" -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=64m -Xloggc:/dev/shm/benchmark-client-gc_%p.log" - -exec java -server -cp $CLASSPATH $JVM_MEM io.openmessaging.benchmark.worker.BenchmarkWorker $* +# Required by Netty for optimized direct byte buffer access +JVM_OPTS="$JVM_OPTS -Dio.netty.tryReflectionSetAccessible=true" +JVM_OPTS="$JVM_OPTS --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED" +# Set io.netty.tryReflectionSetAccessible in Pulsar's shaded client +JVM_OPTS="$JVM_OPTS -Dorg.apache.pulsar.shade.io.netty.tryReflectionSetAccessible=true" +# Required by Pulsar client optimized checksum calculation on other than Linux x86_64 platforms +# reflection access to java.util.zip.CRC32C +JVM_OPTS="$JVM_OPTS --add-opens java.base/java.util.zip=ALL-UNNAMED" +exec java -server -cp $CLASSPATH $JVM_MEM $JVM_OPTS io.openmessaging.benchmark.worker.BenchmarkWorker "$@" \ No newline at end of file diff --git a/bin/create_charts.py b/bin/create_charts.py index 54391abd1..909051620 100755 --- a/bin/create_charts.py +++ b/bin/create_charts.py @@ -1,21 +1,16 @@ #!/usr/bin/env python # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -43,10 +38,18 @@ def create_charts(test_results): y_label='Latency (ms)', time_series=[(x['driver'], x['publishLatency99pct']) for x in results]) + create_chart(workload, 'Publish Delay latency 99pct', + y_label='Latency (us)', + time_series=[(x['driver'], x['publishDelayLatency99pct']) for x in results]) + create_chart(workload, 'Publish rate', y_label='Rate (msg/s)', time_series=[(x['driver'], x['publishRate']) for x in results]) + create_chart(workload, 'Publish Error rate', + y_label='Rate (err/s)', + time_series=[(x['driver'], x['publishErrorRate']) for x in results]) + create_chart(workload, 'End To End Latency 95pct', y_label='Latency (ms)', time_series=[(x['driver'], x['endToEndLatency95pct']) for x in results]) @@ -63,6 +66,10 @@ def create_charts(test_results): y_label='Latency (ms)', time_series=[(x['driver'], x['aggregatedPublishLatencyQuantiles']) for x in results]) + create_quantile_chart(workload, 'Publish Delay Latency Quantiles', + y_label='Latency (us)', + time_series=[(x['driver'], x['aggregatedPublishDelayLatencyQuantiles']) for x in results]) + create_quantile_chart(workload, 'End To End Latency Quantiles', y_label='Latency (ms)', time_series=[(x['driver'], x['aggregatedEndToEndLatencyQuantiles']) for x in results]) diff --git a/deployment/kubernetes/helm/README.md b/deployment/kubernetes/helm/README.md index ac43ac652..f8ef3125a 100644 --- a/deployment/kubernetes/helm/README.md +++ b/deployment/kubernetes/helm/README.md @@ -1,11 +1,10 @@ - Users can deploy the helm chart: ```bash $ helm install ./benchmark --name benchmark ``` -After the chart has started, users can exec into the pod name "benchmark-driver" and run the benchmark from there. +After the chart has started, users can exec into the pod name "benchmark-driver" and run the benchmark from there. For example, once inside the "benchmark-driver" pod, users can execute: diff --git a/deployment/kubernetes/helm/benchmark/Chart.yaml b/deployment/kubernetes/helm/benchmark/Chart.yaml index a1dcacefd..85d0c9556 100644 --- a/deployment/kubernetes/helm/benchmark/Chart.yaml +++ b/deployment/kubernetes/helm/benchmark/Chart.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # apiVersion: v1 diff --git a/deployment/kubernetes/helm/benchmark/templates/benchmark-worker.yaml b/deployment/kubernetes/helm/benchmark/templates/benchmark-worker.yaml index bd77b7fba..250169401 100644 --- a/deployment/kubernetes/helm/benchmark/templates/benchmark-worker.yaml +++ b/deployment/kubernetes/helm/benchmark/templates/benchmark-worker.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # apiVersion: apps/v1 diff --git a/deployment/kubernetes/helm/benchmark/templates/benchmark.yaml b/deployment/kubernetes/helm/benchmark/templates/benchmark.yaml index aa440dc3a..4310b79e8 100644 --- a/deployment/kubernetes/helm/benchmark/templates/benchmark.yaml +++ b/deployment/kubernetes/helm/benchmark/templates/benchmark.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # apiVersion: v1 @@ -40,7 +35,7 @@ spec: - name: WORKERS value: '{{ template "workers" .Values }}' - name: HEAP_OPTS - value: 'Xms4G -Xmx4G' + value: '-Xms4G -Xmx4G' command: ["sh", "-c"] args: - > diff --git a/deployment/kubernetes/helm/benchmark/values.yaml b/deployment/kubernetes/helm/benchmark/values.yaml index aee1f260f..e4963a2bd 100644 --- a/deployment/kubernetes/helm/benchmark/values.yaml +++ b/deployment/kubernetes/helm/benchmark/values.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # numWorkers: 8 diff --git a/dev/license-header.txt b/dev/license-header.txt deleted file mode 100644 index 60b675e31..000000000 --- a/dev/license-header.txt +++ /dev/null @@ -1,16 +0,0 @@ -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. diff --git a/docker/Dockerfile b/docker/Dockerfile index e1af6fa52..243487eb9 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,28 +1,31 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # -FROM openjdk:8-jdk +FROM eclipse-temurin:17 ARG BENCHMARK_TARBALL +# Using ADD instead of COPY because ${BENCHMARK_TARBALL} is an archive that needs to be extracted ADD ${BENCHMARK_TARBALL} / RUN mv openmessaging-benchmark-* /benchmark WORKDIR /benchmark + +# Install vim +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y vim tzdata && rm -rf /var/lib/apt/lists/* + +# Start a shell by default +CMD ["/bin/bash"] diff --git a/docker/Dockerfile.build b/docker/Dockerfile.build index 79c0520c9..d3b3129f9 100644 --- a/docker/Dockerfile.build +++ b/docker/Dockerfile.build @@ -1,31 +1,33 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Build the Project -FROM maven:latest as build +FROM maven:3.9.9-eclipse-temurin-17 as build COPY . /benchmark WORKDIR /benchmark RUN mvn install # Create the benchmark image -FROM openjdk:8-jdk +FROM eclipse-temurin:17 COPY --from=build /benchmark/package/target/openmessaging-benchmark-*-SNAPSHOT-bin.tar.gz / RUN mkdir /benchmark && tar -xzf openmessaging-benchmark-*-SNAPSHOT-bin.tar.gz -C /benchmark --strip=1 RUN rm /openmessaging-benchmark-*-SNAPSHOT-bin.tar.gz -WORKDIR /benchmark \ No newline at end of file +WORKDIR /benchmark + +# Install vim +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y vim tzdata && rm -rf /var/lib/apt/lists/* + +# Start a shell by default +CMD ["/bin/bash"] diff --git a/docker/README.md b/docker/README.md index 1cefa026d..df4a283f2 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,18 +1,48 @@ # OpenMessaging Benchmark Framework Docker -You can use either of the Dockerfiles - `./docker/Dockerfile` or `./docker/Dockerfile.build` based on your needs. + +## Precondition + +You need to install [Eclipse Temurin 17](https://adoptium.net/) (or 21) +and set the JAVA_HOME environment variable to its installation directory. + +## Building the image + +You can use one of the Dockerfiles based on your needs: + +- `Dockerfile` - requires local build first +- `Dockerfile.build` - builds inside Docker (JDK 17 only) +- `Dockerfile.builder` - **recommended** - multi-JDK support (17 and 21) + +### `Dockerfile.builder` (Recommended) + +Supports both JDK 17 and JDK 21. Skips formatting checks that can have +JDK version incompatibilities in container environments. + +```bash +# Build with JDK 17 (default) +docker build -t omb-benchmark:jdk17 -f docker/Dockerfile.builder . + +# Build with JDK 21 +docker build -t omb-benchmark:jdk21 --build-arg JDK_VERSION=21 -f docker/Dockerfile.builder . +``` ### `Dockerfile` -Uses `openjdk-8` and takes `BENCHMARK_TARBALL` as an argument. + +Uses `eclipse-temurin:17` and takes `BENCHMARK_TARBALL` as an argument. While using this Dockerfile, you will need to build the project locally **first**. -``` -#> mvn build -#> export BENCHMARK_TARBALL=package/target/openmessaging-benchmark--SNAPSHOT-bin.tar.gz -#> docker build --build-arg BENCHMARK_TARBALL . -f docker/Dockerfile + +```bash +mvn install -DskipTests +export BENCHMARK_TARBALL=package/target/openmessaging-benchmark--SNAPSHOT-bin.tar.gz +docker build -t openmessaging-benchmark:latest --build-arg BENCHMARK_TARBALL . -f docker/Dockerfile ``` ### `Dockerfile.build` -Uses the latest version of `maven` in order to build the project, and then use `openjdk-8` as runtime. -This Dockerfile has no dependency (you do not need Mavent to be installed locally). + +Uses Maven to build the project inside Docker, then uses `eclipse-temurin:17` as runtime. +This Dockerfile has no local dependency (you do not need Maven installed locally). + +```bash +docker build -t openmessaging-benchmark:latest . -f docker/Dockerfile.build ``` -#> docker build . -f docker/Dockerfile.build -``` \ No newline at end of file + diff --git a/docker/pom.xml b/docker/pom.xml index 3b72c5261..6f9925976 100644 --- a/docker/pom.xml +++ b/docker/pom.xml @@ -1,36 +1,32 @@ + + 4.0.0 - messaging-benchmark io.openmessaging.benchmark + messaging-benchmark 0.0.1-SNAPSHOT - 4.0.0 messaging-benchmark-docker + pom Open Messaging Benchmark Docker Image - pom 1.3.7 @@ -57,6 +53,14 @@ com.spotify dockerfile-maven-plugin ${dockerfile-maven.version} + + ${docker.organization}/openmessaging-benchmark + false + ${project.version} + + target/package-${project.version}-bin.tar.gz + + default @@ -85,14 +89,6 @@ - - ${docker.organization}/openmessaging-benchmark - false - ${project.version} - - target/package-${project.version}-bin.tar.gz - - org.apache.maven.plugins diff --git a/driver-api/pom.xml b/driver-api/pom.xml index 1f1cc7942..cbf66b392 100644 --- a/driver-api/pom.xml +++ b/driver-api/pom.xml @@ -1,40 +1,55 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + - driver-api + driver-api - - - org.apache.bookkeeper.stats - bookkeeper-stats-api - ${bookkeeper.version} - - - \ No newline at end of file + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + + + org.apache.bookkeeper.stats + bookkeeper-stats-api + ${bookkeeper.version} + + + org.projectlombok + lombok + + + diff --git a/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkConsumer.java b/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkConsumer.java index 0499767d6..a8e745e88 100644 --- a/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkConsumer.java +++ b/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkConsumer.java @@ -1,23 +1,16 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver; -public interface BenchmarkConsumer extends AutoCloseable { - -} +public interface BenchmarkConsumer extends AutoCloseable {} diff --git a/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkDriver.java b/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkDriver.java index 45f20ff1a..88c5814aa 100644 --- a/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkDriver.java +++ b/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkDriver.java @@ -1,72 +1,143 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver; +import static java.util.stream.Collectors.toList; + import java.io.File; import java.io.IOException; +import java.util.List; import java.util.concurrent.CompletableFuture; +import lombok.Value; import org.apache.bookkeeper.stats.StatsLogger; -/** - * Base driver interface - */ +/** Base driver interface. */ public interface BenchmarkDriver extends AutoCloseable { /** - * Driver implementation can use this method to initialize the client libraries, with the provided configuration - * file. - *

- * The format of the configuration file is specific to the driver implementation. - * + * Driver implementation can use this method to initialize the client libraries, with the provided + * configuration file. + * + *

The format of the configuration file is specific to the driver implementation. + * * @param configurationFile * @param statsLogger stats logger to collect stats from benchmark driver * @throws IOException */ - void initialize(File configurationFile, StatsLogger statsLogger) throws IOException; + void initialize(File configurationFile, StatsLogger statsLogger) + throws IOException, InterruptedException; /** - * Get a driver specific prefix to be used in creating multiple topic names + * Get a driver specific prefix to be used in creating multiple topic names. + * + * @return the topic name prefix */ String getTopicNamePrefix(); /** - * Create a new topic with a given number of partitions + * Create a new topic with a given number of partitions. + * + * @param topic + * @param partitions + * @return a future the completes when the topic is created */ CompletableFuture createTopic(String topic, int partitions); /** - * Create a producer for a given topic + * Create a list of new topics with the given number of partitions. + * + * @param topicInfos + * @return a future the completes when the topics are created + */ + default CompletableFuture createTopics(List topicInfos) { + @SuppressWarnings("unchecked") + CompletableFuture[] futures = + topicInfos.stream() + .map(topicInfo -> createTopic(topicInfo.getTopic(), topicInfo.getPartitions())) + .toArray(CompletableFuture[]::new); + return CompletableFuture.allOf(futures); + } + + /** + * Create a producer for a given topic. + * + * @param topic + * @return a producer future */ CompletableFuture createProducer(String topic); + /** + * Create a producers for a given topic. + * + * @param producers + * @return a producers future + */ + default CompletableFuture> createProducers(List producers) { + List> futures = + producers.stream().map(ci -> createProducer(ci.getTopic())).collect(toList()); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream().map(CompletableFuture::join).collect(toList())); + } + /** * Create a benchmark consumer relative to one particular topic and subscription. - * - * It is responsibility of the driver implementation to invoke the consumerCallback each time a message - * is received. - * + * + *

It is responsibility of the driver implementation to invoke the consumerCallback + * each time a message is received. + * * @param topic * @param subscriptionName * @param consumerCallback - * @return + * @return a consumer future */ CompletableFuture createConsumer( - String topic, - String subscriptionName, - ConsumerCallback consumerCallback); + String topic, String subscriptionName, ConsumerCallback consumerCallback); + + /** + * Create a consumers for a given topic. + * + * @param consumers + * @return a consumers future + */ + default CompletableFuture> createConsumers(List consumers) { + List> futures = + consumers.stream() + .map( + ci -> + createConsumer( + ci.getTopic(), ci.getSubscriptionName(), ci.getConsumerCallback())) + .collect(toList()); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream().map(CompletableFuture::join).collect(toList())); + } + + @Value + class TopicInfo { + String topic; + int partitions; + } + + @Value + class ProducerInfo { + int id; + String topic; + } + + @Value + class ConsumerInfo { + int id; + String topic; + String subscriptionName; + ConsumerCallback consumerCallback; + } } diff --git a/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkProducer.java b/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkProducer.java index 5f5bf996f..1662cf1c6 100644 --- a/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkProducer.java +++ b/driver-api/src/main/java/io/openmessaging/benchmark/driver/BenchmarkProducer.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver; + import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -26,12 +22,9 @@ public interface BenchmarkProducer extends AutoCloseable { /** * Publish a message and return a callback to track the completion of the operation. * - * @param key - * the key associated with this message - * @param payload - * the message payload + * @param key the key associated with this message + * @param payload the message payload * @return a future that will be triggered when the message is successfully published */ CompletableFuture sendAsync(Optional key, byte[] payload); - } diff --git a/driver-api/src/main/java/io/openmessaging/benchmark/driver/ConsumerCallback.java b/driver-api/src/main/java/io/openmessaging/benchmark/driver/ConsumerCallback.java index 24c55968a..b68ecf451 100644 --- a/driver-api/src/main/java/io/openmessaging/benchmark/driver/ConsumerCallback.java +++ b/driver-api/src/main/java/io/openmessaging/benchmark/driver/ConsumerCallback.java @@ -1,46 +1,36 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver; + import java.nio.ByteBuffer; -/** - * Callback that the driver implementation calls when a message is received - */ +/** Callback that the driver implementation calls when a message is received. */ public interface ConsumerCallback { /** - * Driver should invoke this method (or the ByteBuffer variant) once for each message received - * - * @param payload - * the received message payload - * @param publishTimestamp - * the publish timestamp in milliseconds + * Driver should invoke this method (or the ByteBuffer variant) once for each message received. + * + * @param payload the received message payload + * @param publishTimestamp the publish timestamp in milliseconds */ void messageReceived(byte[] payload, long publishTimestamp); /** - * Driver should invoke this method (or the byte[] variant) once for each message received + * Driver should invoke this method (or the byte[] variant) once for each message received. * - * @param payload - * the received message payload - * @param publishTimestamp - * the publish timestamp in milliseconds + * @param payload the received message payload + * @param publishTimestamp the publish timestamp in milliseconds */ void messageReceived(ByteBuffer payload, long publishTimestamp); } diff --git a/driver-api/src/main/java/io/openmessaging/benchmark/driver/ResourceCreator.java b/driver-api/src/main/java/io/openmessaging/benchmark/driver/ResourceCreator.java new file mode 100644 index 000000000..3bdfe5372 --- /dev/null +++ b/driver-api/src/main/java/io/openmessaging/benchmark/driver/ResourceCreator.java @@ -0,0 +1,99 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.stream.Collectors.toMap; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.Value; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RequiredArgsConstructor +public class ResourceCreator { + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + private final String name; + private final int maxBatchSize; + private final long interBatchDelayMs; + private final Function, Map>> invokeBatchFn; + private final Function, CreationResult> complete; + + public CompletableFuture> create(List resources) { + return CompletableFuture.completedFuture(createBlocking(resources)); + } + + private List createBlocking(List resources) { + BlockingQueue queue = new ArrayBlockingQueue<>(resources.size(), true, resources); + List batch = new ArrayList<>(); + List created = new ArrayList<>(); + AtomicInteger succeeded = new AtomicInteger(); + + ScheduledFuture loggingFuture = + executor.scheduleAtFixedRate( + () -> log.info("Created {}s {}/{}", name, succeeded.get(), resources.size()), + 10, + 10, + SECONDS); + + try { + while (succeeded.get() < resources.size()) { + int batchSize = queue.drainTo(batch, maxBatchSize); + if (batchSize > 0) { + executeBatch(batch) + .forEach( + (resource, result) -> { + if (result.success) { + created.add(result.created); + succeeded.incrementAndGet(); + } else { + //noinspection ResultOfMethodCallIgnored + queue.offer(resource); + } + }); + batch.clear(); + } + } + } finally { + loggingFuture.cancel(true); + } + return created; + } + + @SneakyThrows + private Map> executeBatch(List batch) { + log.debug("Executing batch, size: {}", batch.size()); + Thread.sleep(interBatchDelayMs); + return invokeBatchFn.apply(batch).entrySet().stream() + .collect(toMap(Map.Entry::getKey, e -> complete.apply(e.getValue()))); + } + + @Value + public static class CreationResult { + C created; + boolean success; + } +} diff --git a/driver-artemis/artemis.yaml b/driver-artemis/artemis.yaml index 3529ea61f..75dc0342f 100644 --- a/driver-artemis/artemis.yaml +++ b/driver-artemis/artemis.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Artemis diff --git a/driver-artemis/pom.xml b/driver-artemis/pom.xml index 20b0f50b9..fe8eed01d 100644 --- a/driver-artemis/pom.xml +++ b/driver-artemis/pom.xml @@ -1,47 +1,40 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - - - driver-artemis - - - - - ${project.groupId} - driver-api - ${project.version} - - - - org.apache.activemq - artemis-core-client - 2.4.0 - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + driver-artemis + + + + ${project.groupId} + driver-api + ${project.version} + + + org.apache.activemq + artemis-core-client + 2.23.1 + + diff --git a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkConsumer.java b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkConsumer.java index 6f6a71e64..e0b988219 100644 --- a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkConsumer.java +++ b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkConsumer.java @@ -1,23 +1,21 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.artemis; + +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.ConsumerCallback; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; @@ -27,31 +25,36 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.ConsumerCallback; - public class ArtemisBenchmarkConsumer implements BenchmarkConsumer { private final ClientSession session; private final ClientConsumer consumer; - public ArtemisBenchmarkConsumer(String topic, String queueName, ClientSessionFactory sessionFactory, ConsumerCallback callback) + public ArtemisBenchmarkConsumer( + String topic, + String queueName, + ClientSessionFactory sessionFactory, + ConsumerCallback callback) throws ActiveMQException { session = sessionFactory.createSession(); - session.createQueue(SimpleString.toSimpleString(topic), RoutingType.MULTICAST, - SimpleString.toSimpleString(queueName), true /* durable */); + session.createQueue( + SimpleString.toSimpleString(topic), + RoutingType.MULTICAST, + SimpleString.toSimpleString(queueName), + true /* durable */); consumer = session.createConsumer(queueName); - consumer.setMessageHandler(message -> { - byte[] payload = new byte[message.getBodyBuffer().readableBytes()]; - message.getBodyBuffer().readBytes(payload); - callback.messageReceived(payload, message.getTimestamp()); - try { - message.acknowledge(); - } catch (ActiveMQException e) { - log.warn("Failed to acknowledge message", e); - } - }); - + consumer.setMessageHandler( + message -> { + byte[] payload = new byte[message.getBodyBuffer().readableBytes()]; + message.getBodyBuffer().readBytes(payload); + callback.messageReceived(payload, message.getTimestamp()); + try { + message.acknowledge(); + } catch (ActiveMQException e) { + log.warn("Failed to acknowledge message", e); + } + }); + session.start(); } diff --git a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkDriver.java b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkDriver.java index f547109bb..67db26990 100644 --- a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkDriver.java +++ b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkDriver.java @@ -1,28 +1,31 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.artemis; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; import java.io.File; import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; - import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.RoutingType; import org.apache.activemq.artemis.api.core.SimpleString; @@ -34,16 +37,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; - -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.BenchmarkDriver; -import io.openmessaging.benchmark.driver.BenchmarkProducer; -import io.openmessaging.benchmark.driver.ConsumerCallback; - public class ArtemisBenchmarkDriver implements BenchmarkDriver { private ArtemisConfig config; @@ -56,8 +49,15 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I log.info("ActiveMQ Artemis driver configuration: {}", writer.writeValueAsString(config)); try { ServerLocator serverLocator = ActiveMQClient.createServerLocator(config.brokerAddress); - serverLocator.setConfirmationWindowSize(1000); - + // confirmation window size is in bytes, set to 1MB + serverLocator.setConfirmationWindowSize(1024 * 1024); + // use asynchronous sending of messages where SendAcknowledgementHandler reports + // success/failure + serverLocator.setBlockOnDurableSend(false); + serverLocator.setBlockOnNonDurableSend(false); + // use async acknowledgement + serverLocator.setBlockOnAcknowledge(false); + sessionFactory = serverLocator.createSessionFactory(); session = sessionFactory.createSession(); } catch (Exception e) { @@ -74,18 +74,22 @@ public String getTopicNamePrefix() { public CompletableFuture createTopic(String topic, int partitions) { CompletableFuture future = new CompletableFuture<>(); if (partitions != 1) { - future.completeExceptionally(new IllegalArgumentException("Partitions are not supported in Artemis")); + future.completeExceptionally( + new IllegalArgumentException("Partitions are not supported in Artemis")); return future; } - ForkJoinPool.commonPool().submit(() -> { - try { - session.createAddress(SimpleString.toSimpleString(topic), RoutingType.MULTICAST, true); - future.complete(null); - } catch (ActiveMQException e) { - future.completeExceptionally(e); - } - }); + ForkJoinPool.commonPool() + .submit( + () -> { + try { + session.createAddress( + SimpleString.toSimpleString(topic), RoutingType.MULTICAST, true); + future.complete(null); + } catch (ActiveMQException e) { + future.completeExceptionally(e); + } + }); return future; } @@ -102,19 +106,22 @@ public CompletableFuture createProducer(String topic) { } @Override - public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { CompletableFuture future = new CompletableFuture<>(); - ForkJoinPool.commonPool().submit(() -> { - try { - String queueName = topic + "-" + subscriptionName; - BenchmarkConsumer consumer = new ArtemisBenchmarkConsumer(topic, queueName, sessionFactory, - consumerCallback); - future.complete(consumer); - } catch (ActiveMQException e) { - future.completeExceptionally(e); - } - }); + ForkJoinPool.commonPool() + .submit( + () -> { + try { + String queueName = topic + "-" + subscriptionName; + BenchmarkConsumer consumer = + new ArtemisBenchmarkConsumer( + topic, queueName, sessionFactory, consumerCallback); + future.complete(consumer); + } catch (ActiveMQException e) { + future.completeExceptionally(e); + } + }); return future; } @@ -134,8 +141,9 @@ public void close() throws Exception { log.info("ActiveMQ Artemis benchmark driver successfully shut down"); } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static ArtemisConfig readConfig(File configurationFile) throws IOException { return mapper.readValue(configurationFile, ArtemisConfig.class); diff --git a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkProducer.java b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkProducer.java index 1db656d5e..0b40546fa 100644 --- a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkProducer.java +++ b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisBenchmarkProducer.java @@ -1,40 +1,37 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.artemis; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.Optional; import java.util.concurrent.CompletableFuture; - import org.apache.activemq.artemis.api.core.ActiveMQException; +import org.apache.activemq.artemis.api.core.Message; import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.ClientProducer; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; - -import io.openmessaging.benchmark.driver.BenchmarkProducer; +import org.apache.activemq.artemis.api.core.client.SendAcknowledgementHandler; public class ArtemisBenchmarkProducer implements BenchmarkProducer { private final ClientSession session; private final ClientProducer producer; - public ArtemisBenchmarkProducer(String address, ClientSessionFactory sessionFactory) throws ActiveMQException { + public ArtemisBenchmarkProducer(String address, ClientSessionFactory sessionFactory) + throws ActiveMQException { session = sessionFactory.createSession(); producer = session.createProducer(address); session.start(); @@ -48,20 +45,29 @@ public void close() throws Exception { @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { - ClientMessage msg = session.createMessage(true /* durable */ ); + ClientMessage msg = session.createMessage(true /* durable */); msg.setTimestamp(System.currentTimeMillis()); msg.getBodyBuffer().writeBytes(payload); CompletableFuture future = new CompletableFuture<>(); try { - producer.send(msg, message -> { - future.complete(null); - }); + producer.send( + msg, + new SendAcknowledgementHandler() { + @Override + public void sendAcknowledged(Message message) { + future.complete(null); + } + + @Override + public void sendFailed(Message message, Exception e) { + future.completeExceptionally(e); + } + }); } catch (ActiveMQException e) { future.completeExceptionally(e); } return future; } - } diff --git a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisConfig.java b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisConfig.java index 6aed0d5ed..418340b66 100644 --- a/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisConfig.java +++ b/driver-artemis/src/main/java/io/openmessaging/benchmark/driver/artemis/ArtemisConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.artemis; diff --git a/driver-bookkeeper/bookkeeper.yaml b/driver-bookkeeper/bookkeeper.yaml index 8c049101e..3a6153b7f 100644 --- a/driver-bookkeeper/bookkeeper.yaml +++ b/driver-bookkeeper/bookkeeper.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: BookKeeper diff --git a/driver-bookkeeper/deploy/deploy.yaml b/driver-bookkeeper/deploy/deploy.yaml index be4df52a1..87c1af4da 100644 --- a/driver-bookkeeper/deploy/deploy.yaml +++ b/driver-bookkeeper/deploy/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Format and mount disks for BookKeeper hosts diff --git a/driver-bookkeeper/deploy/templates/bookkeeper.conf b/driver-bookkeeper/deploy/templates/bookkeeper.conf index ad8d9f937..e7ec1bdb6 100644 --- a/driver-bookkeeper/deploy/templates/bookkeeper.conf +++ b/driver-bookkeeper/deploy/templates/bookkeeper.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-bookkeeper/deploy/templates/prometheus.yml b/driver-bookkeeper/deploy/templates/prometheus.yml index 7286f762f..e32538ef1 100644 --- a/driver-bookkeeper/deploy/templates/prometheus.yml +++ b/driver-bookkeeper/deploy/templates/prometheus.yml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # my global config diff --git a/driver-bookkeeper/deploy/templates/pulsar_env.sh b/driver-bookkeeper/deploy/templates/pulsar_env.sh index 1a271b119..903b7df08 100644 --- a/driver-bookkeeper/deploy/templates/pulsar_env.sh +++ b/driver-bookkeeper/deploy/templates/pulsar_env.sh @@ -1,21 +1,16 @@ #!/usr/bin/env bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Set JAVA_HOME here to override the environment setting diff --git a/driver-bookkeeper/deploy/templates/workers.yaml b/driver-bookkeeper/deploy/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-bookkeeper/deploy/templates/workers.yaml +++ b/driver-bookkeeper/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-bookkeeper/deploy/templates/zoo.cfg b/driver-bookkeeper/deploy/templates/zoo.cfg index b33cad819..dbd337067 100644 --- a/driver-bookkeeper/deploy/templates/zoo.cfg +++ b/driver-bookkeeper/deploy/templates/zoo.cfg @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # The number of milliseconds of each tick diff --git a/driver-bookkeeper/pom.xml b/driver-bookkeeper/pom.xml index 08e8a9397..3bbea8691 100644 --- a/driver-bookkeeper/pom.xml +++ b/driver-bookkeeper/pom.xml @@ -1,47 +1,43 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - - - driver-bookkeeper - - - - - ${project.groupId} - driver-api - ${project.version} - - - - org.apache.distributedlog - distributedlog-core-shaded - 4.7.0 - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + driver-bookkeeper + + + ${project.groupId} + driver-api + ${project.version} + + + io.netty + netty-all + + + org.apache.distributedlog + distributedlog-core-shaded + 4.14.4 + + diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/Config.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/Config.java index afaaedc25..db8c83a0b 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/Config.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/Config.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper; @@ -23,5 +18,4 @@ public class Config { public String dlogUri; public String dlogConf; - } diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkConsumer.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkConsumer.java index e2d9ae8dc..95414ef84 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkConsumer.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkConsumer.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper; + import dlshade.com.google.common.util.concurrent.ThreadFactoryBuilder; import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.ConsumerCallback; @@ -49,64 +45,74 @@ private static boolean backoff(long backoffTime, TimeUnit timeUnit) { return true; } catch (InterruptedException e) { Thread.currentThread().interrupt(); - log.warn("Interrupted at backoff {} ms", - timeUnit.toMillis(backoffTime), e); + log.warn("Interrupted at backoff {} ms", timeUnit.toMillis(backoffTime), e); return false; } } - public DlogBenchmarkConsumer(DistributedLogManager dlm, - ConsumerCallback callback) { + @SuppressWarnings("checkstyle:LineLength") + public DlogBenchmarkConsumer(DistributedLogManager dlm, ConsumerCallback callback) { this.dlm = dlm; - this.executor = Executors.newSingleThreadExecutor( - new ThreadFactoryBuilder().setNameFormat("dlog-benchmark-reader-thread-%d").build()); + this.executor = + Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder().setNameFormat("dlog-benchmark-reader-thread-%d").build()); - this.readerTask = executor.submit(() -> { - LogReader reader = null; - DLSN lastDLSN = DLSN.InitialDLSN; - LogRecordWithDLSN record; + this.readerTask = + executor.submit( + () -> { + LogReader reader = null; + DLSN lastDLSN = DLSN.InitialDLSN; + LogRecordWithDLSN record; - while (!closing) { - if (null == reader) { - try { - reader = dlm.openLogReader(lastDLSN); - log.info("Successfully open log reader for stream {} at {}", - dlm.getStreamName(), lastDLSN); - } catch (IOException e) { - log.error("Failed to open reader of stream {} at {}", - dlm.getStreamName(), lastDLSN, e); - if (backoff(10, TimeUnit.SECONDS)) { - continue; - } else { - break; - } - } - } + while (!closing) { + if (null == reader) { + try { + reader = dlm.openLogReader(lastDLSN); + log.info( + "Successfully open log reader for stream {} at {}", + dlm.getStreamName(), + lastDLSN); + } catch (IOException e) { + log.error( + "Failed to open reader of stream {} at {}", + dlm.getStreamName(), + lastDLSN, + e); + if (backoff(10, TimeUnit.SECONDS)) { + continue; + } else { + break; + } + } + } - try { - record = reader.readNext(false); - if (null == record) { - try { - Thread.sleep(1); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - continue; - } + try { + record = reader.readNext(false); + if (null == record) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + continue; + } - callback.messageReceived(record.getPayload(), record.getTransactionId()); + callback.messageReceived(record.getPayload(), record.getTransactionId()); - lastDLSN = record.getDlsn(); - } catch (IOException e) { - log.info("Encountered error on reading records from reading stream {}, last record = {}", - dlm.getStreamName(), lastDLSN, e); - Utils.closeQuietly(reader); - reader = null; - } - } + lastDLSN = record.getDlsn(); + } catch (IOException e) { + log.info( + "Encountered error on reading records from reading stream {}, last record = {}", + dlm.getStreamName(), + lastDLSN, + e); + Utils.closeQuietly(reader); + reader = null; + } + } - Utils.closeQuietly(reader); - }); + Utils.closeQuietly(reader); + }); } @Override @@ -118,5 +124,4 @@ public void close() throws Exception { dlm.close(); } } - } diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkDriver.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkDriver.java index 2734eca62..fd60a4cdf 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkDriver.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkDriver.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -26,7 +22,6 @@ import io.openmessaging.benchmark.driver.BenchmarkDriver; import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.openmessaging.benchmark.driver.ConsumerCallback; - import io.openmessaging.benchmark.driver.bookkeeper.stats.StatsLoggerAdaptor; import java.io.File; import java.io.IOException; @@ -43,14 +38,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Benchmark driver testing distributedlog. - */ +/** Benchmark driver testing distributedlog. */ public class DlogBenchmarkDriver implements BenchmarkDriver { private static final Logger log = LoggerFactory.getLogger(DlogBenchmarkProducer.class); - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private Config config; private Namespace namespace; @@ -71,13 +65,10 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I URI dlogUri = URI.create(config.dlogUri); dlshade.org.apache.bookkeeper.stats.StatsLogger dlStatsLogger = - new CachingStatsLogger(new StatsLoggerAdaptor(statsLogger.scope("dlog"))); + new CachingStatsLogger(new StatsLoggerAdaptor(statsLogger.scope("dlog"))); - namespace = NamespaceBuilder.newBuilder() - .conf(conf) - .uri(dlogUri) - .statsLogger(dlStatsLogger) - .build(); + namespace = + NamespaceBuilder.newBuilder().conf(conf).uri(dlogUri).statsLogger(dlStatsLogger).build(); log.info("Initialized distributedlog namespace at {}", dlogUri); } @@ -93,53 +84,53 @@ private static String getFullyQualifiedPartitionedStreamName(String topic, int p @Override public CompletableFuture createTopic(String topic, int partitions) { - return CompletableFuture.runAsync(() -> { - try { - namespace.createLog(topic); - if (partitions > 1) { - for (int i = 0; i < partitions; i++) { - namespace.createLog(getFullyQualifiedPartitionedStreamName(topic, i)); + return CompletableFuture.runAsync( + () -> { + try { + namespace.createLog(topic); + if (partitions > 1) { + for (int i = 0; i < partitions; i++) { + namespace.createLog(getFullyQualifiedPartitionedStreamName(topic, i)); + } + } + log.info("Successfully create topic {} with {} partitions", topic, partitions); + } catch (IOException ioe) { + log.error("Failed to create topic {} with {} partitions", topic, partitions, ioe); + throw new RuntimeException(ioe); } - } - log.info("Successfully create topic {} with {} partitions", topic, partitions); - } catch (IOException ioe) { - log.error("Failed to create topic {} with {} partitions", - topic, partitions, ioe); - throw new RuntimeException(ioe); - } - }); + }); } @Override public CompletableFuture createProducer(String topic) { - return CompletableFuture.supplyAsync(() -> { - try { - DistributedLogManager dlm = namespace.openLog(topic); - log.info("Open stream {} for producer", topic); - return dlm; - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - }) - .thenCompose(dlm -> dlm.openAsyncLogWriter()) - .thenApply(writer -> new DlogBenchmarkProducer(writer)); + return CompletableFuture.supplyAsync( + () -> { + try { + DistributedLogManager dlm = namespace.openLog(topic); + log.info("Open stream {} for producer", topic); + return dlm; + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + }) + .thenCompose(dlm -> dlm.openAsyncLogWriter()) + .thenApply(writer -> new DlogBenchmarkProducer(writer)); } @Override public CompletableFuture createConsumer( - String topic, - String subscriptionName, - ConsumerCallback consumerCallback) { - return CompletableFuture.supplyAsync(() -> { - try { - DistributedLogManager dlm = namespace.openLog(topic); - log.info("Open stream {} for consumer", topic); - return dlm; - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - }) - .thenApply(dlm -> new DlogBenchmarkConsumer(dlm, consumerCallback)); + String topic, String subscriptionName, ConsumerCallback consumerCallback) { + return CompletableFuture.supplyAsync( + () -> { + try { + DistributedLogManager dlm = namespace.openLog(topic); + log.info("Open stream {} for consumer", topic); + return dlm; + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + }) + .thenApply(dlm -> new DlogBenchmarkConsumer(dlm, consumerCallback)); } @Override @@ -152,5 +143,4 @@ public void close() throws Exception { log.info("BookKeeper benchmark driver successfully shut down"); } - } diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkProducer.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkProducer.java index 1bf981043..43f7399a7 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkProducer.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/DlogBenchmarkProducer.java @@ -1,32 +1,26 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.Optional; import java.util.concurrent.CompletableFuture; - import org.apache.distributedlog.LogRecord; import org.apache.distributedlog.api.AsyncLogWriter; import org.apache.distributedlog.util.TimeSequencer; -import io.openmessaging.benchmark.driver.BenchmarkProducer; - public class DlogBenchmarkProducer implements BenchmarkProducer { private final AsyncLogWriter writer; @@ -44,10 +38,8 @@ public void close() throws Exception { @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { - LogRecord record = new LogRecord( - sequencer.nextId(), payload); + LogRecord record = new LogRecord(sequencer.nextId(), payload); return writer.write(record).thenApply(dlsn -> null); } - } diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/CounterAdaptor.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/CounterAdaptor.java index 3255eb5e8..95d908774 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/CounterAdaptor.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/CounterAdaptor.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper.stats; + import org.apache.bookkeeper.stats.Counter; class CounterAdaptor implements dlshade.org.apache.bookkeeper.stats.Counter { diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/GaugeAdaptor.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/GaugeAdaptor.java index fe8e33105..a675a7484 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/GaugeAdaptor.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/GaugeAdaptor.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper.stats; + import org.apache.bookkeeper.stats.Gauge; class GaugeAdaptor implements Gauge { diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/OpStatsLoggerAdaptor.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/OpStatsLoggerAdaptor.java index 112ff7ca6..8f3d16680 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/OpStatsLoggerAdaptor.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/OpStatsLoggerAdaptor.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper.stats; + import dlshade.org.apache.bookkeeper.stats.OpStatsData; import java.util.concurrent.TimeUnit; import org.apache.bookkeeper.stats.OpStatsLogger; diff --git a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/StatsLoggerAdaptor.java b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/StatsLoggerAdaptor.java index ad36231f4..7f59c2db7 100644 --- a/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/StatsLoggerAdaptor.java +++ b/driver-bookkeeper/src/main/java/io/openmessaging/benchmark/driver/bookkeeper/stats/StatsLoggerAdaptor.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.bookkeeper.stats; + import dlshade.com.google.common.collect.Maps; import java.util.concurrent.ConcurrentMap; import org.apache.bookkeeper.stats.Gauge; @@ -27,7 +23,8 @@ public class StatsLoggerAdaptor implements dlshade.org.apache.bookkeeper.stats.S private final StatsLogger statsLogger; private final ConcurrentMap gauges; - private final ConcurrentMap statsLoggers; + private final ConcurrentMap + statsLoggers; public StatsLoggerAdaptor(StatsLogger statsLogger) { this.statsLogger = statsLogger; @@ -46,14 +43,16 @@ public dlshade.org.apache.bookkeeper.stats.Counter getCounter(String name) { } @Override - public void registerGauge(String name, dlshade.org.apache.bookkeeper.stats.Gauge gauge) { + public void registerGauge( + String name, dlshade.org.apache.bookkeeper.stats.Gauge gauge) { Gauge gaugeAdaptor = new GaugeAdaptor<>(gauge); statsLogger.registerGauge(name, gaugeAdaptor); gauges.put(gauge, gaugeAdaptor); } @Override - public void unregisterGauge(String name, dlshade.org.apache.bookkeeper.stats.Gauge gauge) { + public void unregisterGauge( + String name, dlshade.org.apache.bookkeeper.stats.Gauge gauge) { Gauge gaugeAdaptor = gauges.remove(gauge); if (null != gaugeAdaptor) { statsLogger.unregisterGauge(name, gaugeAdaptor); @@ -69,7 +68,8 @@ public dlshade.org.apache.bookkeeper.stats.StatsLogger scope(String name) { } @Override - public void removeScope(String name, dlshade.org.apache.bookkeeper.stats.StatsLogger dlShadeStatsLogger) { + public void removeScope( + String name, dlshade.org.apache.bookkeeper.stats.StatsLogger dlShadeStatsLogger) { StatsLogger scopedStatsLogger = statsLoggers.remove(dlShadeStatsLogger); if (null != scopedStatsLogger) { statsLogger.removeScope(name, scopedStatsLogger); diff --git a/driver-jms/README.md b/driver-jms/README.md index 360c6ebba..3792d8bc3 100644 --- a/driver-jms/README.md +++ b/driver-jms/README.md @@ -13,10 +13,12 @@ Rather than simply dropping a JMS Client Library into `/opt/benchmark/lib` the l Follow these instructions to compile the openmessaging benchmark for Fast JMS for Apache Pulsar - Build the openmessaging benchmark package as you would normally + ``` mvn clean package ``` - Run the repacking script + ``` bash driver-jms/package-pulsar.sh ``` @@ -28,6 +30,7 @@ You can now deploy to AWS from `driver-pulsar/deploy`. Follow the [Confluent instructions][1] to create a fat jar. - Create a directory + ``` cd ~ mkdir kafka-jms-client @@ -36,6 +39,7 @@ Follow the [Confluent instructions][1] to create a fat jar. - Create the pom.xml - Change `http://packages.confluent.io/maven/` to `https://packages.confluent.io/maven/` - Build the fat jar + ``` mvn clean package ``` @@ -43,10 +47,12 @@ Follow the [Confluent instructions][1] to create a fat jar. Follow these instructions to compile the openmessaging benchmark for Confluent JMS Client - Build the openmessaging benchmark package + ``` mvn clean package ``` - Run the repacking script passing in the location of the fat jar. EG. `~/kafka-jms-client/target/kafka-jms-client-fat-6.2.1.jar` + ``` bash driver-jms/package-kafka.sh /path/to/the/kafka-jms-client.jar ``` @@ -60,6 +66,5 @@ For Pulsar JMS (and likely Kafka) you will likely want to allocate additional co - Edit your `terraform.tfvars` file to adjust `num_instances["client"]`. - Run `bin/benchmark` with the `--extra` option to allocate more workers as consumers. +[1]: https://docs.confluent.io/platform/current/clients/kafka-jms-client/installation.html#appendix-1 - -[1]: https://docs.confluent.io/platform/current/clients/kafka-jms-client/installation.html#appendix-1 \ No newline at end of file diff --git a/driver-jms/artemis-jms-transactions.yaml b/driver-jms/artemis-jms-transactions.yaml index 2035ee38b..099ff7518 100644 --- a/driver-jms/artemis-jms-transactions.yaml +++ b/driver-jms/artemis-jms-transactions.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: JMS diff --git a/driver-jms/artemis-jms.yaml b/driver-jms/artemis-jms.yaml index b229ef5b1..3e2ca8122 100644 --- a/driver-jms/artemis-jms.yaml +++ b/driver-jms/artemis-jms.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: JMS diff --git a/driver-jms/kafka-jms.yaml b/driver-jms/kafka-jms.yaml index c1ddce32a..d9bebc1a2 100644 --- a/driver-jms/kafka-jms.yaml +++ b/driver-jms/kafka-jms.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: JMS diff --git a/driver-jms/package-kafka.sh b/driver-jms/package-kafka.sh index 5b1d18d44..925733f5d 100755 --- a/driver-jms/package-kafka.sh +++ b/driver-jms/package-kafka.sh @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # the one argument is the path to the confluent jms client fat jar on your local system diff --git a/driver-jms/package-pulsar.sh b/driver-jms/package-pulsar.sh index 7c3195c01..cfd357d74 100755 --- a/driver-jms/package-pulsar.sh +++ b/driver-jms/package-pulsar.sh @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # cd package/target diff --git a/driver-jms/pom.xml b/driver-jms/pom.xml index 7789a27dc..12101a80f 100644 --- a/driver-jms/pom.xml +++ b/driver-jms/pom.xml @@ -1,52 +1,47 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + - driver-jms - - 2.0.3 - + driver-jms + + 2.0.3 + - - - ${project.groupId} - driver-api - ${project.version} - - - jakarta.jms - jakarta.jms-api - ${jms.version} - - - com.google.guava - guava - - + + + ${project.groupId} + driver-api + ${project.version} + + + com.google.guava + guava + + + jakarta.jms + jakarta.jms-api + ${jms.version} + + diff --git a/driver-jms/pulsar-jms-selectors.yaml b/driver-jms/pulsar-jms-selectors.yaml index a37059df6..5dbc1ee58 100644 --- a/driver-jms/pulsar-jms-selectors.yaml +++ b/driver-jms/pulsar-jms-selectors.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: JMS diff --git a/driver-jms/pulsar-jms-transactions.yaml b/driver-jms/pulsar-jms-transactions.yaml index aa0f808fa..bc4fcda41 100644 --- a/driver-jms/pulsar-jms-transactions.yaml +++ b/driver-jms/pulsar-jms-transactions.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: JMS diff --git a/driver-jms/pulsar-jms.yaml b/driver-jms/pulsar-jms.yaml index bf659d2da..6e42fbe55 100644 --- a/driver-jms/pulsar-jms.yaml +++ b/driver-jms/pulsar-jms.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: JMS diff --git a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkConsumer.java b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkConsumer.java index 06bd2844a..e88fe86dc 100644 --- a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkConsumer.java +++ b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkConsumer.java @@ -1,37 +1,29 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.jms; + +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.ConsumerCallback; import javax.jms.BytesMessage; import javax.jms.Connection; -import javax.jms.JMSConsumer; -import javax.jms.JMSContext; import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.Session; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.ConsumerCallback; - public class JMSBenchmarkConsumer implements BenchmarkConsumer { private final Connection connection; @@ -39,33 +31,39 @@ public class JMSBenchmarkConsumer implements BenchmarkConsumer { private final MessageConsumer consumer; private final boolean useGetBody; - public JMSBenchmarkConsumer(Connection connection, + public JMSBenchmarkConsumer( + Connection connection, Session session, - MessageConsumer consumer, ConsumerCallback callback, - boolean useGetBody) throws Exception { + MessageConsumer consumer, + ConsumerCallback callback, + boolean useGetBody) + throws Exception { this.connection = connection; this.consumer = consumer; this.session = session; this.useGetBody = useGetBody; - consumer.setMessageListener(message -> { - try { - byte[] payload = getPayload(message); - callback.messageReceived(payload, message.getLongProperty("E2EStartMillis")); - message.acknowledge(); - } catch (Throwable e) { - log.warn("Failed to acknowledge message", e); - } - }); + consumer.setMessageListener( + message -> { + try { + byte[] payload = getPayload(message); + callback.messageReceived(payload, message.getLongProperty("E2EStartMillis")); + message.acknowledge(); + } catch (Throwable e) { + log.warn("Failed to acknowledge message", e); + } + }); // Kafka JMS client does not allow you to add a listener after the connection has been started connection.start(); } @Override public void close() throws Exception { - // This exception may be thrown: java.util.concurrent.ExecutionException: java.util.ConcurrentModificationException: KafkaConsumer is not safe for multi-threaded access - // See https://jakarta.ee/specifications/platform/8/apidocs/javax/jms/session#close-- - // and https://jakarta.ee/specifications/platform/8/apidocs/javax/jms/connection#close-- - // It should be enough to just close the connection. + // This exception may be thrown: java.util.concurrent.ExecutionException: + // java.util.ConcurrentModificationException: KafkaConsumer is not safe for multi-threaded + // access + // See https://jakarta.ee/specifications/platform/8/apidocs/javax/jms/session#close-- + // and https://jakarta.ee/specifications/platform/8/apidocs/javax/jms/connection#close-- + // It should be enough to just close the connection. connection.close(); } diff --git a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkDriver.java b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkDriver.java index c7cd77b03..221c30bc3 100644 --- a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkDriver.java +++ b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkDriver.java @@ -1,24 +1,28 @@ - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.jms; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.jms.config.JMSConfig; import java.io.File; import java.io.IOException; import java.io.StringReader; @@ -27,28 +31,16 @@ import java.util.Properties; import java.util.Random; import java.util.concurrent.CompletableFuture; - import javax.jms.Connection; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.MessageConsumer; import javax.jms.Session; import javax.jms.Topic; - import org.apache.bookkeeper.stats.StatsLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.BenchmarkDriver; -import io.openmessaging.benchmark.driver.BenchmarkProducer; -import io.openmessaging.benchmark.driver.ConsumerCallback; -import io.openmessaging.benchmark.driver.jms.config.JMSConfig; - public class JMSBenchmarkDriver implements BenchmarkDriver { private ConnectionFactory connectionFactory; @@ -61,35 +53,46 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I this.config = readConfig(configurationFile); log.info("JMS driver configuration: {}", writer.writeValueAsString(config)); - if (config.delegateForAdminOperationsClassName != null && !config.delegateForAdminOperationsClassName.isEmpty()) { - log.info("Initializing Driver for Admin operations {}", config.delegateForAdminOperationsClassName); - try - { - delegateForAdminOperations = (BenchmarkDriver) Class.forName(config.delegateForAdminOperationsClassName, - true, JMSBenchmarkDriver.class.getClassLoader()) - .getConstructor().newInstance(); + if (config.delegateForAdminOperationsClassName != null + && !config.delegateForAdminOperationsClassName.isEmpty()) { + log.info( + "Initializing Driver for Admin operations {}", + config.delegateForAdminOperationsClassName); + try { + delegateForAdminOperations = + (BenchmarkDriver) + Class.forName( + config.delegateForAdminOperationsClassName, + true, + JMSBenchmarkDriver.class.getClassLoader()) + .getConstructor() + .newInstance(); delegateForAdminOperations.initialize(configurationFile, statsLogger); - } - catch (Throwable e) - { - log.error("Cannot created delegate driver " + config.delegateForAdminOperationsClassName, e); + } catch (Throwable e) { + log.error( + "Cannot created delegate driver " + config.delegateForAdminOperationsClassName, e); throw new IOException(e); } } - try - { + try { connectionFactory = buildConnectionFactory(); connection = connectionFactory.createConnection(); connection.start(); } catch (Throwable t) { - log.error("Cannot initialize connectionFactoryClassName = "+config.connectionFactoryClassName, t); + log.error( + "Cannot initialize connectionFactoryClassName = " + config.connectionFactoryClassName, t); throw new IOException(t); } } private ConnectionFactory buildConnectionFactory() throws Exception { - Class clazz = (Class) Class.forName(config.connectionFactoryClassName, true, Thread.currentThread().getContextClassLoader()); + Class clazz = + (Class) + Class.forName( + config.connectionFactoryClassName, + true, + Thread.currentThread().getContextClassLoader()); // constructor with a String (like DataStax Pulsar JMS) try { @@ -103,7 +106,8 @@ private ConnectionFactory buildConnectionFactory() throws Exception { Constructor constructor = clazz.getConstructor(Properties.class); Properties props = new Properties(); ObjectMapper mapper = new ObjectMapper(); - Map map = mapper.readValue(new StringReader(config.connectionFactoryConfigurationParam), Map.class); + Map map = + mapper.readValue(new StringReader(config.connectionFactoryConfigurationParam), Map.class); props.putAll(map); return constructor.newInstance(props); } catch (NoSuchMethodException ignore) { @@ -132,11 +136,14 @@ public CompletableFuture createTopic(String topic, int partitions) { public CompletableFuture createProducer(String topic) { try { if (config.sendWithTransactions) { - return CompletableFuture.completedFuture(new JMSBenchmarkTransactionProducer(connection, topic, config.use20api, config.properties)); + return CompletableFuture.completedFuture( + new JMSBenchmarkTransactionProducer( + connection, topic, config.use20api, config.properties)); } else { Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination destination = session.createTopic(topic); - return CompletableFuture.completedFuture(new JMSBenchmarkProducer(session, destination, config.use20api, config.properties)); + return CompletableFuture.completedFuture( + new JMSBenchmarkProducer(session, destination, config.use20api, config.properties)); } } catch (Exception err) { CompletableFuture res = new CompletableFuture<>(); @@ -146,22 +153,28 @@ public CompletableFuture createProducer(String topic) { } @Override - public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { try { - String selector = config.messageSelector != null && !config.messageSelector.isEmpty() ? config.messageSelector : null; + String selector = + config.messageSelector != null && !config.messageSelector.isEmpty() + ? config.messageSelector + : null; Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Topic destination = session.createTopic(topic); MessageConsumer durableConsumer; if (config.use20api) { - durableConsumer = session.createSharedDurableConsumer(destination, subscriptionName, selector); + durableConsumer = + session.createSharedDurableConsumer(destination, subscriptionName, selector); } else { // in JMS 1.0 we should use session.createDurableSubscriber() // but it is not supported in Confluent Kafka JMS client durableConsumer = session.createConsumer(destination, selector); } - return CompletableFuture.completedFuture(new JMSBenchmarkConsumer(connection, session, durableConsumer, consumerCallback, config.use20api)); + return CompletableFuture.completedFuture( + new JMSBenchmarkConsumer( + connection, session, durableConsumer, consumerCallback, config.use20api)); } catch (Exception err) { CompletableFuture res = new CompletableFuture<>(); res.completeExceptionally(err); @@ -184,7 +197,8 @@ public void close() throws Exception { } } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static JMSConfig readConfig(File configurationFile) throws IOException { diff --git a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkProducer.java b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkProducer.java index fb651a621..b6ae05a69 100644 --- a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkProducer.java +++ b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkProducer.java @@ -1,44 +1,35 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.jms; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.jms.config.JMSConfig; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; - import javax.jms.BytesMessage; import javax.jms.CompletionListener; import javax.jms.Destination; -import javax.jms.JMSContext; import javax.jms.JMSException; -import javax.jms.JMSProducer; import javax.jms.Message; import javax.jms.MessageProducer; import javax.jms.Session; - -import io.openmessaging.benchmark.driver.jms.config.JMSConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openmessaging.benchmark.driver.BenchmarkProducer; - public class JMSBenchmarkProducer implements BenchmarkProducer { private final Session session; @@ -46,7 +37,13 @@ public class JMSBenchmarkProducer implements BenchmarkProducer { private final MessageProducer producer; private final boolean useAsyncSend; private final List properties; - public JMSBenchmarkProducer(Session session, Destination destination, boolean useAsyncSend, List properties) throws Exception { + + public JMSBenchmarkProducer( + Session session, + Destination destination, + boolean useAsyncSend, + List properties) + throws Exception { this.session = session; this.destination = destination; this.useAsyncSend = useAsyncSend; @@ -62,36 +59,33 @@ public void close() throws Exception { @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { CompletableFuture res = new CompletableFuture<>(); - try - { + try { BytesMessage bytesMessage = session.createBytesMessage(); bytesMessage.writeBytes(payload); - if (key.isPresent()) - { + if (key.isPresent()) { // a behaviour similar to https://activemq.apache.org/message-groups bytesMessage.setStringProperty("JMSXGroupID", key.get()); } for (JMSConfig.AddProperty prop : properties) { bytesMessage.setStringProperty(prop.name, prop.value); } - // Add a timer property for end to end - bytesMessage.setLongProperty("E2EStartMillis",System.currentTimeMillis()); + // Add a timer property for end to end + bytesMessage.setLongProperty("E2EStartMillis", System.currentTimeMillis()); if (useAsyncSend) { - producer.send(bytesMessage, new CompletionListener() - { - @Override - public void onCompletion(Message message) - { - res.complete(null); - } + producer.send( + bytesMessage, + new CompletionListener() { + @Override + public void onCompletion(Message message) { + res.complete(null); + } - @Override - public void onException(Message message, Exception exception) - { - log.error("send completed with error", exception); - res.completeExceptionally(exception); - } - }); + @Override + public void onException(Message message, Exception exception) { + log.error("send completed with error", exception); + res.completeExceptionally(exception); + } + }); } else { producer.send(bytesMessage); res.complete(null); @@ -101,5 +95,6 @@ public void onException(Message message, Exception exception) } return res; } + private static final Logger log = LoggerFactory.getLogger(JMSBenchmarkProducer.class); } diff --git a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkTransactionProducer.java b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkTransactionProducer.java index 9e24277f6..01087a9cb 100644 --- a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkTransactionProducer.java +++ b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/JMSBenchmarkTransactionProducer.java @@ -1,34 +1,35 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.jms; + import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.openmessaging.benchmark.driver.jms.config.JMSConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jms.*; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; +import javax.jms.BytesMessage; +import javax.jms.CompletionListener; +import javax.jms.Connection; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageProducer; +import javax.jms.Session; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class JMSBenchmarkTransactionProducer implements BenchmarkProducer { @@ -36,7 +37,13 @@ public class JMSBenchmarkTransactionProducer implements BenchmarkProducer { private final boolean useAsyncSend; private final Connection connection; private final List properties; - public JMSBenchmarkTransactionProducer(Connection connection, String destination, boolean useAsyncSend, List properties) throws Exception { + + public JMSBenchmarkTransactionProducer( + Connection connection, + String destination, + boolean useAsyncSend, + List properties) + throws Exception { this.destination = destination; this.useAsyncSend = useAsyncSend; this.connection = connection; @@ -44,57 +51,54 @@ public JMSBenchmarkTransactionProducer(Connection connection, String destination } @Override - public void close() { - } + public void close() {} @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { - try - { + try { // start a new Session every time, we cannot share the same Session // among the Producers because we want to have control over the commit operation Session session = connection.createSession(true, Session.SESSION_TRANSACTED); MessageProducer producer = session.createProducer(session.createTopic(destination)); BytesMessage bytesMessage = session.createBytesMessage(); bytesMessage.writeBytes(payload); - if (key.isPresent()) - { + if (key.isPresent()) { // a behaviour similar to https://activemq.apache.org/message-groups bytesMessage.setStringProperty("JMSXGroupID", key.get()); } for (JMSConfig.AddProperty prop : properties) { bytesMessage.setStringProperty(prop.name, prop.value); } - // Add a timer property for end to end - bytesMessage.setLongProperty("E2EStartMillis",System.currentTimeMillis()); + // Add a timer property for end to end + bytesMessage.setLongProperty("E2EStartMillis", System.currentTimeMillis()); if (useAsyncSend) { CompletableFuture res = new CompletableFuture<>(); - producer.send(bytesMessage, new CompletionListener() - { - @Override - public void onCompletion(Message message) - { - res.complete(null); - } + producer.send( + bytesMessage, + new CompletionListener() { + @Override + public void onCompletion(Message message) { + res.complete(null); + } - @Override - public void onException(Message message, Exception exception) - { - log.info("send completed with error", exception); - res.completeExceptionally(exception); - } - }); - return res.whenCompleteAsync((msg, error) -> { - if (error == null) { - // you cannot close the producer and session inside the CompletionListener - try { - session.commit(); - } catch (JMSException err) { - throw new CompletionException(err); - } - } - ensureClosed(producer, session);; - }); + @Override + public void onException(Message message, Exception exception) { + log.info("send completed with error", exception); + res.completeExceptionally(exception); + } + }); + return res.whenCompleteAsync( + (msg, error) -> { + if (error == null) { + // you cannot close the producer and session inside the CompletionListener + try { + session.commit(); + } catch (JMSException err) { + throw new CompletionException(err); + } + } + ensureClosed(producer, session); + }); } else { try { @@ -112,10 +116,9 @@ public void onException(Message message, Exception exception) res.completeExceptionally(err); return res; } - } - private void ensureClosed(MessageProducer producer, Session session) { + private void ensureClosed(MessageProducer producer, Session session) { try { producer.close(); } catch (Throwable err) { diff --git a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/config/JMSConfig.java b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/config/JMSConfig.java index 324873aca..3b936024c 100644 --- a/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/config/JMSConfig.java +++ b/driver-jms/src/main/java/io/openmessaging/benchmark/driver/jms/config/JMSConfig.java @@ -1,29 +1,24 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.jms.config; + import java.util.ArrayList; import java.util.List; -public class JMSConfig -{ +public class JMSConfig { public String connectionFactoryClassName = ""; public String connectionFactoryConfigurationParam = ""; diff --git a/driver-kafka/deploy/README.md b/driver-kafka/deploy/README.md index 67f1fadbf..9cadfd6c9 100644 --- a/driver-kafka/deploy/README.md +++ b/driver-kafka/deploy/README.md @@ -9,8 +9,8 @@ Customize the instance types in the terraform.tfvars. If you choose larger instances, they come with more drives. To include those in the benchmarks you must: - - update the Ansible script to include them in the mount and filesystem tasks - - update the server.properties to include them in the logs.dir config +- update the Ansible script to include them in the mount and filesystem tasks +- update the server.properties to include them in the logs.dir config NOTE: When using d2 instances, the instance stores are not automatically generated. You must add them to the provision-kafka-aws.tf file. @@ -34,4 +34,4 @@ For instructions on how to run a benchmark see the [Kafka instructions](http://o When using 4 client VMs or less you may see lower throughput when using compression. Compression is performed by the producers and consumers only (when using defaults) and clients need to be spread across more VMs to see any throughput gains. -Obviously, throughput may not be your primary goal when using compression. \ No newline at end of file +Obviously, throughput may not be your primary goal when using compression. diff --git a/driver-kafka/deploy/hdd-deployment/alicloud/deploy.yaml b/driver-kafka/deploy/hdd-deployment/alicloud/deploy.yaml index 8cd0ed1de..24816a5db 100644 --- a/driver-kafka/deploy/hdd-deployment/alicloud/deploy.yaml +++ b/driver-kafka/deploy/hdd-deployment/alicloud/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Format and mount disks for Kafka hosts @@ -59,7 +54,7 @@ - set_fact: zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" boostrapServers: "{{ groups['kafka'] | map('extract', hostvars, ['private_ip']) | map('regex_replace', '^(.*)$', '\\1:9092') | join(',') }}" - kafkaVersion: "2.0.0" + kafkaVersion: "3.6.1" - debug: msg: "zookeeper servers: {{ zookeeperServers }}\nboostrap servers: {{ boostrapServers }}" - name: Download Kafka package diff --git a/driver-kafka/deploy/hdd-deployment/deploy.yaml b/driver-kafka/deploy/hdd-deployment/deploy.yaml index d5d05a06c..b9f632b77 100644 --- a/driver-kafka/deploy/hdd-deployment/deploy.yaml +++ b/driver-kafka/deploy/hdd-deployment/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Format and mount disks for Kafka hosts @@ -85,7 +80,7 @@ - set_fact: zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" boostrapServers: "{{ groups['kafka'] | map('extract', hostvars, ['private_ip']) | map('regex_replace', '^(.*)$', '\\1:9092') | join(',') }}" - kafkaVersion: "2.8.1" + kafkaVersion: "3.6.1" - debug: msg: "zookeeper servers: {{ zookeeperServers }}\nboostrap servers: {{ boostrapServers }}" - name: Download Kafka package diff --git a/driver-kafka/deploy/hdd-deployment/templates/chrony.conf b/driver-kafka/deploy/hdd-deployment/templates/chrony.conf index 0e68c66a5..2ec5485aa 100644 --- a/driver-kafka/deploy/hdd-deployment/templates/chrony.conf +++ b/driver-kafka/deploy/hdd-deployment/templates/chrony.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Use public servers from the pool.ntp.org project. diff --git a/driver-kafka/deploy/hdd-deployment/templates/kafka.service b/driver-kafka/deploy/hdd-deployment/templates/kafka.service index c5afac56a..d35ac4b8b 100644 --- a/driver-kafka/deploy/hdd-deployment/templates/kafka.service +++ b/driver-kafka/deploy/hdd-deployment/templates/kafka.service @@ -5,7 +5,7 @@ After=network.target [Service] ExecStart=/opt/kafka/bin/kafka-server-start.sh config/server.properties Environment='KAFKA_HEAP_OPTS=-Xms6g -Xmx6g -XX:MetaspaceSize=96m' -Environment='KAFKA_JVM_PERFORMANCE_OPTS=-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80 -Djava.awt.headless=true" +Environment='KAFKA_JVM_PERFORMANCE_OPTS=-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80 -Djava.awt.headless=true' WorkingDirectory=/opt/kafka RestartSec=1s Restart=on-failure diff --git a/driver-kafka/deploy/hdd-deployment/templates/server.properties b/driver-kafka/deploy/hdd-deployment/templates/server.properties index 0d565707f..9ad5c2369 100644 --- a/driver-kafka/deploy/hdd-deployment/templates/server.properties +++ b/driver-kafka/deploy/hdd-deployment/templates/server.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-kafka/deploy/hdd-deployment/templates/workers.yaml b/driver-kafka/deploy/hdd-deployment/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-kafka/deploy/hdd-deployment/templates/workers.yaml +++ b/driver-kafka/deploy/hdd-deployment/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-kafka/deploy/hdd-deployment/templates/zookeeper.properties b/driver-kafka/deploy/hdd-deployment/templates/zookeeper.properties index b33cad819..dbd337067 100644 --- a/driver-kafka/deploy/hdd-deployment/templates/zookeeper.properties +++ b/driver-kafka/deploy/hdd-deployment/templates/zookeeper.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # The number of milliseconds of each tick diff --git a/driver-kafka/deploy/ssd-deployment/alicloud/deploy.yaml b/driver-kafka/deploy/ssd-deployment/alicloud/deploy.yaml index 8cd0ed1de..24816a5db 100644 --- a/driver-kafka/deploy/ssd-deployment/alicloud/deploy.yaml +++ b/driver-kafka/deploy/ssd-deployment/alicloud/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Format and mount disks for Kafka hosts @@ -59,7 +54,7 @@ - set_fact: zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" boostrapServers: "{{ groups['kafka'] | map('extract', hostvars, ['private_ip']) | map('regex_replace', '^(.*)$', '\\1:9092') | join(',') }}" - kafkaVersion: "2.0.0" + kafkaVersion: "3.6.1" - debug: msg: "zookeeper servers: {{ zookeeperServers }}\nboostrap servers: {{ boostrapServers }}" - name: Download Kafka package diff --git a/driver-kafka/deploy/ssd-deployment/ansible.cfg b/driver-kafka/deploy/ssd-deployment/ansible.cfg index d1fac48cd..066d4f2e4 100644 --- a/driver-kafka/deploy/ssd-deployment/ansible.cfg +++ b/driver-kafka/deploy/ssd-deployment/ansible.cfg @@ -5,4 +5,8 @@ private_key_file=~/.ssh/kafka_aws [privilege_escalation] become=true become_method='sudo' -become_user='root' \ No newline at end of file +become_user='root' + +[ssh_connection] +ssh_args=-o ServerAliveInterval=60 +retries=10 diff --git a/driver-kafka/deploy/ssd-deployment/deploy.yaml b/driver-kafka/deploy/ssd-deployment/deploy.yaml index eaec0d276..d02ce5dda 100644 --- a/driver-kafka/deploy/ssd-deployment/deploy.yaml +++ b/driver-kafka/deploy/ssd-deployment/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Format and mount disks for Kafka hosts @@ -67,6 +62,29 @@ - name: Reboot the machine with all defaults reboot: +- name: Format and mount disks for Zookeeper hosts + hosts: zookeeper + connection: ssh + become: true + tasks: + - name: Format disks + filesystem: + fstype: xfs + dev: '{{ item }}' + with_items: + - '/dev/nvme1n1' + - '/dev/nvme2n1' + - name: Mount disks + mount: + path: "{{ item.path }}" + src: "{{ item.src }}" + fstype: xfs + opts: defaults,noatime,nodiscard + state: mounted + with_items: + - { path: "/mnt/zookeeper/logs", src: "/dev/nvme1n1" } + - { path: "/mnt/zookeeper/data", src: "/dev/nvme2n1" } + - name: Kafka setup hosts: all connection: ssh @@ -84,10 +102,11 @@ - file: path=/opt/kafka state=directory - set_fact: zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" - boostrapServers: "{{ groups['kafka'] | map('extract', hostvars, ['private_ip']) | map('regex_replace', '^(.*)$', '\\1:9092') | join(',') }}" - kafkaVersion: "3.0.0" + bootstrapServers: "{{ groups['kafka'] | map('extract', hostvars, ['private_ip']) | map('regex_replace', '^(.*)$', '\\1:9092') | join(',') }}" + kafkaVersion: "3.6.1" + tags: [client-code] - debug: - msg: "zookeeper servers: {{ zookeeperServers }}\nboostrap servers: {{ boostrapServers }}" + msg: "zookeeper servers: {{ zookeeperServers }}\nbootstrap servers: {{ bootstrapServers }}" - name: Download Kafka package unarchive: src: "http://archive.apache.org/dist/kafka/{{ kafkaVersion }}/kafka_2.13-{{ kafkaVersion }}.tgz" @@ -108,15 +127,12 @@ tasks: - set_fact: zid: "{{ groups['zookeeper'].index(inventory_hostname) }}" - - file: - path: "/opt/kafka/data/zookeeper" - state: directory - template: src: "templates/zookeeper.properties" dest: "/opt/kafka/config/zookeeper.properties" - template: src: templates/myid - dest: "/opt/kafka/data/zookeeper/myid" + dest: "/mnt/zookeeper/data/myid" - template: src: "templates/zookeeper.service" dest: "/etc/systemd/system/zookeeper.service" @@ -143,6 +159,7 @@ state: restarted daemon_reload: yes name: "kafka" + tags: [restart-kafka] - name: Chrony setup hosts: client @@ -164,23 +181,28 @@ become: true tasks: - file: path=/opt/benchmark state=absent + tags: [client-code] - name: Copy benchmark code unarchive: src: ../../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz dest: /opt + tags: [client-code] - shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT /opt/benchmark + tags: [client-code] - shell: tuned-adm profile latency-performance - name: Get list of driver config files raw: ls -1 /opt/benchmark/driver-kafka/*.yaml register: drivers_list + tags: [client-code] - name: Configure Bootstrap Servers lineinfile: dest: '{{ item }}' regexp: '^ bootstrap.servers=' - line: ' bootstrap.servers={{ boostrapServers }}' + line: ' bootstrap.servers={{ bootstrapServers }}' with_items: '{{ drivers_list.stdout_lines }}' + tags: [client-code] - name: Get list of jms driver config files raw: ls -1 /opt/benchmark/driver-jms/kafka*.yaml @@ -190,14 +212,14 @@ lineinfile: dest: '{{ item }}' regexp: '^ bootstrap.servers=' - line: ' bootstrap.servers={{ boostrapServers }}' + line: ' bootstrap.servers={{ bootstrapServers }}' with_items: '{{ jms_drivers_list.stdout_lines }}' - name: Configure JMS Connection Factory ansible.builtin.replace: dest: '{{ item }}' regexp: 'localhost\:9092' - replace: '{{ boostrapServers }}' + replace: '{{ bootstrapServers }}' with_items: '{{ jms_drivers_list.stdout_lines }}' - name: Configure memory @@ -205,22 +227,27 @@ dest: /opt/benchmark/bin/benchmark-worker regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xms100G -Xmx100G -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=12 -XX:ConcGCThreads=12 -XX:+DisableExplicitGC -XX:-ResizePLAB"' + tags: [client-code] - name: Configure memory lineinfile: dest: /opt/benchmark/bin/benchmark regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xmx4G"' + tags: [client-code] - template: src: "templates/workers.yaml" dest: "/opt/benchmark/workers.yaml" + tags: [client-code] - name: Install benchmark systemd service template: src: "templates/benchmark-worker.service" dest: "/etc/systemd/system/benchmark-worker.service" + tags: [client-code] - systemd: state: restarted daemon_reload: yes name: "benchmark-worker" + tags: [client-code] - name: Hosts addresses hosts: localhost diff --git a/driver-kafka/deploy/ssd-deployment/provision-kafka-aws.tf b/driver-kafka/deploy/ssd-deployment/provision-kafka-aws.tf index e1f99472f..172c01ee8 100644 --- a/driver-kafka/deploy/ssd-deployment/provision-kafka-aws.tf +++ b/driver-kafka/deploy/ssd-deployment/provision-kafka-aws.tf @@ -45,7 +45,7 @@ resource "aws_vpc" "benchmark_vpc" { cidr_block = "10.0.0.0/16" tags = { - Name = "Kafka-Benchmark-VPC-${random_id.hash.hex}" + Name = "Kafka_Benchmark_VPC_${random_id.hash.hex}" } } @@ -116,7 +116,8 @@ resource "aws_instance" "zookeeper" { count = "${var.num_instances["zookeeper"]}" tags = { - Name = "zk-${count.index}" + Name = "zk_${count.index}" + Benchmark = "Kafka" } } @@ -129,7 +130,8 @@ resource "aws_instance" "kafka" { count = "${var.num_instances["kafka"]}" tags = { - Name = "kafka-${count.index}" + Name = "kafka_${count.index}" + Benchmark = "Kafka" } } @@ -142,10 +144,15 @@ resource "aws_instance" "client" { count = "${var.num_instances["client"]}" tags = { - Name = "kafka-client-${count.index}" + Name = "kafka_client_${count.index}" + Benchmark = "Kafka" } } +output "kafka_ssh_host" { + value = "${aws_instance.kafka.0.public_ip}" +} + output "client_ssh_host" { value = "${aws_instance.client.0.public_ip}" } diff --git a/driver-kafka/deploy/ssd-deployment/templates/chrony.conf b/driver-kafka/deploy/ssd-deployment/templates/chrony.conf index 0e68c66a5..2ec5485aa 100644 --- a/driver-kafka/deploy/ssd-deployment/templates/chrony.conf +++ b/driver-kafka/deploy/ssd-deployment/templates/chrony.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Use public servers from the pool.ntp.org project. diff --git a/driver-kafka/deploy/ssd-deployment/templates/kafka.service b/driver-kafka/deploy/ssd-deployment/templates/kafka.service index 39c04c1a8..9d4a975ef 100644 --- a/driver-kafka/deploy/ssd-deployment/templates/kafka.service +++ b/driver-kafka/deploy/ssd-deployment/templates/kafka.service @@ -5,7 +5,7 @@ After=network.target [Service] ExecStart=/opt/kafka/bin/kafka-server-start.sh config/server.properties Environment='KAFKA_HEAP_OPTS=-Xms16g -Xmx16g -XX:MetaspaceSize=96m' -Environment='KAFKA_JVM_PERFORMANCE_OPTS=-server -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=12 -XX:ConcGCThreads=12 -XX:+DisableExplicitGC -XX:-ResizePLAB -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80 -Djava.awt.headless=true" +Environment='KAFKA_JVM_PERFORMANCE_OPTS=-server -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=12 -XX:ConcGCThreads=12 -XX:+DisableExplicitGC -XX:-ResizePLAB -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80 -Djava.awt.headless=true' WorkingDirectory=/opt/kafka RestartSec=1s Restart=on-failure diff --git a/driver-kafka/deploy/ssd-deployment/templates/server.properties b/driver-kafka/deploy/ssd-deployment/templates/server.properties index 0d565707f..9ad5c2369 100644 --- a/driver-kafka/deploy/ssd-deployment/templates/server.properties +++ b/driver-kafka/deploy/ssd-deployment/templates/server.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-kafka/deploy/ssd-deployment/templates/workers.yaml b/driver-kafka/deploy/ssd-deployment/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-kafka/deploy/ssd-deployment/templates/workers.yaml +++ b/driver-kafka/deploy/ssd-deployment/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-kafka/deploy/ssd-deployment/templates/zookeeper.properties b/driver-kafka/deploy/ssd-deployment/templates/zookeeper.properties index b33cad819..4fb919bd5 100644 --- a/driver-kafka/deploy/ssd-deployment/templates/zookeeper.properties +++ b/driver-kafka/deploy/ssd-deployment/templates/zookeeper.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # The number of milliseconds of each tick @@ -26,7 +21,8 @@ initLimit=10 # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. -dataDir=data/zookeeper +dataLogDir=/mnt/zookeeper/logs +dataDir=/mnt/zookeeper/data # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. diff --git a/driver-kafka/deploy/ssd-deployment/templates/zookeeper.service b/driver-kafka/deploy/ssd-deployment/templates/zookeeper.service index 3a2706efa..cb0d13d7b 100644 --- a/driver-kafka/deploy/ssd-deployment/templates/zookeeper.service +++ b/driver-kafka/deploy/ssd-deployment/templates/zookeeper.service @@ -3,6 +3,7 @@ Description=ZooKeeper After=network.target [Service] +Environment='KAFKA_HEAP_OPTS=-Xms32g -Xmx32g' ExecStart=/opt/kafka/bin/zookeeper-server-start.sh config/zookeeper.properties WorkingDirectory=/opt/kafka RestartSec=1s diff --git a/driver-kafka/deploy/ssd-deployment/terraform.tfvars b/driver-kafka/deploy/ssd-deployment/terraform.tfvars index ac01d4acb..f6b6d8995 100644 --- a/driver-kafka/deploy/ssd-deployment/terraform.tfvars +++ b/driver-kafka/deploy/ssd-deployment/terraform.tfvars @@ -1,11 +1,11 @@ public_key_path = "~/.ssh/kafka_aws.pub" region = "us-west-2" az = "us-west-2a" -ami = "ami-9fa343e7" // RHEL-7.4 +ami = "ami-08970fb2e5767e3b8" // RHEL-8 instance_types = { "kafka" = "i3en.6xlarge" - "zookeeper" = "t2.small" + "zookeeper" = "i3en.2xlarge" "client" = "m5n.8xlarge" } diff --git a/driver-kafka/kafka-big-batches-gzip.yaml b/driver-kafka/kafka-big-batches-gzip.yaml index 603145388..86e48eac4 100644 --- a/driver-kafka/kafka-big-batches-gzip.yaml +++ b/driver-kafka/kafka-big-batches-gzip.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-big-batches-lz4.yaml b/driver-kafka/kafka-big-batches-lz4.yaml index 0c3fcfdf6..18453137d 100644 --- a/driver-kafka/kafka-big-batches-lz4.yaml +++ b/driver-kafka/kafka-big-batches-lz4.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-big-batches-snappy.yaml b/driver-kafka/kafka-big-batches-snappy.yaml index f7a70161c..ffd1d0990 100644 --- a/driver-kafka/kafka-big-batches-snappy.yaml +++ b/driver-kafka/kafka-big-batches-snappy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-big-batches-zstd.yaml b/driver-kafka/kafka-big-batches-zstd.yaml index 162ff7225..3a15a5e26 100644 --- a/driver-kafka/kafka-big-batches-zstd.yaml +++ b/driver-kafka/kafka-big-batches-zstd.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-big-batches.yaml b/driver-kafka/kafka-big-batches.yaml index 5c3b99b0b..b0c8638a5 100644 --- a/driver-kafka/kafka-big-batches.yaml +++ b/driver-kafka/kafka-big-batches.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-compression-gzip.yaml b/driver-kafka/kafka-compression-gzip.yaml index 68dc9dba7..011a98f4a 100644 --- a/driver-kafka/kafka-compression-gzip.yaml +++ b/driver-kafka/kafka-compression-gzip.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-compression-lz4.yaml b/driver-kafka/kafka-compression-lz4.yaml index f756ec8c6..8fdccc982 100644 --- a/driver-kafka/kafka-compression-lz4.yaml +++ b/driver-kafka/kafka-compression-lz4.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-compression-snappy.yaml b/driver-kafka/kafka-compression-snappy.yaml index dcdfcfd1b..ae229768b 100644 --- a/driver-kafka/kafka-compression-snappy.yaml +++ b/driver-kafka/kafka-compression-snappy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-compression-zstd.yaml b/driver-kafka/kafka-compression-zstd.yaml index 1a5a577fa..d769bbb5f 100644 --- a/driver-kafka/kafka-compression-zstd.yaml +++ b/driver-kafka/kafka-compression-zstd.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-exactly-once.yaml b/driver-kafka/kafka-exactly-once.yaml index e85d6ea1c..8a6ec7706 100644 --- a/driver-kafka/kafka-exactly-once.yaml +++ b/driver-kafka/kafka-exactly-once.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-latency.yaml b/driver-kafka/kafka-latency.yaml index 6246c0f08..ed0d5a600 100644 --- a/driver-kafka/kafka-latency.yaml +++ b/driver-kafka/kafka-latency.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-no-linger.yaml b/driver-kafka/kafka-no-linger.yaml index 768bd7eed..aaccf8edb 100644 --- a/driver-kafka/kafka-no-linger.yaml +++ b/driver-kafka/kafka-no-linger.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,7 +18,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-sync.yaml b/driver-kafka/kafka-sync.yaml index 2fa14cd01..357b570c4 100644 --- a/driver-kafka/kafka-sync.yaml +++ b/driver-kafka/kafka-sync.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Kafka driver profile that is configuring to sync all @@ -24,7 +19,6 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 diff --git a/driver-kafka/kafka-throughput.yaml b/driver-kafka/kafka-throughput.yaml index 4c00b39d4..01122b46d 100644 --- a/driver-kafka/kafka-throughput.yaml +++ b/driver-kafka/kafka-throughput.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,13 +18,14 @@ driverClass: io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkDriver # Kafka client-specific configuration replicationFactor: 3 -reset: true topicConfig: | min.insync.replicas=2 commonConfig: | bootstrap.servers=localhost:9092 + default.api.timeout.ms=1200000 + request.timeout.ms=1200000 producerConfig: | acks=all diff --git a/driver-kafka/pom.xml b/driver-kafka/pom.xml index a44de0b86..83324ab5c 100644 --- a/driver-kafka/pom.xml +++ b/driver-kafka/pom.xml @@ -1,46 +1,65 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - - driver-kafka + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + driver-kafka - - - ${project.groupId} - driver-api - ${project.version} - - - - org.apache.kafka - kafka-clients - 2.8.1 - - + + + ${project.groupId} + driver-api + ${project.version} + + + org.apache.kafka + kafka-clients + 3.6.1 + + + org.projectlombok + lombok + provided + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.assertj + assertj-core + test + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-junit-jupiter + test + + diff --git a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/Config.java b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/Config.java index b73eb0b68..d2fafafa3 100644 --- a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/Config.java +++ b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/Config.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.kafka; @@ -28,6 +23,4 @@ public class Config { public String producerConfig; public String consumerConfig; - - public boolean reset; } diff --git a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkConsumer.java b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkConsumer.java index 2f3dd695a..e07b417d9 100644 --- a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkConsumer.java +++ b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkConsumer.java @@ -1,23 +1,21 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.kafka; + +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.ConsumerCallback; import java.time.Duration; import java.util.HashMap; import java.util.Map; @@ -25,16 +23,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; - import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.consumer.OffsetAndMetadata; import org.apache.kafka.common.TopicPartition; - -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.ConsumerCallback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,32 +42,51 @@ public class KafkaBenchmarkConsumer implements BenchmarkConsumer { private final Future consumerTask; private volatile boolean closing = false; private boolean autoCommit; - public KafkaBenchmarkConsumer(KafkaConsumer consumer, Properties consumerConfig, ConsumerCallback callback) { + + public KafkaBenchmarkConsumer( + KafkaConsumer consumer, + Properties consumerConfig, + ConsumerCallback callback) { + this(consumer, consumerConfig, callback, 100L); + } + + public KafkaBenchmarkConsumer( + KafkaConsumer consumer, + Properties consumerConfig, + ConsumerCallback callback, + long pollTimeoutMs) { this.consumer = consumer; this.executor = Executors.newSingleThreadExecutor(); - this.autoCommit= Boolean.valueOf((String)consumerConfig.getOrDefault(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,"false")); - this.consumerTask = this.executor.submit(() -> { - while (!closing) { - try { - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + this.autoCommit = + Boolean.valueOf( + (String) + consumerConfig.getOrDefault(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false")); + this.consumerTask = + this.executor.submit( + () -> { + while (!closing) { + try { + ConsumerRecords records = + consumer.poll(Duration.ofMillis(pollTimeoutMs)); - Map offsetMap = new HashMap<>(); - for (ConsumerRecord record : records) { - callback.messageReceived(record.value(), record.timestamp()); + Map offsetMap = new HashMap<>(); + for (ConsumerRecord record : records) { + callback.messageReceived(record.value(), record.timestamp()); - offsetMap.put(new TopicPartition(record.topic(), record.partition()), - new OffsetAndMetadata(record.offset()+1)); - } + offsetMap.put( + new TopicPartition(record.topic(), record.partition()), + new OffsetAndMetadata(record.offset() + 1)); + } - if (!autoCommit&&!offsetMap.isEmpty()) { - // Async commit all messages polled so far - consumer.commitAsync(offsetMap, null); - } - } catch(Exception e){ - log.error("exception occur while consuming message", e); - } - } - }); + if (!autoCommit && !offsetMap.isEmpty()) { + // Async commit all messages polled so far + consumer.commitAsync(offsetMap, null); + } + } catch (Exception e) { + log.error("exception occur while consuming message", e); + } + } + }); } @Override @@ -83,5 +96,4 @@ public void close() throws Exception { consumerTask.get(); consumer.close(); } - } diff --git a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkDriver.java b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkDriver.java index f1ea60bee..d506b5b37 100644 --- a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkDriver.java +++ b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkDriver.java @@ -1,23 +1,26 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.kafka; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; import java.io.File; import java.io.IOException; import java.io.StringReader; @@ -28,15 +31,9 @@ import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.Set; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - import org.apache.bookkeeper.stats.StatsLogger; import org.apache.kafka.clients.admin.AdminClient; -import org.apache.kafka.clients.admin.DeleteTopicsResult; -import org.apache.kafka.clients.admin.ListTopicsResult; -import org.apache.kafka.clients.admin.NewTopic; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.producer.KafkaProducer; @@ -46,17 +43,11 @@ import org.apache.kafka.common.serialization.StringDeserializer; import org.apache.kafka.common.serialization.StringSerializer; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; - -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.BenchmarkDriver; -import io.openmessaging.benchmark.driver.BenchmarkProducer; -import io.openmessaging.benchmark.driver.ConsumerCallback; - public class KafkaBenchmarkDriver implements BenchmarkDriver { + private static final String ZONE_ID_CONFIG = "zone.id"; + private static final String ZONE_ID_TEMPLATE = "{zone.id}"; + private static final String KAFKA_CLIENT_ID = "client.id"; private Config config; private List producers = Collections.synchronizedList(new ArrayList<>()); @@ -75,36 +66,33 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I Properties commonProperties = new Properties(); commonProperties.load(new StringReader(config.commonConfig)); + if (commonProperties.containsKey(KAFKA_CLIENT_ID)) { + commonProperties.put( + KAFKA_CLIENT_ID, + applyZoneId( + commonProperties.getProperty(KAFKA_CLIENT_ID), System.getProperty(ZONE_ID_CONFIG))); + } + producerProperties = new Properties(); commonProperties.forEach((key, value) -> producerProperties.put(key, value)); producerProperties.load(new StringReader(config.producerConfig)); - producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); - producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class.getName()); + producerProperties.put( + ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + producerProperties.put( + ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class.getName()); consumerProperties = new Properties(); commonProperties.forEach((key, value) -> consumerProperties.put(key, value)); consumerProperties.load(new StringReader(config.consumerConfig)); - consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); - consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class.getName()); + consumerProperties.put( + ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + consumerProperties.put( + ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class.getName()); topicProperties = new Properties(); topicProperties.load(new StringReader(config.topicConfig)); admin = AdminClient.create(commonProperties); - - if (config.reset) { - // List existing topics - ListTopicsResult result = admin.listTopics(); - try { - Set topics = result.names().get(); - // Delete all existing topics - DeleteTopicsResult deletes = admin.deleteTopics(topics); - deletes.all().get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - throw new IOException(e); - } - } } @Override @@ -112,18 +100,18 @@ public String getTopicNamePrefix() { return "test-topic"; } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public CompletableFuture createTopic(String topic, int partitions) { - return CompletableFuture.runAsync(() -> { - try { - NewTopic newTopic = new NewTopic(topic, partitions, config.replicationFactor); - newTopic.configs(new HashMap<>((Map) topicProperties)); - admin.createTopics(Arrays.asList(newTopic)).all().get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - }); + return createTopics(Collections.singletonList(new TopicInfo(topic, partitions))); + } + + @Override + public CompletableFuture createTopics(List topicInfos) { + @SuppressWarnings({"unchecked", "rawtypes"}) + Map topicConfigs = new HashMap<>((Map) topicProperties); + KafkaTopicCreator topicCreator = + new KafkaTopicCreator(admin, topicConfigs, config.replicationFactor); + return topicCreator.create(topicInfos); } @Override @@ -143,22 +131,22 @@ public CompletableFuture createProducer(String topic) { } @Override - public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { Properties properties = new Properties(); consumerProperties.forEach((key, value) -> properties.put(key, value)); properties.put(ConsumerConfig.GROUP_ID_CONFIG, subscriptionName); KafkaConsumer consumer = new KafkaConsumer<>(properties); try { consumer.subscribe(Arrays.asList(topic)); - return CompletableFuture.completedFuture(new KafkaBenchmarkConsumer(consumer,consumerProperties,consumerCallback)); + return CompletableFuture.completedFuture( + new KafkaBenchmarkConsumer(consumer, consumerProperties, consumerCallback)); } catch (Throwable t) { consumer.close(); CompletableFuture future = new CompletableFuture<>(); future.completeExceptionally(t); return future; } - } @Override @@ -173,6 +161,11 @@ public void close() throws Exception { admin.close(); } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static String applyZoneId(String clientId, String zoneId) { + return clientId.replace(ZONE_ID_TEMPLATE, zoneId); + } + + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } diff --git a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkProducer.java b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkProducer.java index 830df2652..6c62d9fbc 100644 --- a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkProducer.java +++ b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaBenchmarkProducer.java @@ -1,41 +1,44 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.kafka; -import java.util.ArrayList; -import java.util.List; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.Optional; -import java.util.Random; import java.util.concurrent.CompletableFuture; - -import org.apache.commons.lang.ArrayUtils; -import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; -import io.openmessaging.benchmark.driver.BenchmarkProducer; - public class KafkaBenchmarkProducer implements BenchmarkProducer { - private final KafkaProducer producer; + private final Producer producer; private final String topic; - public KafkaBenchmarkProducer(KafkaProducer producer, String topic) { + public KafkaBenchmarkProducer(Producer producer, String topic) { this.producer = producer; this.topic = topic; } @@ -46,13 +49,15 @@ public CompletableFuture sendAsync(Optional key, byte[] payload) { CompletableFuture future = new CompletableFuture<>(); - producer.send(record, (metadata, exception) -> { - if (exception != null) { - future.completeExceptionally(exception); - } else { - future.complete(null); - } - }); + producer.send( + record, + (metadata, exception) -> { + if (exception != null) { + future.completeExceptionally(exception); + } else { + future.complete(null); + } + }); return future; } @@ -61,5 +66,4 @@ public CompletableFuture sendAsync(Optional key, byte[] payload) { public void close() throws Exception { producer.close(); } - } diff --git a/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaTopicCreator.java b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaTopicCreator.java new file mode 100644 index 000000000..82d3e38b7 --- /dev/null +++ b/driver-kafka/src/main/java/io/openmessaging/benchmark/driver/kafka/KafkaTopicCreator.java @@ -0,0 +1,121 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kafka; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; + +import io.openmessaging.benchmark.driver.BenchmarkDriver.TopicInfo; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicInteger; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.common.KafkaFuture; +import org.apache.kafka.common.errors.TopicExistsException; + +@Slf4j +@RequiredArgsConstructor +class KafkaTopicCreator { + private static final int MAX_BATCH_SIZE = 500; + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + private final AdminClient admin; + private final Map topicConfigs; + private final short replicationFactor; + private final int maxBatchSize; + + KafkaTopicCreator(AdminClient admin, Map topicConfigs, short replicationFactor) { + this(admin, topicConfigs, replicationFactor, MAX_BATCH_SIZE); + } + + CompletableFuture create(List topicInfos) { + return CompletableFuture.runAsync(() -> createBlocking(topicInfos)); + } + + private void createBlocking(List topicInfos) { + BlockingQueue queue = new ArrayBlockingQueue<>(topicInfos.size(), true, topicInfos); + List batch = new ArrayList<>(); + AtomicInteger succeeded = new AtomicInteger(); + + ScheduledFuture loggingFuture = + executor.scheduleAtFixedRate( + () -> log.info("Created topics {}/{}", succeeded.get(), topicInfos.size()), + 10, + 10, + SECONDS); + + try { + while (succeeded.get() < topicInfos.size()) { + int batchSize = queue.drainTo(batch, maxBatchSize); + if (batchSize > 0) { + executeBatch(batch) + .forEach( + (topicInfo, success) -> { + if (success) { + succeeded.incrementAndGet(); + } else { + //noinspection ResultOfMethodCallIgnored + queue.offer(topicInfo); + } + }); + batch.clear(); + } + } + } finally { + loggingFuture.cancel(true); + } + } + + private Map executeBatch(List batch) { + log.debug("Executing batch, size: {}", batch.size()); + Map lookup = batch.stream().collect(toMap(TopicInfo::getTopic, identity())); + + List newTopics = batch.stream().map(this::newTopic).collect(toList()); + + return admin.createTopics(newTopics).values().entrySet().stream() + .collect(toMap(e -> lookup.get(e.getKey()), e -> isSuccess(e.getValue()))); + } + + private NewTopic newTopic(TopicInfo topicInfo) { + NewTopic newTopic = + new NewTopic(topicInfo.getTopic(), topicInfo.getPartitions(), replicationFactor); + newTopic.configs(topicConfigs); + return newTopic; + } + + private boolean isSuccess(KafkaFuture future) { + try { + future.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (ExecutionException e) { + log.debug(e.getMessage()); + return e.getCause() instanceof TopicExistsException; + } + return true; + } +} diff --git a/driver-kafka/src/test/java/io/openmessaging/benchmark/driver/kafka/KafkaTopicCreatorTest.java b/driver-kafka/src/test/java/io/openmessaging/benchmark/driver/kafka/KafkaTopicCreatorTest.java new file mode 100644 index 000000000..25b38a0e1 --- /dev/null +++ b/driver-kafka/src/test/java/io/openmessaging/benchmark/driver/kafka/KafkaTopicCreatorTest.java @@ -0,0 +1,122 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kafka; + +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.openmessaging.benchmark.driver.BenchmarkDriver.TopicInfo; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeoutException; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.CreateTopicsResult; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.common.KafkaFuture; +import org.apache.kafka.common.errors.TopicExistsException; +import org.apache.kafka.common.internals.KafkaFutureImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class KafkaTopicCreatorTest { + private final Map topicConfigs = new HashMap<>(); + private final String topic = "topic"; + private final int partitions = 1; + private final short replicationFactor = 1; + private final TopicInfo topicInfo = new TopicInfo(topic, partitions); + @Mock private AdminClient admin; + @Mock private CreateTopicsResult createTopicsResult; + @Captor private ArgumentCaptor> captor; + private KafkaTopicCreator topicCreator; + + @BeforeEach + void beforeEach() { + int maxBatchSize = 1; + topicCreator = new KafkaTopicCreator(admin, topicConfigs, replicationFactor, maxBatchSize); + + when(admin.createTopics(any())).thenAnswer(__ -> createTopicsResult); + } + + @Test + void created() { + KafkaFuture future = KafkaFuture.completedFuture(null); + + when(createTopicsResult.values()).thenReturn(singletonMap(topic, future)); + + topicCreator.create(singletonList(topicInfo)).join(); + + verify(admin).createTopics(captor.capture()); + + List> allValues = captor.getAllValues(); + assertThat(allValues).hasSize(1); + assertNewTopics(allValues.get(0)); + } + + @Test + void topicExists() { + KafkaFutureImpl future = new KafkaFutureImpl<>(); + future.completeExceptionally(new TopicExistsException(null)); + + when(createTopicsResult.values()).thenReturn(singletonMap(topic, future)); + + topicCreator.create(singletonList(topicInfo)).join(); + + verify(admin).createTopics(captor.capture()); + + List> allValues = captor.getAllValues(); + assertThat(allValues).hasSize(1); + assertNewTopics(allValues.get(0)); + } + + @Test + void timeout() { + KafkaFutureImpl future1 = new KafkaFutureImpl<>(); + future1.completeExceptionally(new TimeoutException()); + KafkaFuture future2 = KafkaFuture.completedFuture(null); + + when(createTopicsResult.values()) + .thenReturn(singletonMap(topic, future1)) + .thenReturn(singletonMap(topic, future2)); + + topicCreator.create(singletonList(topicInfo)).join(); + + verify(admin, times(2)).createTopics(captor.capture()); + + List> allValues = captor.getAllValues(); + assertThat(allValues).hasSize(2); + assertNewTopics(allValues.get(0)); + assertNewTopics(allValues.get(1)); + } + + private void assertNewTopics(List newTopics) { + assertThat(newTopics).hasSize(1); + NewTopic newTopic = newTopics.get(0); + assertThat(newTopic.name()).isEqualTo(topic); + assertThat(newTopic.numPartitions()).isEqualTo(partitions); + assertThat(newTopic.replicationFactor()).isEqualTo(replicationFactor); + assertThat(newTopic.configs()).isSameAs(topicConfigs); + } +} diff --git a/driver-kafka/src/test/resources/log4j2.yaml b/driver-kafka/src/test/resources/log4j2.yaml new file mode 100644 index 000000000..bd1f7cfe1 --- /dev/null +++ b/driver-kafka/src/test/resources/log4j2.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Configuration: + status: INFO + name: driver-kafka-test + + Appenders: + Console: + name: Console + target: SYSTEM_OUT + PatternLayout: + Pattern: "%d{HH:mm:ss.SSS} [%t] %-4level %c{1} - %msg%n" + Loggers: + Logger: + name: io.openmessaging.benchmark.driver.kafka + level: debug + Root: + level: info + additivity: false + AppenderRef: + - ref: Console diff --git a/driver-kop/kafka_to_kafka.yaml b/driver-kop/kafka_to_kafka.yaml new file mode 100644 index 000000000..d3a96a7cc --- /dev/null +++ b/driver-kop/kafka_to_kafka.yaml @@ -0,0 +1,39 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: Kafka producer and Pulsar consumer +driverClass: io.openmessaging.benchmark.driver.kop.KopBenchmarkDriver + +producerType: kafka +consumerType: kafka + +# Pulsar configs +pulsarConfig: + serviceUrl: pulsar://localhost:6650 + # producer configs + batchingEnabled: true + batchingMaxPublishDelayMs: 1 + batchingMaxBytes: 1048576 + blockIfQueueFull: true + pendingQueueSize: 1000 + maxPendingMessagesAcrossPartitions: 50000 + # consumer configs + maxTotalReceiverQueueSizeAcrossPartitions: 50000 + receiverQueueSize: 1000 + +# Kafka configs +kafkaConfig: | + bootstrap.servers=localhost:9092 + linger.ms=1 + batch.size=1048576 diff --git a/driver-kop/kafka_to_pulsar.yaml b/driver-kop/kafka_to_pulsar.yaml new file mode 100644 index 000000000..b1ecc256d --- /dev/null +++ b/driver-kop/kafka_to_pulsar.yaml @@ -0,0 +1,31 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: Kafka producer and Pulsar consumer +driverClass: io.openmessaging.benchmark.driver.kop.KopBenchmarkDriver + +producerType: kafka +consumerType: pulsar + +# Pulsar configs +pulsarConfig: + serviceUrl: pulsar://localhost:6650 + batchingMaxPublishDelayMs: 1 + batchingMaxBytes: 1048576 + +# Kafka configs +kafkaConfig: | + bootstrap.servers=localhost:9092 + linger.ms=1 + batch.size=1048576 diff --git a/driver-kop/pom.xml b/driver-kop/pom.xml new file mode 100644 index 000000000..def80e60b --- /dev/null +++ b/driver-kop/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + driver-kop + + + + ${project.groupId} + driver-api + ${project.version} + + + ${project.groupId} + driver-kafka + ${project.version} + + + ${project.groupId} + driver-pulsar + ${project.version} + + + io.streamnative.pulsar.handlers + kafka-payload-processor + 2.10.1.7 + + + org.apache.commons + commons-lang3 + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.testng + testng + 7.7.0 + test + + + + diff --git a/driver-kop/pulsar_to_kafka.yaml b/driver-kop/pulsar_to_kafka.yaml new file mode 100644 index 000000000..d587395c3 --- /dev/null +++ b/driver-kop/pulsar_to_kafka.yaml @@ -0,0 +1,31 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: Kafka producer and Pulsar consumer +driverClass: io.openmessaging.benchmark.driver.kop.KopBenchmarkDriver + +producerType: pulsar +consumerType: kafka + +# Pulsar configs +pulsarConfig: + serviceUrl: pulsar://localhost:6650 + batchingMaxPublishDelayMs: 1 + batchingMaxBytes: 1048576 + +# Kafka configs +kafkaConfig: | + bootstrap.servers=localhost:9092 + linger.ms=1 + batch.size=1048576 diff --git a/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/KopBenchmarkDriver.java b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/KopBenchmarkDriver.java new file mode 100644 index 000000000..32ccb6ba2 --- /dev/null +++ b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/KopBenchmarkDriver.java @@ -0,0 +1,245 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kop; + + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkConsumer; +import io.openmessaging.benchmark.driver.kafka.KafkaBenchmarkProducer; +import io.openmessaging.benchmark.driver.kop.config.ClientType; +import io.openmessaging.benchmark.driver.kop.config.Config; +import io.openmessaging.benchmark.driver.kop.config.PulsarConfig; +import io.openmessaging.benchmark.driver.pulsar.PulsarBenchmarkConsumer; +import io.openmessaging.benchmark.driver.pulsar.PulsarBenchmarkProducer; +import io.streamnative.pulsar.handlers.kop.KafkaPayloadProcessor; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import org.apache.bookkeeper.stats.StatsLogger; +import org.apache.kafka.clients.admin.AdminClient; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.ByteArrayDeserializer; +import org.apache.kafka.common.serialization.ByteArraySerializer; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.client.api.ConsumerBuilder; +import org.apache.pulsar.client.api.ProducerBuilder; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.client.api.SubscriptionType; +import org.apache.pulsar.common.util.FutureUtil; + +public class KopBenchmarkDriver implements BenchmarkDriver { + + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + private final List producers = new CopyOnWriteArrayList<>(); + private final List consumers = new CopyOnWriteArrayList<>(); + + private Config config; + private AdminClient admin; + private Properties producerProperties; + private Properties consumerProperties; + private PulsarClient client = null; + private ProducerBuilder producerBuilder = null; + private ConsumerBuilder consumerBuilder = null; + + public static Config loadConfig(File file) throws IOException { + return mapper.readValue(file, Config.class); + } + + @Override + public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { + config = loadConfig(configurationFile); + final Properties commonProperties = config.getKafkaProperties(); + admin = AdminClient.create(commonProperties); + + producerProperties = new Properties(); + commonProperties.forEach(producerProperties::put); + producerProperties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + producerProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, ByteArraySerializer.class); + + consumerProperties = new Properties(); + commonProperties.forEach(consumerProperties::put); + consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); + consumerProperties.put( + ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class); + + final PulsarConfig pulsarConfig = config.pulsarConfig; + if (config.producerType.equals(ClientType.PULSAR)) { + producerBuilder = + getPulsarClient(pulsarConfig.serviceUrl) + .newProducer() + .enableBatching(pulsarConfig.batchingEnabled) + .blockIfQueueFull(pulsarConfig.blockIfQueueFull) + .batchingMaxPublishDelay( + pulsarConfig.batchingMaxPublishDelayMs, TimeUnit.MILLISECONDS) + .batchingMaxBytes(pulsarConfig.batchingMaxBytes) + .maxPendingMessages(pulsarConfig.pendingQueueSize) + .maxPendingMessagesAcrossPartitions(pulsarConfig.maxPendingMessagesAcrossPartitions); + } + if (config.consumerType.equals(ClientType.PULSAR)) { + consumerBuilder = + getPulsarClient(pulsarConfig.serviceUrl) + .newConsumer(Schema.BYTEBUFFER) + .subscriptionType(SubscriptionType.Failover) + .receiverQueueSize(pulsarConfig.receiverQueueSize) + .maxTotalReceiverQueueSizeAcrossPartitions( + pulsarConfig.maxTotalReceiverQueueSizeAcrossPartitions); + } + } + + @Override + public String getTopicNamePrefix() { + return "test-topic"; + } + + @Override + public CompletableFuture createTopic(String topic, int partitions) { + // replicationFactor is meaningless in KoP + final NewTopic newTopic = new NewTopic(topic, partitions, (short) 1L); + final CompletableFuture future = new CompletableFuture<>(); + admin + .createTopics(Collections.singletonList(newTopic)) + .all() + .whenComplete( + (result, throwable) -> { + if (throwable == null) { + future.complete(result); + } else { + future.completeExceptionally(throwable); + } + }); + return future; + } + + @Override + public CompletableFuture createProducer(String topic) { + if (config.producerType.equals(ClientType.KAFKA)) { + final BenchmarkProducer producer = + new KafkaBenchmarkProducer(new KafkaProducer<>(producerProperties), topic); + producers.add(producer); + return CompletableFuture.completedFuture(producer); + } else if (config.consumerType.equals(ClientType.PULSAR)) { + return producerBuilder + .clone() + .topic(topic) + .createAsync() + .thenApply(PulsarBenchmarkProducer::new); + } else { + throw new IllegalArgumentException("producerType " + config.producerType + " is invalid"); + } + } + + @SuppressWarnings("checkstyle:LineLength") + @Override + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { + if (config.consumerType.equals(ClientType.KAFKA)) { + final Properties properties = new Properties(); + consumerProperties.forEach(properties::put); + properties.put(ConsumerConfig.GROUP_ID_CONFIG, subscriptionName); + properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + final KafkaConsumer kafkaConsumer = new KafkaConsumer<>(properties); + kafkaConsumer.subscribe(Collections.singleton(topic)); + final BenchmarkConsumer consumer = + new KafkaBenchmarkConsumer( + kafkaConsumer, properties, consumerCallback, config.pollTimeoutMs); + consumers.add(consumer); + return CompletableFuture.completedFuture(consumer); + } else if (config.consumerType.equals(ClientType.PULSAR)) { + final List>> futures = new ArrayList<>(); + return client + .getPartitionsForTopic(topic) + .thenCompose( + partitions -> { + partitions.forEach( + p -> + futures.add( + createInternalPulsarConsumer(p, subscriptionName, consumerCallback))); + return FutureUtil.waitForAll(futures); + }) + .thenApply( + __ -> + new PulsarBenchmarkConsumer( + futures.stream().map(CompletableFuture::join).collect(Collectors.toList()))); + } else { + throw new IllegalArgumentException("consumerType " + config.consumerType + " is invalid"); + } + } + + @Override + public void close() throws Exception { + for (BenchmarkProducer producer : producers) { + producer.close(); + } + for (BenchmarkConsumer consumer : consumers) { + consumer.close(); + } + admin.close(); + if (client != null) { + client.close(); + } + } + + private PulsarClient getPulsarClient(String serviceUrl) throws PulsarClientException { + if (client == null) { + client = PulsarClient.builder().serviceUrl(serviceUrl).build(); + } + return client; + } + + private CompletableFuture> createInternalPulsarConsumer( + String topic, String subscriptionName, ConsumerCallback callback) { + return consumerBuilder + .clone() + .topic(topic) + .subscriptionName(subscriptionName) + .messagePayloadProcessor( + new KafkaPayloadProcessor()) // support consuming Kafka format messages + .poolMessages(true) + .messageListener( + (c, msg) -> { + try { + callback.messageReceived(msg.getValue(), msg.getPublishTime()); + c.acknowledgeAsync(msg); + } finally { + msg.release(); + } + }) + .subscribeAsync(); + } +} diff --git a/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/ClientType.java b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/ClientType.java new file mode 100644 index 000000000..0f279f645 --- /dev/null +++ b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/ClientType.java @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kop.config; + + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum ClientType { + @JsonProperty("kafka") + KAFKA, + @JsonProperty("pulsar") + PULSAR +} diff --git a/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/Config.java b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/Config.java new file mode 100644 index 000000000..36cc4b0fe --- /dev/null +++ b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/Config.java @@ -0,0 +1,46 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kop.config; + + +import java.io.IOException; +import java.io.StringReader; +import java.util.Properties; +import org.apache.commons.lang3.StringUtils; +import org.apache.kafka.clients.producer.ProducerConfig; + +public class Config { + + public ClientType producerType; + public ClientType consumerType; + public long pollTimeoutMs = 100; + public PulsarConfig pulsarConfig; + public String kafkaConfig; + + public Properties getKafkaProperties() { + if (StringUtils.isEmpty(kafkaConfig)) { + throw new IllegalArgumentException(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG + " is not set"); + } + final Properties props = new Properties(); + try { + props.load(new StringReader(kafkaConfig)); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + if (props.get(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG) == null) { + throw new IllegalArgumentException(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG + " is not set"); + } + return props; + } +} diff --git a/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/PulsarConfig.java b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/PulsarConfig.java new file mode 100644 index 000000000..3017219af --- /dev/null +++ b/driver-kop/src/main/java/io/openmessaging/benchmark/driver/kop/config/PulsarConfig.java @@ -0,0 +1,31 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kop.config; + +public class PulsarConfig { + + public String serviceUrl; + + // producer configs + public boolean batchingEnabled = true; + public boolean blockIfQueueFull = true; + public int batchingMaxPublishDelayMs = 1; + public int batchingMaxBytes = 128 * 1024; + public int pendingQueueSize = 1000; + public int maxPendingMessagesAcrossPartitions = 50000; + + // consumer configs + public int maxTotalReceiverQueueSizeAcrossPartitions = 50000; + public int receiverQueueSize = 1000; +} diff --git a/driver-kop/src/test/java/io/openmessaging/benchmark/driver/kop/KopBenchmarkDriverTest.java b/driver-kop/src/test/java/io/openmessaging/benchmark/driver/kop/KopBenchmarkDriverTest.java new file mode 100644 index 000000000..277bdb146 --- /dev/null +++ b/driver-kop/src/test/java/io/openmessaging/benchmark/driver/kop/KopBenchmarkDriverTest.java @@ -0,0 +1,99 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.kop; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import io.openmessaging.benchmark.driver.kop.config.ClientType; +import io.openmessaging.benchmark.driver.kop.config.Config; +import io.openmessaging.benchmark.driver.kop.config.PulsarConfig; +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Properties; +import org.testng.annotations.Test; + +public class KopBenchmarkDriverTest { + + @Test + public void testLoadDefaultConfig() throws URISyntaxException, IOException { + final URL url = getClass().getClassLoader().getResource("kop_required.yaml"); + assertNotNull(url); + + final Config config = KopBenchmarkDriver.loadConfig(new File(url.toURI())); + assertEquals(config.producerType, ClientType.PULSAR); + assertEquals(config.consumerType, ClientType.KAFKA); + assertEquals(config.pollTimeoutMs, 100); + + final PulsarConfig pulsarConfig = config.pulsarConfig; + assertEquals(pulsarConfig.serviceUrl, "pulsar://localhost:6650"); + assertTrue(pulsarConfig.batchingEnabled); + assertEquals(pulsarConfig.batchingMaxPublishDelayMs, 1); + assertEquals(pulsarConfig.batchingMaxBytes, 131072); + assertTrue(pulsarConfig.blockIfQueueFull); + assertEquals(pulsarConfig.pendingQueueSize, 1000); + assertEquals(pulsarConfig.maxPendingMessagesAcrossPartitions, 50000); + assertEquals(pulsarConfig.maxTotalReceiverQueueSizeAcrossPartitions, 50000); + assertEquals(pulsarConfig.receiverQueueSize, 1000); + + assertEquals(config.getKafkaProperties().get("bootstrap.servers"), "localhost:9092"); + } + + @Test + public void testLoadCustomConfig() throws Exception { + final URL url = this.getClass().getClassLoader().getResource("kop_custom.yaml"); + assertNotNull(url); + + final Config config = KopBenchmarkDriver.loadConfig(new File(url.toURI())); + assertEquals(config.producerType, ClientType.KAFKA); + assertEquals(config.consumerType, ClientType.PULSAR); + assertEquals(config.pollTimeoutMs, 1000); + + final PulsarConfig pulsarConfig = config.pulsarConfig; + assertEquals(pulsarConfig.serviceUrl, "pulsar+ssl://localhost:6651"); + assertFalse(pulsarConfig.batchingEnabled); + assertEquals(pulsarConfig.batchingMaxPublishDelayMs, 10); + assertEquals(pulsarConfig.batchingMaxBytes, 1310720); + assertFalse(pulsarConfig.blockIfQueueFull); + assertEquals(pulsarConfig.pendingQueueSize, 10000); + assertEquals(pulsarConfig.maxPendingMessagesAcrossPartitions, 500000); + assertEquals(pulsarConfig.maxTotalReceiverQueueSizeAcrossPartitions, 500000); + assertEquals(pulsarConfig.receiverQueueSize, 10000); + + final Properties props = config.getKafkaProperties(); + assertEquals(props.size(), 3); + assertEquals(props.get("bootstrap.servers"), "localhost:9092"); + assertEquals(props.get("linger.ms"), "1"); + assertEquals(props.get("batch.size"), "1048576"); + } + + @Test + public void testLoadWrongKafkaConfig() throws Exception { + final URL url = this.getClass().getClassLoader().getResource("kop_wrong_kafka_config.yaml"); + assertNotNull(url); + + final Config config = KopBenchmarkDriver.loadConfig(new File(url.toURI())); + try { + config.getKafkaProperties(); + fail(); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "bootstrap.servers is not set"); + } + } +} diff --git a/driver-kop/src/test/resources/kop_custom.yaml b/driver-kop/src/test/resources/kop_custom.yaml new file mode 100644 index 000000000..755b40e27 --- /dev/null +++ b/driver-kop/src/test/resources/kop_custom.yaml @@ -0,0 +1,42 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# The KoP config file whose optional items are customized with different values from default. + +name: Kafka-on-Pulsar +driverClass: io.openmessaging.benchmark.driver.kop.KopBenchmarkDriver + +producerType: kafka +consumerType: pulsar +pollTimeoutMs: 1000 + +# Pulsar configs +pulsarConfig: + serviceUrl: pulsar+ssl://localhost:6651 + # producer configs + batchingEnabled: false + batchingMaxPublishDelayMs: 10 + batchingMaxBytes: 1310720 + blockIfQueueFull: false + pendingQueueSize: 10000 + maxPendingMessagesAcrossPartitions: 500000 + # consumer configs + maxTotalReceiverQueueSizeAcrossPartitions: 500000 + receiverQueueSize: 10000 + +# Kafka configs +kafkaConfig: | + bootstrap.servers=localhost:9092 + linger.ms=1 + batch.size=1048576 diff --git a/driver-kop/src/test/resources/kop_required.yaml b/driver-kop/src/test/resources/kop_required.yaml new file mode 100644 index 000000000..95548a775 --- /dev/null +++ b/driver-kop/src/test/resources/kop_required.yaml @@ -0,0 +1,29 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# The KoP config file with required config items. + +name: Kafka-on-Pulsar +driverClass: io.openmessaging.benchmark.driver.kop.KopBenchmarkDriver + +producerType: pulsar +consumerType: kafka + +# Pulsar configs +pulsarConfig: + serviceUrl: pulsar://localhost:6650 + +# Kafka configs +kafkaConfig: | + bootstrap.servers=localhost:9092 diff --git a/driver-kop/src/test/resources/kop_wrong_kafka_config.yaml b/driver-kop/src/test/resources/kop_wrong_kafka_config.yaml new file mode 100644 index 000000000..0fa6b4fa4 --- /dev/null +++ b/driver-kop/src/test/resources/kop_wrong_kafka_config.yaml @@ -0,0 +1,21 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# The KoP config file whose kafka config is wrong (without required configs) + +name: Kafka-on-Pulsar +driverClass: io.openmessaging.benchmark.driver.kop.KopBenchmarkDriver + +kafkaConfig: + linger.ms=1 diff --git a/driver-mqtt5/mqtt5.yaml b/driver-mqtt5/mqtt5.yaml new file mode 100644 index 000000000..995024666 --- /dev/null +++ b/driver-mqtt5/mqtt5.yaml @@ -0,0 +1,27 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: MQTT +driverClass: io.openmessaging.benchmark.driver.mqtt5.MqttBenchmarkDriver + +client: + serverUri: tcp://localhost:1883 + username: + password: + topicPrefix: benchmark + +consumer: + cleanSession: true + sessionExpiryIntervalSeconds: 259200 + receiveMaximum: 256 diff --git a/driver-mqtt5/pom.xml b/driver-mqtt5/pom.xml new file mode 100644 index 000000000..11e459a87 --- /dev/null +++ b/driver-mqtt5/pom.xml @@ -0,0 +1,49 @@ + + + + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + driver-mqtt5 + + + 1.3.8 + + + + + ${project.groupId} + driver-api + ${project.version} + + + com.google.guava + guava + + + com.hivemq + hivemq-mqtt-client + ${hive.mqtt.client.verson} + + + + diff --git a/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkConsumer.java b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkConsumer.java new file mode 100644 index 000000000..d9adef199 --- /dev/null +++ b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkConsumer.java @@ -0,0 +1,39 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.mqtt5; + + +import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; + +public class MqttBenchmarkConsumer implements BenchmarkConsumer { + private Mqtt5AsyncClient client; + private volatile boolean closed = false; + + public MqttBenchmarkConsumer() {} + + @Override + public void close() throws Exception { + MqttBenchmarkDriver.closeClient(client); + closed = true; + } + + public void setClient(Mqtt5AsyncClient client) { + this.client = client; + } + + public boolean isClosed() { + return closed; + } +} diff --git a/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkDriver.java b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkDriver.java new file mode 100644 index 000000000..2a716f568 --- /dev/null +++ b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkDriver.java @@ -0,0 +1,388 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.mqtt5; + + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.io.BaseEncoding; +import com.google.common.net.HostAndPort; +import com.hivemq.client.mqtt.MqttClientConfig; +import com.hivemq.client.mqtt.MqttClientTransportConfig; +import com.hivemq.client.mqtt.datatypes.MqttQos; +import com.hivemq.client.mqtt.datatypes.MqttUtf8String; +import com.hivemq.client.mqtt.lifecycle.MqttClientAutoReconnect; +import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import com.hivemq.client.mqtt.mqtt5.Mqtt5ClientBuilder; +import com.hivemq.client.mqtt.mqtt5.datatypes.Mqtt5UserProperties; +import com.hivemq.client.mqtt.mqtt5.datatypes.Mqtt5UserProperty; +import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck; +import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAckReasonCode; +import com.hivemq.client.mqtt.mqtt5.message.subscribe.Mqtt5Subscription; +import com.hivemq.client.mqtt.mqtt5.message.subscribe.suback.Mqtt5SubAckReasonCode; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.mqtt5.client.MqttConfig; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.bookkeeper.stats.StatsLogger; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MqttBenchmarkDriver implements BenchmarkDriver { + + private static final Logger log = LoggerFactory.getLogger(MqttBenchmarkDriver.class); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectWriter writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); + private static final Random random = new Random(); + private static final Pattern server_uri_pattern = + Pattern.compile("(?:[^:]*://)?([^:]+)(?::(\\w+))?"); + public static final MqttUtf8String USER_PROPERTY_KEY_PUBLISH_TIMESTAMP = + MqttUtf8String.of("benchmark-publish-timestamp"); + + private MqttConfig config; + + @Override + public void initialize(File configurationFile, StatsLogger statsLogger) + throws IOException, InterruptedException { + this.config = readConfig(configurationFile); + log.info("MqttBenchmarkDriver configuration: {}", writer.writeValueAsString(config)); + } + + @Override + public String getTopicNamePrefix() { + return config.client.topicPrefix + "/test"; + } + + @Override + public CompletableFuture createTopic(String topic, int partitions) { + // MQTT topics are created on the fly when messages are published or subscribed to. + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture createProducer(String topic) { + CompletableFuture future = new CompletableFuture<>(); + + MqttBenchmarkProducer producer = new MqttBenchmarkProducer(topic, config.client.qos); + Mqtt5ClientBuilder clientBuilder = + getClientBuilder(buildPublisherClientId(), producer::isClosed); + Mqtt5AsyncClient client = clientBuilder.buildAsync(); + client + .connect() + .whenComplete( + ((connAck, ex) -> { + if (handleConnResult(client, connAck, ex, future)) { + return; + } + producer.setClient(client); + future.complete(producer); + })); + + return future; + } + + @Override + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { + CompletableFuture future = new CompletableFuture<>(); + + MqttQos qos = intToQoS(config.client.qos); + List subscriptions = new ArrayList<>(); + Splitter.on(",") + .split(topic) + .forEach( + topicFilter -> { + topicFilter = topicFilter.trim(); + if (StringUtils.isNotEmpty(topicFilter)) { + Mqtt5Subscription subscription = + Mqtt5Subscription.builder() + // Use subscriptionName as shared subscription group name + .topicFilter(toSharedSubscription(topicFilter, subscriptionName)) + .qos(qos) + .build(); + subscriptions.add(subscription); + } + }); + + MqttBenchmarkConsumer consumer = new MqttBenchmarkConsumer(); + Mqtt5ClientBuilder clientBuilder = + getClientBuilder(buildSubscriberClientId(), consumer::isClosed); + Mqtt5AsyncClient client = clientBuilder.buildAsync(); + client + .subscribeWith() + .addSubscriptions(subscriptions) + .callback( + message -> { + long publishTime = extractPublishTimestamp(message.getUserProperties()); + consumerCallback.messageReceived(message.getPayloadAsBytes(), publishTime); + message.acknowledge(); + }) + .manualAcknowledgement(true) + .send() + .whenComplete( + ((subAck, ex) -> { + String clientId = extractClientId(client.getConfig()); + if (ex != null) { + log.error( + "Client[{}] failed to subscribe, subscriptions={}", + clientId, + subscriptions, + ex); + } else if (subAck == null || subAck.getReasonCodes().size() != subscriptions.size()) { + log.error( + "Client[{}] received invalid subAck={}, subscriptions={}", + clientId, + subAck, + subscriptions); + } else { + int size = subAck.getReasonCodes().size(); + for (int i = 0; i < size; i++) { + Mqtt5SubAckReasonCode reasonCode = subAck.getReasonCodes().get(i); + Mqtt5Subscription subscription = subscriptions.get(i); + if (reasonCode == Mqtt5SubAckReasonCode.GRANTED_QOS_0 + || reasonCode == Mqtt5SubAckReasonCode.GRANTED_QOS_1 + || reasonCode == Mqtt5SubAckReasonCode.GRANTED_QOS_2) { + log.info( + "Client[{}] subscribed topic-filters={}, qos={}, granted-qos={}", + clientId, + subscription.getTopicFilter(), + subscription.getQos().getCode(), + reasonCode.getCode()); + } else { + log.warn( + "Client[{}] failed to subscribe topic-filters={}, qos={}, " + + "reason-code={}", + clientId, + subscription.getTopicFilter(), + subscription.getQos().getCode(), + reasonCode.name()); + } + } + } + })); + + client + .connectWith() + .cleanStart(config.consumer.cleanSession) + .sessionExpiryInterval( + config.consumer.cleanSession ? 0 : config.consumer.sessionExpiryInterval) + .restrictions() + .receiveMaximum(config.consumer.receiveMaximum) + .applyRestrictions() + .send() + .whenComplete( + ((connAck, ex) -> { + if (handleConnResult(client, connAck, ex, future)) { + return; + } + consumer.setClient(client); + future.complete(consumer); + })); + + return future; + } + + private boolean handleConnResult( + Mqtt5AsyncClient client, Mqtt5ConnAck connAck, Throwable ex, CompletableFuture future) { + if (ex != null) { + future.completeExceptionally(ex); + log.error( + "Client[{}] failed to connect to MQTT broker", extractClientId(client.getConfig()), ex); + return true; + } + if (connAck.getReasonCode() != Mqtt5ConnAckReasonCode.SUCCESS) { + future.completeExceptionally( + new RuntimeException("ConnAck-ReasonCode: " + connAck.getReasonCode())); + log.warn( + "Client[{}] was rejected by MQTT broker, ConnAck-ReasonCode={}", + extractClientId(client.getConfig()), + connAck.getReasonCode()); + return true; + } + return false; + } + + private Mqtt5ClientBuilder getClientBuilder(String clientId, Supplier closed) { + HostAndPort hostAndPort = parseServerUri(this.config.client.serverUri); + Mqtt5ClientBuilder clientBuilder = + Mqtt5Client.builder() + .identifier(clientId) + .transportConfig( + MqttClientTransportConfig.builder() + .serverHost(hostAndPort.getHost()) + .serverPort(hostAndPort.getPort()) + .socketConnectTimeout(3, TimeUnit.SECONDS) + .mqttConnectTimeout(3, TimeUnit.SECONDS) + .build()); + + // Simple Auth with username and password + if (StringUtils.isNotEmpty(this.config.client.username) + && StringUtils.isNotEmpty(this.config.client.password)) { + clientBuilder = + clientBuilder + .simpleAuth() + .username(this.config.client.username) + .password(this.config.client.password.getBytes(StandardCharsets.UTF_8)) + .applySimpleAuth(); + } + + // Auto reconnect with initial delay 100 mills, max delay 10 seconds + clientBuilder = + clientBuilder.automaticReconnect( + MqttClientAutoReconnect.builder() + .initialDelay(100, TimeUnit.MILLISECONDS) + .maxDelay(10, TimeUnit.SECONDS) + .build()); + + // Listen to connection events + clientBuilder = + clientBuilder + .addConnectedListener( + context -> + log.info( + "Client[{}] connected to MQTT broker {}", + extractClientId(context.getClientConfig()), + context.getClientConfig().getServerAddress())) + .addDisconnectedListener( + context -> { + String clientId1 = extractClientId(context.getClientConfig()); + log.warn( + "Client[{}] lost connection to MQTT broker {}, by {}", + clientId1, + context.getClientConfig().getServerAddress(), + context.getSource().name(), + context.getCause()); + if (closed.get()) { + log.warn( + "Client[{}] stops reconnecting to MQTT broker since the client" + + " wasn't created successfully or has been stopped already", + clientId1); + context.getReconnector().reconnect(false); + } + }); + + return clientBuilder; + } + + @Override + public void close() throws Exception { + // Nothing to close + } + + private static MqttConfig readConfig(File configurationFile) throws IOException { + return mapper.readValue(configurationFile, MqttConfig.class); + } + + private static HostAndPort parseServerUri(String serverUri) { + Matcher matcher = server_uri_pattern.matcher(serverUri); + if (matcher.find()) { + String host = matcher.group(1); + String portStr = matcher.group(2); + int port = StringUtils.isNotEmpty(portStr) ? Integer.parseInt(portStr) : 80; + return HostAndPort.fromParts(host, port); + } else { + throw new IllegalArgumentException("Invalid serverUri: " + serverUri); + } + } + + private static String getRandomString() { + byte[] buffer = new byte[5]; + random.nextBytes(buffer); + return BaseEncoding.base64Url().omitPadding().encode(buffer); + } + + private static String buildPublisherClientId() { + return Joiner.on("_").join("benchmark", "pub", getRandomString(), System.currentTimeMillis()); + } + + private static String buildSubscriberClientId() { + return Joiner.on("_").join("benchmark", "sub", getRandomString(), System.currentTimeMillis()); + } + + private static String extractClientId(MqttClientConfig clientConfig) { + if (clientConfig.getClientIdentifier().isPresent()) { + return clientConfig.getClientIdentifier().get().toString(); + } + return ""; + } + + private static String toSharedSubscription(String topicFilter, String sharedGroup) { + if (StringUtils.isEmpty(topicFilter)) { + return topicFilter; + } + + if (topicFilter.startsWith("$share")) { + return topicFilter; + } + + return Joiner.on('/').join("$share", sharedGroup, topicFilter); + } + + // Extract publishTimestamp from user properties, return System.currentTimeMillis() if not found + private static long extractPublishTimestamp(Mqtt5UserProperties userProperties) { + List propertyList = userProperties.asList(); + for (Mqtt5UserProperty property : propertyList) { + if (USER_PROPERTY_KEY_PUBLISH_TIMESTAMP.equals(property.getName())) { + try { + return Long.parseLong(property.getValue().toString()); + } catch (NumberFormatException ignore) { + return System.currentTimeMillis(); + } + } + } + return System.currentTimeMillis(); + } + + public static MqttQos intToQoS(int val) { + MqttQos qos = MqttQos.fromCode(val); + if (qos == null) { + qos = MqttQos.AT_LEAST_ONCE; + } + return qos; + } + + public static void closeClient(Mqtt5AsyncClient client) { + if (client != null) { + String clientId = String.valueOf(client.getConfig().getClientIdentifier()); + log.info("Client[{}] disconnecting...", clientId); + client + .disconnect() + .exceptionally( + ex -> { + log.error("Client[{}] failed to disconnect", clientId, ex); + return null; + }); + } + } +} diff --git a/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkProducer.java b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkProducer.java new file mode 100644 index 000000000..f0f6e98dc --- /dev/null +++ b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/MqttBenchmarkProducer.java @@ -0,0 +1,89 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.mqtt5; + + +import com.hivemq.client.mqtt.datatypes.MqttQos; +import com.hivemq.client.mqtt.datatypes.MqttUtf8String; +import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; +import com.hivemq.client.mqtt.mqtt5.datatypes.Mqtt5UserProperties; +import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MqttBenchmarkProducer implements BenchmarkProducer { + + private static final Logger log = LoggerFactory.getLogger(MqttBenchmarkProducer.class); + + private final String topic; + private final MqttQos qos; + private Mqtt5AsyncClient client; + private volatile boolean closed = false; + + public MqttBenchmarkProducer(String topic, int qosCode) { + this.topic = topic; + this.qos = MqttBenchmarkDriver.intToQoS(qosCode); + } + + @Override + public CompletableFuture sendAsync(Optional key, byte[] payload) { + + Mqtt5UserProperties properties = + Mqtt5UserProperties.builder() + .add( + MqttBenchmarkDriver.USER_PROPERTY_KEY_PUBLISH_TIMESTAMP, + MqttUtf8String.of(String.valueOf(System.currentTimeMillis()))) + .build(); + Mqtt5Publish message = + Mqtt5Publish.builder() + .topic(topic) + .payload(payload) + .qos(qos) + .userProperties(properties) + .build(); + + CompletableFuture future = new CompletableFuture<>(); + this.client + .publish(message) + .whenComplete( + ((result, ex) -> { + if (ex != null || result.getError().isPresent()) { + Throwable error = ex != null ? ex : result.getError().get(); + future.completeExceptionally(error); + log.error("Client[{}] failed to publish MQTT message, topic={}", topic, error); + } else { + future.complete(null); + } + })); + + return future; + } + + @Override + public void close() throws Exception { + MqttBenchmarkDriver.closeClient(client); + closed = true; + } + + public void setClient(Mqtt5AsyncClient client) { + this.client = client; + } + + public boolean isClosed() { + return closed; + } +} diff --git a/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttClientConfig.java b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttClientConfig.java new file mode 100644 index 000000000..2fd88cbb0 --- /dev/null +++ b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttClientConfig.java @@ -0,0 +1,31 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.mqtt5.client; + +public class MqttClientConfig { + /** The MQTT server URI. */ + public String serverUri = "tcp://localhost:1883"; + + /** The username used for MQTT server-side authentication. */ + public String username = ""; + + /** The password that matches the username. */ + public String password = ""; + + /** The Quality of Service level for message delivery (0, 1, or 2). */ + public int qos = 1; + + /** The topic prefix for topics used in the benchmark. No need to add a trailing slash. */ + public String topicPrefix = "benchmark"; +} diff --git a/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttConfig.java b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttConfig.java new file mode 100644 index 000000000..1ca7e81f8 --- /dev/null +++ b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttConfig.java @@ -0,0 +1,19 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.mqtt5.client; + +public class MqttConfig { + public MqttClientConfig client = new MqttClientConfig(); + public MqttConsumerConfig consumer = new MqttConsumerConfig(); +} diff --git a/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttConsumerConfig.java b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttConsumerConfig.java new file mode 100644 index 000000000..cf3a992b5 --- /dev/null +++ b/driver-mqtt5/src/main/java/io/openmessaging/benchmark/driver/mqtt5/client/MqttConsumerConfig.java @@ -0,0 +1,25 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.mqtt5.client; + +public class MqttConsumerConfig { + /** Consume in clean session mode or not. */ + public Boolean cleanSession = true; + + /** The session expiry interval in seconds when cleanSession is false. */ + public Integer sessionExpiryInterval = 3 * 24 * 60 * 60; + + /** The maximum number of unacknowledged QoS 1 and 2 messages. */ + public Integer receiveMaximum = 256; +} diff --git a/driver-nats-streaming/README.md b/driver-nats-streaming/README.md new file mode 100644 index 000000000..74685537b --- /dev/null +++ b/driver-nats-streaming/README.md @@ -0,0 +1,151 @@ +# NATS Streaming benchmarks + +> **Warning** +> This module relates to [NATS Streaming / STAN](https://docs.nats.io/legacy/stan) which has been deprecated +> and replaced by [NATS JetStream](https://docs.nats.io/nats-concepts/jetstream). We do not yet have a benchmark +> driver for JetStream. + +This folder houses the assets necessary to run benchmarks for +[NATS Streaming](https://docs.nats.io/legacy/stan). In order to run these benchmarks, you'll need to: + +* [Create the necessary local artifacts](#creating-local-artifacts) +* [Stand up a NATS cluster](#creating-a-nats-cluster-on-amazon-web-services-aws-using-terraform-and-ansible) + on Amazon Web Services (which includes a client host for running the benchmarks) +* [SSH into the client host](#sshing-into-the-client-host) +* [Run the benchmarks from the client host](#running-the-benchmarks-from-the-client-host) + +## Creating local artifacts + +In order to create the local artifacts necessary to run the NATS benchmarks in AWS, you'll need to have +[Maven](https://maven.apache.org/install.html) installed. Once Maven's installed, you can create the necessary +artifacts with a single Maven command: + +```bash +$ git clone https://github.com/openmessaging/benchmark.git +% cd messaging-benchmark +$ mvn install +``` + +## Creating a NATS cluster on Amazon Web Services (AWS) using Terraform and Ansible + +In order to create an NATS cluster on AWS, you'll need to have the following installed: + +* [Terraform](https://terraform.io) +* [The `terraform-inventory` plugin for Terraform](https://github.com/adammck/terraform-inventory) +* [Ansible](http://docs.ansible.com/ansible/latest/intro_installation.html) + +In addition, you will need to: + +* [Create an AWS account](https://aws.amazon.com/account/) (or use an existing account) +* [Install the `aws` CLI tool](https://aws.amazon.com/cli/) +* [Configure the `aws` CLI tool](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html) + +Once those conditions are in place, you'll need to create an SSH public and private key at `~/.ssh/nats_streaming_aws` +(private) and `~/.ssh/nats_streaming_aws.pub` (public), respectively. + +```bash +$ ssh-keygen -f ~/.ssh/nats_streaming_aws +``` + +When prompted to enter a passphrase, simply hit **Enter** twice. Then, make sure that the keys have been created: + +```bash +$ ls ~/.ssh/nats_streaming_aws* +``` + +With SSH keys in place, you can create the necessary AWS resources using a single Terraform command: + +```bash +$ cd driver-nats-streaming/deploy +$ terraform init +$ terraform apply +``` + +That will install the following [EC2](https://aws.amazon.com/ec2) instances (plus some other resources, such as a +[Virtual Private Cloud](https://aws.amazon.com/vpc/) (VPC)): + +| Resource | Description | Count | +|:--------------------|:------------------------------------------------------------|:------| +| NATS instances | The VMs on which NATS brokers will run | 3 | +| Client instance | The VM from which the benchmarking suite itself will be run | 4 | +| Prometheus instance | The VM on which metrics services will be run | 1 | + +When you run `terraform apply`, you will be prompted to type `yes`. Type `yes` to continue with the installation or +anything else to quit. + +Once the installation is complete, you will see a confirmation message listing the resources that have been installed. + +### Variables + +There's a handful of configurable parameters related to the Terraform deployment that you can alter by modifying the +defaults in the `terraform.tfvars` file. + +| Variable | Description | Default | +|:------------------|:------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------| +| `region` | The AWS region in which the NATS cluster will be deployed | `us-west-2` | +| `az` | The availability zone in which the NATS cluster will be deployed | `us-west-2a` | +| `public_key_path` | The path to the SSH public key that you've generated | `~/.ssh/rabbitmq_aws.pub` | +| `ami` | The [Amazon Machine Image](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) (AWI) to be used by the cluster's machines | [`ami-9fa343e7`](https://access.redhat.com/articles/3135091) | +| `instance_types` | The EC2 instance types used by the various components | `i3.4xlarge` (NATS brokers), `c4.8xlarge` (benchmarking clients) | + +> If you modify the `public_key_path`, make sure that you point to the appropriate SSH key path when running the +> [Ansible playbook](#running-the-ansible-playbook). + +### Running the Ansible playbook + +With the appropriate infrastructure in place, you can install and start the RabbitMQ cluster using Ansible with just +one command. Note that a `TFSTATE` environment must point to the folder in which the `tf.state` file is located. + +```bash +$ TF_STATE=. ansible-playbook \ + --user ec2-user \ + --inventory `which terraform-inventory` \ + deploy.yaml +``` + +> If you're using an SSH private key path different from `~/.ssh/nats_streaming_aws`, you can specify that path using +> the `--private-key` flag, for example `--private-key=~/.ssh/my_key`. + +## SSHing into the client host + +In the [output](https://www.terraform.io/intro/getting-started/outputs.html) produced by Terraform, there's a +`client_ssh_host` variable that provides the IP address for the client EC2 host from which benchmarks can be run. +You can SSH into that host using this command: + +```bash +$ ssh -i ~/.ssh/nats_streaming_aws ec2-user@$(terraform output client_ssh_host) +``` + +## Running the benchmarks from the client host + +Once you've successfully SSHed into the client host, you can run all +[available benchmark workloads](../#benchmarking-workloads) like this: + +```bash +$ cd /opt/benchmark +$ sudo bin/benchmark --drivers driver-nats-streaming/nats-streaming.yaml workloads/*.yaml +``` + +You can also run specific workloads in the `workloads` folder. Here's an example: + +```bash +$ sudo bin/benchmark --drivers driver-nats-streaming/nats-streaming.yaml workloads/1-topic-1-partitions-1kb.yaml +``` + +## Monitoring + +### Prometheus + +The [`prometheus-nats-exporter`](https://github.com/nats-io/prometheus-nats-exporter) +service is installed and Prometheus is installed on a standalone instance, along with +[Node Exporter](https://github.com/prometheus/node_exporter) on all brokers to allow the collection of system metrics. +Prometheus exposes a public endpoint `http://${prometheus_host}:9090`. + +### Grafana + +Grafana and a set of standard dashboards are installed alongside Prometheus. These are exposed on a public endpoint +`http://${prometheus_host}:3000`. Credentials are `admin`/`admin`. Dashboards included: +* [NATS dashboards](https://github.com/nats-io/prometheus-nats-exporter/blob/main/walkthrough/README.md) +* [NATS streaming dashboard](https://github.com/nats-io/prometheus-nats-exporter/blob/main/walkthrough/streaming.md) +* [Node Exporter dashboard](https://grafana.com/grafana/dashboards/1860-node-exporter-full/) + diff --git a/driver-nats-streaming/deploy/ali/ansible.cfg b/driver-nats-streaming/deploy/ali/ansible.cfg new file mode 100644 index 000000000..15d972b75 --- /dev/null +++ b/driver-nats-streaming/deploy/ali/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +host_key_checking=false +private_key_file=alicloud.pem diff --git a/driver-nats-streaming/deploy/provision-nats-streaming-ali.tf b/driver-nats-streaming/deploy/ali/provision-nats-streaming-ali.tf similarity index 100% rename from driver-nats-streaming/deploy/provision-nats-streaming-ali.tf rename to driver-nats-streaming/deploy/ali/provision-nats-streaming-ali.tf diff --git a/driver-nats-streaming/deploy/ali/terraform.tfvars b/driver-nats-streaming/deploy/ali/terraform.tfvars new file mode 100644 index 000000000..1b872e9e8 --- /dev/null +++ b/driver-nats-streaming/deploy/ali/terraform.tfvars @@ -0,0 +1,15 @@ +region = "cn-shenzhen" +availability_zone = "cn-shenzhen-c" +private_key_file = "alicloud.pem" +key_name = "key-pair-from-terraform-nats-streaming" +image_id = "centos_7_04_64_20G_alibase_201701015.vhd" + +instance_types = { + "nats-streaming-server" = "ecs.se1.4xlarge" #4c16g + "client" = "ecs.n4.4xlarge" +} + +num_instances = { + "nats-streaming-server" = 3 + "client" = 2 +} \ No newline at end of file diff --git a/driver-nats-streaming/deploy/ansible.cfg b/driver-nats-streaming/deploy/ansible.cfg index 15d972b75..4679241b7 100644 --- a/driver-nats-streaming/deploy/ansible.cfg +++ b/driver-nats-streaming/deploy/ansible.cfg @@ -1,3 +1,8 @@ [defaults] host_key_checking=false -private_key_file=alicloud.pem +private_key_file=~/.ssh/nats_streaming_aws + +[privilege_escalation] +become=true +become_method='sudo' +become_user='root' \ No newline at end of file diff --git a/driver-nats-streaming/deploy/deploy.yaml b/driver-nats-streaming/deploy/deploy.yaml index ab0f2ab13..f0e9cff62 100644 --- a/driver-nats-streaming/deploy/deploy.yaml +++ b/driver-nats-streaming/deploy/deploy.yaml @@ -1,29 +1,49 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # +- name: Format and mount disks for NATS hosts + hosts: nats + connection: ssh + become: true + tasks: + - name: NATS - Format disks + filesystem: + fstype: xfs + dev: '{{ item }}' + with_items: + - '/dev/nvme1n1' + - name: NATS - Mount disks + mount: + path: "{{ item.path }}" + src: "{{ item.src }}" + fstype: xfs + opts: defaults,noatime,nodiscard + state: mounted + with_items: + - { path: "/mnt/data", src: "/dev/nvme1n1" } + - name: NATS - Set filesystem permissions + file: + path: "/mnt/data" + state: touch + mode: "0777" -- name: Install NATS-Streaming Cluster - hosts: nats-streaming-server +- name: NATS - Install Cluster + hosts: nats connection: ssh tasks: - set_fact: - natsHostUrl: "{{ hostvars[groups['nats-streaming-server'][0]].private_ip }}" + natsHostUrl: "{{ hostvars[groups['nats'][0]].private_ip }}" private_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" - name: Install RPM packages yum: pkg={{ item }} state=latest @@ -33,102 +53,356 @@ - file: path=/opt/nats-streaming state=absent - file: path=/opt/nats-streaming state=directory - - name: Install Nats-streaming Server + - name: NATS - Install server binary unarchive: - src: "https://github.com/nats-io/nats-streaming-server/releases/download/v0.11.2/nats-streaming-server-v0.11.2-linux-amd64.zip" + src: "https://github.com/nats-io/nats-streaming-server/releases/download/v0.25.2/nats-streaming-server-v0.25.2-linux-amd64.zip" remote_src: yes dest: /opt/nats-streaming - - template: + - name: NATS - Apply server configuration + template: src: "templates/cluster.conf" dest: "/opt/nats-streaming/cluster.conf" - - template: + - name: NATS - Configure server systemd service + template: src: "templates/nats-streaming-server.service" dest: "/etc/systemd/system/nats-streaming-server.service" - - - replace: + - name: NATS - Inject cluster URL + replace: dest: /opt/nats-streaming/cluster.conf regexp: 'natsHostUrl' replace: '{{natsHostUrl}}' - - replace: + - name: NATS - Inject cluster private IP + replace: dest: /opt/nats-streaming/cluster.conf regexp: 'localhost' replace: '{{private_ip}}' - - replace: + - name: NATS - Inject cluster leader setting + replace: dest: /opt/nats-streaming/cluster.conf regexp: 'false' replace: 'true' - when: groups['nats-streaming-server'][0] == inventory_hostname - - replace: + when: groups['nats'][0] == inventory_hostname + - name: NATS - Inject cluster hostname + replace: dest: /opt/nats-streaming/cluster.conf regexp: 'routes' replace: '#routes' - when: groups['nats-streaming-server'][0] == inventory_hostname - - - systemd: + when: groups['nats'][0] == inventory_hostname + - name: NATS - Start service + systemd: state: started daemon_reload: yes name: "nats-streaming-server" +- name: Install NATS Prometheus exporters + hosts: nats + connection: ssh + become: true + tasks: + - name: NATSExporter - Configure yum Docker repo + tags: ['nse'] + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: NATSExporter - Install Docker + tags: ['nse'] + yum: + state: latest + pkg: ['docker-ce'] + - name: NATSExporter - Start docker + tags: ['nse'] + service: + name: docker + state: started + enabled: yes + +- name: Configure NATS Prometheus exporters + hosts: nats + connection: ssh + become: true + tasks: + - file: path=/opt/nats-streaming-metrics state=absent + tags: ['nse'] + - file: path=/opt/nats-streaming-metrics state=directory + tags: ['nse'] + - name: NATSExporter - Configure systemd + tags: ['nse'] + template: + src: "templates/nats-streaming-metrics.service" + dest: "/etc/systemd/system/nats-streaming-metrics.service" + - name: NATSExporter - Restart NATS exporter + tags: ['nse'] + systemd: + state: restarted + daemon_reload: yes + name: "nats-streaming-metrics.service" + +- name: Install Node exporters + hosts: nats + connection: ssh + become: true + tasks: + - name: NodeExporter - Set software versions + set_fact: + nodeExporterVersion: 1.2.2 + - name: NodeExporter - Set binary source URL + set_fact: + nodeExporterBinary: + src: "https://github.com/prometheus/node_exporter/releases/download/v{{ nodeExporterVersion }}/node_exporter-{{ nodeExporterVersion }}.linux-amd64.tar.gz" + remote: yes + when: nodeExporterBinary is not defined + - name: NodeExporter - Add node_exporter user + user: + name: node_exporter + shell: /bin/false + system: true + create_home: no + - name: NodeExporter - Download and extract + unarchive: + src: "{{ nodeExporterBinary.src }}" + dest: /tmp + remote_src: "{{ nodeExporterBinary.remote }}" + - name: NodeExporter - Install binary + copy: + src: "/tmp/node_exporter-{{ nodeExporterVersion }}.linux-amd64/node_exporter" + remote_src: yes + dest: /usr/local/bin/ + owner: node_exporter + group: node_exporter + mode: u+x,g+x,o+x + - name: NodeExporter - Create service + blockinfile: + path: /etc/systemd/system/node_exporter.service + block: | + [Unit] + Description=Prometheus Node Exporter + Wants=network-online.target + After=network-online.target + [Service] + User=node_exporter + Group=node_exporter + Type=simple + ExecStart=/usr/local/bin/node_exporter + [Install] + WantedBy=multi-user.target + create: true + - name: NodeExporter - Reload daemon configuration + systemd: + daemon_reload: yes + - name: NodeExporter - Start and enable service + service: + name: node_exporter + state: started + enabled: yes + - name: NodeExporter - Check port 9100 availability + wait_for: + port: 9100 + state: started + timeout: 5 + +- name: Prometheus installation + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Prometheus - Set software versions + set_fact: + prometheusVersion: 2.31.1 + - name: Prometheus - Set binary source URL + set_fact: + prometheusBinary: + src: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheusVersion }}/prometheus-{{ prometheusVersion }}.linux-amd64.tar.gz" + remote: yes + - name: Prometheus - Add RHEL yum repo + shell: yum-config-manager --enable rhui-REGION-rhel-server-extras + when: + - ansible_facts['distribution'] == 'RedHat' + - ansible_facts['distribution_major_version'] | int <= 7 + - name: Prometheus - Create install folders + file: path=/opt/prometheus/data state=absent + - file: path=/opt/prometheus/data state=directory + - name: Prometheus - Download and unarchive binary + unarchive: + src: "{{ prometheusBinary.src }}" + remote_src: "{{ prometheusBinary.remote }}" + dest: /opt/prometheus + extra_opts: ["--strip-components=1"] -- name: benchmarking client setup +- name: Prometheus setup + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Prometheus - Configure systemd + template: + src: "templates/prometheus.service" + dest: "/etc/systemd/system/prometheus.service" + - name: Prometheus - Configure service + template: + src: "templates/prometheus.yml" + dest: "/opt/prometheus/prometheus.yml" + - name: Prometheus - Restart service + systemd: + state: restarted + daemon_reload: yes + name: "prometheus" + +- name: Grafana installation + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Grafana - Configure yum Docker repo + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: Grafana - Install Docker + yum: + state: latest + pkg: ['docker-ce'] + - name: Grafana - Start docker + service: + name: docker + state: started + enabled: yes + - name: Grafana - Create install folders + file: path=/opt/grafana state=absent + - file: path=/opt/grafana state=directory + - file: path=/repos/prometheus-nats-exporter state=absent + - file: path=/repos/prometheus-nats-exporter state=directory + - file: path=/repos/grafana-dashboards state=absent + - file: path=/repos/grafana-dashboards state=directory + - name: Grafana - Install Git RPM packages + yum: pkg={{ item }} state=latest + with_items: + - git + - name: Grafana - Clone nats-io/prometheus-nats-exporter repository + git: + repo: https://github.com/nats-io/prometheus-nats-exporter.git + dest: /repos/prometheus-nats-exporter + clone: yes + update: yes + - name: Grafana - Clone rfmoz/grafana-dashboard repository + git: + repo: https://github.com/rfmoz/grafana-dashboards.git + dest: /repos/grafana-dashboards + clone: yes + update: yes + - name: Grafana - Copy node_exporter dashboard + copy: remote_src=True src=/repos/grafana-dashboards/prometheus/node-exporter-full.json dest=/repos/prometheus-nats-exporter/walkthrough/ + +- name: Grafana setup + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Grafana - Create data folders + file: path=/opt/nats-streaming state=absent + - file: path=/opt/nats-streaming state=directory + - name: Grafana - Configure Dashboards + template: + src: "templates/grafana-dashboards.yml" + dest: "/opt/nats-streaming/dashboards.yml" + - name: Grafana - Configure Prometheus datasource + template: + src: "templates/grafana-datasource.yml" + dest: "/opt/nats-streaming/grafana-datasource.yml" + - name: Grafana - Configure systemd + template: + src: "templates/nats-streaming-dashboard.service" + dest: "/etc/systemd/system/nats-streaming-dashboard.service" + - name: Grafana - Restart Grafana + systemd: + state: restarted + daemon_reload: yes + name: "nats-streaming-dashboard.service" + +- name: Chrony setup + hosts: client + connection: ssh + become: true + tasks: + - name: Chrony - Configure + template: + src: "templates/chrony.conf" + dest: "/etc/chrony.conf" + - name: Chrony - Restart + systemd: + state: restarted + daemon_reload: yes + name: "chronyd" + +- name: Benchmarking client setup hosts: client connection: ssh become: true tasks: - set_fact: - natsHostUrl: "{{ hostvars[groups['nats-streaming-server'][0]].private_ip }}" - - name: Install RPM packages + natsHostUrl: "{{ hostvars[groups['nats'][0]].private_ip }}" + - name: Benchmark - Install RPM packages yum: pkg={{ item }} state=latest with_items: - java - - file: path=/opt/benchmark state=absent + - name: Benchmark - Create folders + file: path=/opt/benchmark state=absent - file: path=/opt/benchmark state=directory - - name: Copy benchmark code + - name: Benchmark - Copy code unarchive: src: ../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz dest: /opt - - shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT/* /opt/benchmark - - shell: tuned-adm profile latency-performance - - template: + - name: Benchmark - Install code + shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT/* /opt/benchmark + - name: Benchmark - Tune kernel + shell: tuned-adm profile latency-performance + - name: Benchmark - Configure workers + template: src: "templates/workers.yaml" dest: "/opt/benchmark/workers.yaml" - - name: Get list of driver config files + - name: Benchmark - Get list of driver config files raw: ls -1 /opt/benchmark/driver-nats-streaming/*.yaml register: drivers_list - - - name: Configure natsHost URL + - name: Benchmark - Configure natsHost URL lineinfile: dest: /opt/benchmark/driver-nats-streaming/nats-streaming.yaml regexp: '^natsHostUrl\: ' line: 'natsHostUrl: nats://{{natsHostUrl}}:4222' - - name: Configure memory + - name: Benchmark - Configure worker memory lineinfile: dest: /opt/benchmark/bin/benchmark-worker regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xms12G -Xmx12G -XX:+UseG1GC -XX:MaxGCPauseMillis=10 -XX:+ParallelRefProcEnabled -XX:+UnlockExperimentalVMOptions -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=32 -XX:ConcGCThreads=32 -XX:G1NewSizePercent=50 -XX:+DisableExplicitGC -XX:-ResizePLAB -XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch -XX:-UseBiasedLocking"' - - name: Configure memory + - name: Benchmark - Configure client memory lineinfile: dest: /opt/benchmark/bin/benchmark regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xmx4G"' - - name: Install benchmark systemd service + - name: Benchmark - Install systemd service template: src: "templates/benchmark-worker.service" dest: "/etc/systemd/system/benchmark-worker.service" - - systemd: + - name: Benchmark - Start service + systemd: state: restarted daemon_reload: yes name: "benchmark-worker" - - name: List host addresses hosts: localhost become: false tasks: - debug: - msg: "nats-streaming brokers {{ item }}" - with_items: "{{ groups['nats-streaming-server'] }}" + msg: "NATS Streaming brokers {{ item }}" + with_items: "{{ groups['nats'] }}" - debug: msg: "Benchmark client {{ item }}" with_items: "{{ groups['client'] }}" + - debug: + msg: "Prometheus servers {{ item }}" + with_items: "{{ groups['prometheus'] }}" \ No newline at end of file diff --git a/driver-nats-streaming/deploy/provision-nats-streaming-aws.tf b/driver-nats-streaming/deploy/provision-nats-streaming-aws.tf new file mode 100644 index 000000000..defc2b6c4 --- /dev/null +++ b/driver-nats-streaming/deploy/provision-nats-streaming-aws.tf @@ -0,0 +1,161 @@ +variable "public_key_path" { + description = <` with the right cluster name. E.g. + # + # cluster: test-cluster + cluster: local + +# Load and evaluate rules in these files every 'evaluation_interval' seconds. +# rule_files: + +scrape_configs: + + - job_name: "broker" + honor_labels: true # don't overwrite job & instance labels + static_configs: + - targets: +{% for broker in groups['nats'] %} + - {{ hostvars[broker].private_ip }}:9090 +{% endfor %} + + - job_name: "node_metrics" + honor_labels: true # don't overwrite job & instance labels + static_configs: + - targets: +{% for broker in groups['nats'] %} + - {{ hostvars[broker].private_ip }}:9100 +{% endfor %} \ No newline at end of file diff --git a/driver-nats-streaming/deploy/templates/workers.yaml b/driver-nats-streaming/deploy/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-nats-streaming/deploy/templates/workers.yaml +++ b/driver-nats-streaming/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-nats-streaming/deploy/terraform.tfvars b/driver-nats-streaming/deploy/terraform.tfvars index 1b872e9e8..c86fa5450 100644 --- a/driver-nats-streaming/deploy/terraform.tfvars +++ b/driver-nats-streaming/deploy/terraform.tfvars @@ -1,15 +1,16 @@ -region = "cn-shenzhen" -availability_zone = "cn-shenzhen-c" -private_key_file = "alicloud.pem" -key_name = "key-pair-from-terraform-nats-streaming" -image_id = "centos_7_04_64_20G_alibase_201701015.vhd" +public_key_path = "~/.ssh/nats_streaming_aws.pub" +region = "us-west-2" +az = "us-west-2a" +ami = "ami-08970fb2e5767e3b8" // RHEL-8 instance_types = { - "nats-streaming-server" = "ecs.se1.4xlarge" #4c16g - "client" = "ecs.n4.4xlarge" + "nats" = "i3en.6xlarge" + "client" = "m5n.8xlarge" + "prometheus" = "t2.large" } num_instances = { - "nats-streaming-server" = 3 - "client" = 2 -} \ No newline at end of file + "nats" = 3 + "client" = 4 + "prometheus" = 1 +} diff --git a/driver-nats-streaming/nats-streaming.yaml b/driver-nats-streaming/nats-streaming.yaml index d7ab09fa6..576487933 100644 --- a/driver-nats-streaming/nats-streaming.yaml +++ b/driver-nats-streaming/nats-streaming.yaml @@ -1,24 +1,19 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # -name: Nats +name: Nats Streaming driverClass: io.openmessaging.benchmark.driver.natsStreaming.NatsStreamingBenchmarkDriver # RabbitMq client specific configurations diff --git a/driver-nats-streaming/pom.xml b/driver-nats-streaming/pom.xml index 01720dd1c..3852fd65b 100644 --- a/driver-nats-streaming/pom.xml +++ b/driver-nats-streaming/pom.xml @@ -1,46 +1,44 @@ + - - + 4.0.0 - messaging-benchmark io.openmessaging.benchmark + messaging-benchmark 0.0.1-SNAPSHOT - 4.0.0 driver-nats-streaming - - io.nats - java-nats-streaming - 2.1.0 - ${project.groupId} driver-api ${project.version} + + com.google.guava + guava + + + io.nats + java-nats-streaming + 2.2.3 + - \ No newline at end of file + diff --git a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkConsumer.java b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkConsumer.java index eaf6e6a88..1e6e1c1bd 100644 --- a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkConsumer.java +++ b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkConsumer.java @@ -1,42 +1,34 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.natsStreaming; + import io.nats.streaming.StreamingConnection; -import io.nats.streaming.Subscription; import io.openmessaging.benchmark.driver.BenchmarkConsumer; public class NatsStreamingBenchmarkConsumer implements BenchmarkConsumer { private StreamingConnection streamingConnection; - private Subscription sub; - private String topic; private boolean unsubscribe; - public NatsStreamingBenchmarkConsumer(StreamingConnection streamingConnection, Subscription sub, String topic) { - this.sub = sub; - this.topic = topic; + + public NatsStreamingBenchmarkConsumer(StreamingConnection streamingConnection) { this.unsubscribe = false; this.streamingConnection = streamingConnection; } - @Override public void close() throws Exception { + @Override + public void close() throws Exception { if (!unsubscribe) { -// sub.unsubscribe(); unsubscribe = true; streamingConnection.close(); } diff --git a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkDriver.java b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkDriver.java index 0eeab65b8..06e31b988 100644 --- a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkDriver.java +++ b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkDriver.java @@ -1,23 +1,20 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.natsStreaming; +import static java.nio.charset.StandardCharsets.UTF_8; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -41,7 +38,6 @@ import org.apache.bookkeeper.stats.StatsLogger; import org.slf4j.LoggerFactory; - public class NatsStreamingBenchmarkDriver implements BenchmarkDriver { private final String defaultClusterId = "test-cluster"; private String clusterId; @@ -49,7 +45,9 @@ public class NatsStreamingBenchmarkDriver implements BenchmarkDriver { private StreamingConnection natsStreamingPublisher; private SubscriptionOptions.Builder subBuilder = new SubscriptionOptions.Builder(); private Options.Builder optsBuilder = new Options.Builder(); - @Override public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { + + @Override + public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { config = mapper.readValue(configurationFile, NatsStreamingClientConfig.class); log.info("read config file," + config.toString()); if (config.clusterId != null) { @@ -66,11 +64,13 @@ public class NatsStreamingBenchmarkDriver implements BenchmarkDriver { subBuilder.maxInFlight(config.maxInFlight); } - @Override public String getTopicNamePrefix() { + @Override + public String getTopicNamePrefix() { return "Nats-streaming-benchmark"; } - @Override public CompletableFuture createTopic(String topic, int partitions) { + @Override + public CompletableFuture createTopic(String topic, int partitions) { log.info("nats streaming create a topic" + topic); log.info("ignore partitions"); CompletableFuture future = new CompletableFuture<>(); @@ -78,7 +78,8 @@ public class NatsStreamingBenchmarkDriver implements BenchmarkDriver { return future; } - @Override public CompletableFuture createProducer(String topic) { + @Override + public CompletableFuture createProducer(String topic) { if (natsStreamingPublisher == null) { String clientId = "ProducerInstance" + getRandomString(); try { @@ -89,43 +90,54 @@ public class NatsStreamingBenchmarkDriver implements BenchmarkDriver { } } - return CompletableFuture.completedFuture(new NatsStreamingBenchmarkProducer(natsStreamingPublisher, topic)); + return CompletableFuture.completedFuture( + new NatsStreamingBenchmarkProducer(natsStreamingPublisher, topic)); } - @Override public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + @Override + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { Subscription sub; StreamingConnection streamingConnection; String clientId = "ConsumerInstance" + getRandomString(); try { streamingConnection = NatsStreaming.connect(clusterId, clientId, optsBuilder.build()); - sub = streamingConnection.subscribe(topic, subscriptionName, new MessageHandler() { - @Override public void onMessage(Message message) { - consumerCallback.messageReceived(message.getData(), message.getTimestamp()); - } - }, subBuilder.build()); + streamingConnection.subscribe( + topic, + subscriptionName, + new MessageHandler() { + @Override + public void onMessage(Message message) { + consumerCallback.messageReceived(message.getData(), message.getTimestamp()); + } + }, + subBuilder.build()); } catch (Exception e) { log.warn("nats streaming create consumer exception", e); return null; } - return CompletableFuture.completedFuture(new NatsStreamingBenchmarkConsumer(streamingConnection, sub, topic)); + return CompletableFuture.completedFuture( + new NatsStreamingBenchmarkConsumer(streamingConnection)); } - @Override public void close() throws Exception { + @Override + public void close() throws Exception { if (natsStreamingPublisher != null) { natsStreamingPublisher.close(); natsStreamingPublisher = null; } } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private static final org.slf4j.Logger log = LoggerFactory.getLogger(NatsStreamingBenchmarkDriver.class); + private static final org.slf4j.Logger log = + LoggerFactory.getLogger(NatsStreamingBenchmarkDriver.class); private static final Random random = new Random(); - private static final String getRandomString() { + private static String getRandomString() { byte[] buffer = new byte[5]; random.nextBytes(buffer); return BaseEncoding.base64Url().omitPadding().encode(buffer); @@ -135,26 +147,36 @@ public static void main(String[] args) throws Exception { try { Options opts = new Options.Builder().natsUrl("nats://0.0.0.0:4222").build(); SubscriptionOptions.Builder builder = new SubscriptionOptions.Builder(); - StreamingConnection streamingConnection = NatsStreaming.connect("mycluster", "benchmark-sub", opts); - Subscription sub = streamingConnection.subscribe("topicTest", "subscription", new MessageHandler() { - @Override public void onMessage(Message message) { - System.out.println(message.toString()); - } - }, builder.build()); - StreamingConnection natsStreamingPublisher = NatsStreaming.connect("mycluster", "benchmark-pub", opts); + StreamingConnection streamingConnection = + NatsStreaming.connect("mycluster", "benchmark-sub", opts); + Subscription sub = + streamingConnection.subscribe( + "topicTest", + "subscription", + new MessageHandler() { + @Override + public void onMessage(Message message) { + System.out.println(message.toString()); + } + }, + builder.build()); + StreamingConnection natsStreamingPublisher = + NatsStreaming.connect("mycluster", "benchmark-pub", opts); final String[] guid = new String[1]; - AckHandler acb = new AckHandler() { - @Override public void onAck(String s, Exception e) { - if ((e != null) || !guid[0].equals(s)) { - System.out.println("pub error"); - } else { - System.out.println("pub success"); - } - } - }; - - guid[0] = natsStreamingPublisher.publish("topicTest", "HelloStreaming".getBytes(), acb); + AckHandler acb = + new AckHandler() { + @Override + public void onAck(String s, Exception e) { + if ((e != null) || !guid[0].equals(s)) { + System.out.println("pub error"); + } else { + System.out.println("pub success"); + } + } + }; + + guid[0] = natsStreamingPublisher.publish("topicTest", "HelloStreaming".getBytes(UTF_8), acb); if (guid[0].isEmpty()) { System.out.println("Expected non-empty guid to be returned."); diff --git a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkProducer.java b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkProducer.java index 4c4fad746..2393c0719 100644 --- a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkProducer.java +++ b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingBenchmarkProducer.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.natsStreaming; + import io.nats.streaming.AckHandler; import io.nats.streaming.StreamingConnection; import io.openmessaging.benchmark.driver.BenchmarkProducer; @@ -27,23 +23,28 @@ public class NatsStreamingBenchmarkProducer implements BenchmarkProducer { private StreamingConnection natsStreamingPublisher; private String topic; - public NatsStreamingBenchmarkProducer (StreamingConnection natsStreamingPublisher, String topic) { + + public NatsStreamingBenchmarkProducer(StreamingConnection natsStreamingPublisher, String topic) { this.natsStreamingPublisher = natsStreamingPublisher; this.topic = topic; } - @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { + @Override + public CompletableFuture sendAsync(Optional key, byte[] payload) { CompletableFuture future = new CompletableFuture<>(); final String[] guid = new String[1]; - AckHandler acb = new AckHandler() { - @Override public void onAck(String s, Exception e) { - if ((e != null) || !guid[0].equals(s)) { - future.completeExceptionally(e); - } else { - future.complete(null); - } - } - }; + AckHandler acb = + new AckHandler() { + @Override + public void onAck(String s, Exception e) { + if ((e != null) || !guid[0].equals(s)) { + future.completeExceptionally( + e != null ? e : new IllegalStateException("guid != nuid")); + } else { + future.complete(null); + } + } + }; try { guid[0] = natsStreamingPublisher.publish(topic, payload, acb); } catch (Exception e) { @@ -55,7 +56,6 @@ public NatsStreamingBenchmarkProducer (StreamingConnection natsStreamingPublishe return future; } - @Override public void close() throws Exception { - - } + @Override + public void close() throws Exception {} } diff --git a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingClientConfig.java b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingClientConfig.java index 6bdeb31d5..57e45f426 100644 --- a/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingClientConfig.java +++ b/driver-nats-streaming/src/main/java/io/openmessaging/benchmark/driver/natsStreaming/NatsStreamingClientConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.natsStreaming; diff --git a/driver-nats/README.md b/driver-nats/README.md new file mode 100644 index 000000000..8beb85ce9 --- /dev/null +++ b/driver-nats/README.md @@ -0,0 +1,151 @@ +# NATS JetStream benchmarks + +> **Warning** +> This module relates to [NATS JetStream](https://docs.nats.io/nats-concepts/jetstream) which supersedes the now +> deprecated [NATS Streaming / STAN](https://docs.nats.io/legacy/stan). If you are interested in STAN benchmarks, +> see the [driver-nats-streaming](../driver-nats-streaming) module. + +This folder houses the assets necessary to run benchmarks for +[NATS JetStream](https://docs.nats.io/nats-concepts/jetstream). In order to run these benchmarks, you'll need to: + +* [Create the necessary local artifacts](#creating-local-artifacts) +* [Stand up a JetStream cluster](#creating-a-jetstream-cluster-on-amazon-web-services-aws-using-terraform-and-ansible) + on Amazon Web Services (which includes a client host for running the benchmarks) +* [SSH into the client host](#sshing-into-the-client-host) +* [Run the benchmarks from the client host](#running-the-benchmarks-from-the-client-host) + +## Creating local artifacts + +In order to create the local artifacts necessary to run the JetStream benchmarks in AWS, you'll need to have +[Maven](https://maven.apache.org/install.html) installed. Once Maven's installed, you can create the necessary +artifacts with a single Maven command: + +```bash +$ git clone https://github.com/openmessaging/benchmark.git +% cd messaging-benchmark +$ mvn install +``` + +## Creating a NATS cluster on Amazon Web Services (AWS) using Terraform and Ansible + +In order to create an NATS cluster on AWS, you'll need to have the following installed: + +* [Terraform](https://terraform.io) +* [The `terraform-inventory` plugin for Terraform](https://github.com/adammck/terraform-inventory) +* [Ansible](http://docs.ansible.com/ansible/latest/intro_installation.html) + +In addition, you will need to: + +* [Create an AWS account](https://aws.amazon.com/account/) (or use an existing account) +* [Install the `aws` CLI tool](https://aws.amazon.com/cli/) +* [Configure the `aws` CLI tool](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html) + +Once those conditions are in place, you'll need to create an SSH public and private key at `~/.ssh/nats_aws` +(private) and `~/.ssh/nats_aws.pub` (public), respectively. + +```bash +$ ssh-keygen -f ~/.ssh/nats_aws +``` + +When prompted to enter a passphrase, simply hit **Enter** twice. Then, make sure that the keys have been created: + +```bash +$ ls ~/.ssh/nats_aws* +``` + +With SSH keys in place, you can create the necessary AWS resources using a single Terraform command: + +```bash +$ cd driver-nats/deploy +$ terraform init +$ terraform apply +``` + +That will install the following [EC2](https://aws.amazon.com/ec2) instances (plus some other resources, such as a +[Virtual Private Cloud](https://aws.amazon.com/vpc/) (VPC)): + +| Resource | Description | Count | +|:--------------------|:------------------------------------------------------------|:------| +| NATS instances | The VMs on which NATS brokers will run | 3 | +| Client instance | The VM from which the benchmarking suite itself will be run | 4 | +| Prometheus instance | The VM on which metrics services will be run | 1 | + +When you run `terraform apply`, you will be prompted to type `yes`. Type `yes` to continue with the installation or +anything else to quit. + +Once the installation is complete, you will see a confirmation message listing the resources that have been installed. + +### Variables + +There's a handful of configurable parameters related to the Terraform deployment that you can alter by modifying the +defaults in the `terraform.tfvars` file. + +| Variable | Description | Default | +|:------------------|:------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------| +| `region` | The AWS region in which the NATS cluster will be deployed | `us-west-2` | +| `az` | The availability zone in which the NATS cluster will be deployed | `us-west-2a` | +| `public_key_path` | The path to the SSH public key that you've generated | `~/.ssh/rabbitmq_aws.pub` | +| `ami` | The [Amazon Machine Image](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) (AWI) to be used by the cluster's machines | [`ami-9fa343e7`](https://access.redhat.com/articles/3135091) | +| `instance_types` | The EC2 instance types used by the various components | `i3.4xlarge` (NATS brokers), `c4.8xlarge` (benchmarking clients) | + +> If you modify the `public_key_path`, make sure that you point to the appropriate SSH key path when running the +> [Ansible playbook](#running-the-ansible-playbook). + +### Running the Ansible playbook + +With the appropriate infrastructure in place, you can install and start the NATS cluster using Ansible with just +one command. Note that a `TFSTATE` environment must point to the folder in which the `tf.state` file is located. + +```bash +$ TF_STATE=. ansible-playbook \ + --user ec2-user \ + --inventory `which terraform-inventory` \ + deploy.yaml +``` + +> If you're using an SSH private key path different from `~/.ssh/nats_aws`, you can specify that path using +> the `--private-key` flag, for example `--private-key=~/.ssh/my_key`. + +## SSHing into the client host + +In the [output](https://www.terraform.io/intro/getting-started/outputs.html) produced by Terraform, there's a +`client_ssh_host` variable that provides the IP address for the client EC2 host from which benchmarks can be run. +You can SSH into that host using this command: + +```bash +$ ssh -i ~/.ssh/nats_aws ec2-user@$(terraform output client_ssh_host) +``` + +## Running the benchmarks from the client host + +Once you've successfully SSHed into the client host, you can run all +[available benchmark workloads](../#benchmarking-workloads) like this: + +```bash +$ cd /opt/benchmark +$ sudo bin/benchmark --drivers driver-nats/nats.yaml workloads/*.yaml +``` + +You can also run specific workloads in the `workloads` folder. Here's an example: + +```bash +$ sudo bin/benchmark --drivers driver-nats/nats.yaml workloads/1-topic-1-partitions-1kb.yaml +``` + +## Monitoring + +### Prometheus + +The [`prometheus-nats-exporter`](https://github.com/nats-io/prometheus-nats-exporter) +service is installed and Prometheus is installed on a standalone instance, along with +[Node Exporter](https://github.com/prometheus/node_exporter) on all brokers to allow the collection of system metrics. +Prometheus exposes a public endpoint `http://${prometheus_host}:9090`. + +### Grafana + +Grafana and a set of standard dashboards are installed alongside Prometheus. These are exposed on a public endpoint +`http://${prometheus_host}:3000`. Credentials are `admin`/`admin`. Dashboards included: + +* [NATS dashboards](https://github.com/nats-io/prometheus-nats-exporter/blob/main/walkthrough/README.md) +* [Node Exporter dashboard](https://grafana.com/grafana/dashboards/1860-node-exporter-full/) + diff --git a/driver-nats/deploy/alicloud/ansible.cfg b/driver-nats/deploy/alicloud/ansible.cfg new file mode 100644 index 000000000..15d972b75 --- /dev/null +++ b/driver-nats/deploy/alicloud/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +host_key_checking=false +private_key_file=alicloud.pem diff --git a/driver-nats/deploy/alicloud/deploy.yaml b/driver-nats/deploy/alicloud/deploy.yaml new file mode 100644 index 000000000..4cd79a751 --- /dev/null +++ b/driver-nats/deploy/alicloud/deploy.yaml @@ -0,0 +1,118 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +- name: Install NATS Cluster + hosts: nats + connection: ssh + tasks: + - set_fact: + natsHostUrl: "{{ hostvars[groups['nats'][0]].private_ip }}" + - name: Install RPM packages + yum: pkg={{ item }} state=latest + with_items: + - wget + - unzip + + - file: path=/opt/nats state=absent + - file: path=/opt/nats state=directory + - name: Install Nats Server + unarchive: + src: "https://github.com/nats-io/nats-server/releases/download/v2.9.3/nats-server-v2.9.3-amd64.rpm" + remote_src: yes + dest: /opt/nats +# extra_opts: ["--strip-components=1"] + - template: + src: "../templates/cluster.conf" + dest: "/opt/nats/cluster.conf" + - template: + src: "../templates/nats-server.service" + dest: "/etc/systemd/system/nats-server.service" + - replace: + dest: /opt/nats/cluster.conf + regexp: 'natsHostUrl' + replace: '{{natsHostUrl}}' + - replace: + dest: /opt/nats/cluster.conf + regexp: 'localhost' + replace: '{{natsHostUrl}}' + - systemd: + state: started + daemon_reload: yes + name: "nats-server" + + +- name: benchmarking client setup + hosts: client + connection: ssh + become: true + tasks: + - set_fact: + natsHostUrl: "{{ hostvars[groups['nats'][0]].private_ip }}" + - name: Install RPM packages + yum: pkg={{ item }} state=latest + with_items: + - java + - name: Copy benchmark code + unarchive: + src: ../../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz + dest: /opt + - shell: rm -rf /opt/benchmark/ + - shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT /opt/benchmark + - shell: tuned-adm profile latency-performance + - template: + src: "../templates/workers.yaml" + dest: "/opt/benchmark/workers.yaml" + - name: Get list of driver config files + raw: ls -1 /opt/benchmark/driver-rabbitmq/*.yaml + register: drivers_list + - template: + src: "../templates/nats.yaml" + dest: "/opt/benchmark/driver-nats/nats.yaml" + - name: Configure natsHost URL + lineinfile: + dest: /opt/benchmark/driver-nats/nats.yaml + regexp: '^natsHostUrl\: ' + line: 'natsHostUrl: nats://{{natsHostUrl}}:4222' + - name: Configure memory + lineinfile: + dest: /opt/benchmark/bin/benchmark-worker + regexp: '^JVM_MEM=' + line: 'JVM_MEM="-Xms12G -Xmx12G -XX:+UseG1GC -XX:MaxGCPauseMillis=10 -XX:+ParallelRefProcEnabled -XX:+UnlockExperimentalVMOptions -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=32 -XX:ConcGCThreads=32 -XX:G1NewSizePercent=50 -XX:+DisableExplicitGC -XX:-ResizePLAB -XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch -XX:-UseBiasedLocking"' + - name: Configure memory + lineinfile: + dest: /opt/benchmark/bin/benchmark + regexp: '^JVM_MEM=' + line: 'JVM_MEM="-Xmx4G"' + - name: Install benchmark systemd service + template: + src: "../templates/benchmark-worker.service" + dest: "/etc/systemd/system/benchmark-worker.service" + - systemd: + state: restarted + daemon_reload: yes + name: "benchmark-worker" + + +- name: List host addresses + hosts: localhost + become: false + tasks: + - debug: + msg: "nats brokers {{ item }}" + with_items: "{{ groups['nats'] }}" + - debug: + msg: "Benchmark client {{ item }}" + with_items: "{{ groups['client'] }}" + \ No newline at end of file diff --git a/driver-nats/deploy/provision-rabbitmq-aws.tf b/driver-nats/deploy/alicloud/provision-nats-ali.tf similarity index 100% rename from driver-nats/deploy/provision-rabbitmq-aws.tf rename to driver-nats/deploy/alicloud/provision-nats-ali.tf diff --git a/driver-nats/deploy/alicloud/terraform.tfvars b/driver-nats/deploy/alicloud/terraform.tfvars new file mode 100644 index 000000000..14bbf86ee --- /dev/null +++ b/driver-nats/deploy/alicloud/terraform.tfvars @@ -0,0 +1,15 @@ +region = "cn-shenzhen" +availability_zone = "cn-shenzhen-c" +private_key_file = "alicloud.pem" +key_name = "key-pair-from-terraform-nats" +image_id = "centos_7_04_64_20G_alibase_201701015.vhd" + +instance_types = { + "nats" = "ecs.se1.4xlarge" #4c16g + "client" = "ecs.n4.4xlarge" +} + +num_instances = { + "nats" = 1 + "client" = 2 +} \ No newline at end of file diff --git a/driver-nats/deploy/ansible.cfg b/driver-nats/deploy/ansible.cfg index 15d972b75..a33efb2d9 100644 --- a/driver-nats/deploy/ansible.cfg +++ b/driver-nats/deploy/ansible.cfg @@ -1,3 +1,8 @@ [defaults] host_key_checking=false -private_key_file=alicloud.pem +private_key_file=~/.ssh/nats_aws + +[privilege_escalation] +become=true +become_method='sudo' +become_user='root' \ No newline at end of file diff --git a/driver-nats/deploy/deploy-client-jars.yaml b/driver-nats/deploy/deploy-client-jars.yaml new file mode 100644 index 000000000..d210cba01 --- /dev/null +++ b/driver-nats/deploy/deploy-client-jars.yaml @@ -0,0 +1,30 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +- name: Deploy benchmark + hosts: client + connection: ssh + become: true + tasks: + - shell: rm -fr /opt/openmessaging-benchmark-0.0.1-SNAPSHOT + - shell: rm -f /opt/benchmark/lib/io.openmessaging.* + - unarchive: + src: ../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz + dest: /opt + - shell: cp -f /opt/openmessaging-benchmark-0.0.1-SNAPSHOT/lib/io.openmessaging.* /opt/benchmark/lib/ + - name: Benchmark - Start service + systemd: + state: restarted + daemon_reload: yes + name: "benchmark-worker" diff --git a/driver-nats/deploy/deploy.yaml b/driver-nats/deploy/deploy.yaml index 893b39444..40716ab23 100644 --- a/driver-nats/deploy/deploy.yaml +++ b/driver-nats/deploy/deploy.yaml @@ -1,123 +1,415 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # +- name: Format and mount disks for NATS hosts + hosts: nats + connection: ssh + become: true + tasks: + - name: NATS - Format disks + filesystem: + fstype: xfs + dev: '{{ item }}' + with_items: + - '/dev/nvme2n1' + - name: NATS - Mount disks + mount: + path: "{{ item.path }}" + src: "{{ item.src }}" + fstype: xfs + opts: defaults,noatime,nodiscard + state: mounted + with_items: + - { path: "/mnt/data", src: "/dev/nvme2n1" } + - name: NATS - Set filesystem permissions + file: + path: "/mnt/data" + state: touch + mode: "0777" -- name: Install NATS Cluster +- name: NATS - Install Cluster hosts: nats connection: ssh tasks: - set_fact: natsHostUrl: "{{ hostvars[groups['nats'][0]].private_ip }}" - - name: Install RPM packages + private_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + tags: [ broker ] + - name: NATS - Install RPM packages + tags: [ broker ] yum: pkg={{ item }} state=latest with_items: - wget - unzip - - file: path=/opt/nats state=absent + tags: [ broker ] - file: path=/opt/nats state=directory - - name: Install Nats Server - unarchive: - src: "https://github.com/nats-io/gnatsd/releases/download/v1.3.0/gnatsd-v1.3.0-linux-amd64.zip" - remote_src: yes - dest: /opt/nats -# extra_opts: ["--strip-components=1"] - - template: - src: "templates/cluster.conf" + tags: [ broker ] + - name: NATS - Install server + tags: [ broker ] + yum: + name: "https://github.com/nats-io/nats-server/releases/download/v2.9.6/nats-server-v2.9.6-amd64.rpm" + state: present + disable_gpg_check: yes + - name: NATS - Apply server configuration + tags: [ broker ] + template: + src: "../../driver-nats/deploy/templates/cluster.conf" dest: "/opt/nats/cluster.conf" - - template: + - name: NATS - Configure server systemd service + tags: [ broker ] + template: src: "templates/nats-server.service" dest: "/etc/systemd/system/nats-server.service" - - replace: - dest: /opt/nats/cluster.conf - regexp: 'natsHostUrl' - replace: '{{natsHostUrl}}' - - replace: - dest: /opt/nats/cluster.conf - regexp: 'localhost' - replace: '{{natsHostUrl}}' - - systemd: + - name: NATS - Start service + tags: [ broker ] + systemd: state: started daemon_reload: yes name: "nats-server" +- name: Install NATS Prometheus exporters + hosts: nats + connection: ssh + become: true + tasks: + - name: NATSExporter - Configure yum Docker repo + tags: ['nse'] + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: NATSExporter - Install Docker + tags: ['nse'] + yum: + state: latest + pkg: ['docker-ce'] + - name: NATSExporter - Start docker + tags: ['nse'] + service: + name: docker + state: started + enabled: yes -- name: benchmarking client setup +- name: Configure NATS Prometheus exporters + hosts: nats + connection: ssh + become: true + tasks: + - file: path=/opt/nats-metrics state=absent + tags: ['nse'] + - file: path=/opt/nats-metrics state=directory + tags: ['nse'] + - name: NATSExporter - Configure systemd + tags: ['nse'] + template: + src: "templates/nats-metrics.service" + dest: "/etc/systemd/system/nats-metrics.service" + - name: NATSExporter - Restart NATS exporter + tags: ['nse'] + systemd: + state: restarted + daemon_reload: yes + name: "nats-metrics.service" + +- name: Install Node exporters + hosts: nats + connection: ssh + become: true + tasks: + - name: NodeExporter - Set software versions + set_fact: + nodeExporterVersion: 1.2.2 + - name: NodeExporter - Set binary source URL + set_fact: + nodeExporterBinary: + src: "https://github.com/prometheus/node_exporter/releases/download/v{{ nodeExporterVersion }}/node_exporter-{{ nodeExporterVersion }}.linux-amd64.tar.gz" + remote: yes + when: nodeExporterBinary is not defined + - name: NodeExporter - Add node_exporter user + user: + name: node_exporter + shell: /bin/false + system: true + create_home: no + - name: NodeExporter - Download and extract + unarchive: + src: "{{ nodeExporterBinary.src }}" + dest: /tmp + remote_src: "{{ nodeExporterBinary.remote }}" + - name: NodeExporter - Install binary + copy: + src: "/tmp/node_exporter-{{ nodeExporterVersion }}.linux-amd64/node_exporter" + remote_src: yes + dest: /usr/local/bin/ + owner: node_exporter + group: node_exporter + mode: u+x,g+x,o+x + - name: NodeExporter - Create service + blockinfile: + path: /etc/systemd/system/node_exporter.service + block: | + [Unit] + Description=Prometheus Node Exporter + Wants=network-online.target + After=network-online.target + [Service] + User=node_exporter + Group=node_exporter + Type=simple + ExecStart=/usr/local/bin/node_exporter + [Install] + WantedBy=multi-user.target + create: true + - name: NodeExporter - Reload daemon configuration + systemd: + daemon_reload: yes + - name: NodeExporter - Start and enable service + service: + name: node_exporter + state: started + enabled: yes + - name: NodeExporter - Check port 9100 availability + wait_for: + port: 9100 + state: started + timeout: 5 + +- name: Prometheus installation + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Prometheus - Set software versions + set_fact: + prometheusVersion: 2.31.1 + - name: Prometheus - Set binary source URL + set_fact: + prometheusBinary: + src: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheusVersion }}/prometheus-{{ prometheusVersion }}.linux-amd64.tar.gz" + remote: yes + - name: Prometheus - Add RHEL yum repo + shell: yum-config-manager --enable rhui-REGION-rhel-server-extras + when: + - ansible_facts['distribution'] == 'RedHat' + - ansible_facts['distribution_major_version'] | int <= 7 + - name: Prometheus - Create install folders + file: path=/opt/prometheus/data state=absent + - file: path=/opt/prometheus/data state=directory + - name: Prometheus - Download and unarchive binary + unarchive: + src: "{{ prometheusBinary.src }}" + remote_src: "{{ prometheusBinary.remote }}" + dest: /opt/prometheus + extra_opts: ["--strip-components=1"] + +- name: Prometheus setup + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Prometheus - Configure systemd + template: + src: "templates/prometheus.service" + dest: "/etc/systemd/system/prometheus.service" + - name: Prometheus - Configure service + template: + src: "templates/prometheus.yml" + dest: "/opt/prometheus/prometheus.yml" + - name: Prometheus - Restart service + systemd: + state: restarted + daemon_reload: yes + name: "prometheus" + +- name: Grafana installation + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Grafana - Configure yum Docker repo + tags: ['grafins'] + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: Grafana - Install Docker + tags: ['grafins'] + yum: + state: latest + pkg: ['docker-ce'] + - name: Grafana - Start docker + tags: ['grafins'] + service: + name: docker + state: started + enabled: yes + - name: Grafana - Create install folders + tags: ['grafins'] + file: path=/opt/grafana state=absent + - file: path=/opt/grafana state=directory + tags: ['grafins'] + - file: path=/repos/prometheus-nats-exporter state=absent + tags: ['grafins'] + - file: path=/repos/prometheus-nats-exporter state=directory + tags: ['grafins'] + - file: path=/repos/grafana-dashboards state=absent + tags: ['grafins'] + - file: path=/repos/grafana-dashboards state=directory + tags: ['grafins'] + - name: Grafana - Install Git RPM packages + tags: ['grafins'] + yum: pkg={{ item }} state=latest + with_items: + - git + - name: Grafana - Clone nats-io/prometheus-nats-exporter repository + tags: ['grafins'] + git: + repo: https://github.com/nats-io/prometheus-nats-exporter.git + dest: /repos/prometheus-nats-exporter + clone: yes + update: yes + - name: Grafana - Clone rfmoz/grafana-dashboard repository + tags: ['grafins'] + git: + repo: https://github.com/rfmoz/grafana-dashboards.git + dest: /repos/grafana-dashboards + clone: yes + update: yes + - name: Grafana - Copy node_exporter dashboard + tags: ['grafins'] + copy: remote_src=True src=/repos/grafana-dashboards/prometheus/node-exporter-full.json dest=/repos/prometheus-nats-exporter/walkthrough/ + +- name: Grafana setup + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Grafana - Update datasource + tags: ['grafconf'] + shell: sed -i 's/\${DS__NATS-PROMETHEUS}/NATS-Prometheus/g' /repos/prometheus-nats-exporter/walkthrough/*.json + - name: Grafana - Create data folders + tags: ['grafconf'] + file: path=/opt/nats state=absent + - file: path=/opt/nats state=directory + tags: ['grafconf'] + - name: Grafana - Configure Dashboards + tags: ['grafconf'] + template: + src: "templates/grafana-dashboards.yml" + dest: "/opt/nats/dashboards.yml" + - name: Grafana - Configure Prometheus datasource + tags: ['grafconf'] + template: + src: "templates/grafana-datasource.yml" + dest: "/opt/nats/grafana-datasource.yml" + - name: Grafana - Configure systemd + tags: ['grafconf'] + template: + src: "../../driver-nats/deploy/templates/nats-dashboard.service" + dest: "/etc/systemd/system/nats-dashboard.service" + - name: Grafana - Restart Grafana + tags: ['grafconf'] + systemd: + state: restarted + daemon_reload: yes + name: "nats-dashboard.service" + +- name: Chrony setup + hosts: client + connection: ssh + become: true + tasks: + - name: Chrony - Configure + template: + src: "templates/chrony.conf" + dest: "/etc/chrony.conf" + - name: Chrony - Restart + systemd: + state: restarted + daemon_reload: yes + name: "chronyd" + +- name: Benchmarking client setup hosts: client connection: ssh become: true tasks: - set_fact: natsHostUrl: "{{ hostvars[groups['nats'][0]].private_ip }}" - - name: Install RPM packages + - name: Benchmark - Install RPM packages yum: pkg={{ item }} state=latest with_items: - java - - name: Copy benchmark code + - name: Benchmark - Create folders + file: path=/opt/benchmark state=absent + - file: path=/opt/benchmark state=directory + - name: Benchmark - Copy code unarchive: src: ../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz dest: /opt - - shell: rm -rf /opt/benchmark/ - - shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT /opt/benchmark - - shell: tuned-adm profile latency-performance - - template: - src: "templates/workers.yaml" + - name: Benchmark - Install code + shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT/* /opt/benchmark + - name: Benchmark - Tune kernel + shell: tuned-adm profile latency-performance + - name: Benchmark - Configure workers + template: + src: "../../driver-nats/deploy/templates/workers.yaml" dest: "/opt/benchmark/workers.yaml" - - name: Get list of driver config files - raw: ls -1 /opt/benchmark/driver-rabbitmq/*.yaml + - name: Benchmark - Get list of driver config files + raw: ls -1 /opt/benchmark/driver-nats/*.yaml register: drivers_list - - template: - src: "templates/nats.yaml" - dest: "/opt/benchmark/driver-nats/nats.yaml" - - name: Configure natsHost URL + - name: Benchmark - Configure natsHost URL lineinfile: dest: /opt/benchmark/driver-nats/nats.yaml regexp: '^natsHostUrl\: ' line: 'natsHostUrl: nats://{{natsHostUrl}}:4222' - - name: Configure memory + - name: Benchmark - Configure worker memory lineinfile: dest: /opt/benchmark/bin/benchmark-worker regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xms12G -Xmx12G -XX:+UseG1GC -XX:MaxGCPauseMillis=10 -XX:+ParallelRefProcEnabled -XX:+UnlockExperimentalVMOptions -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=32 -XX:ConcGCThreads=32 -XX:G1NewSizePercent=50 -XX:+DisableExplicitGC -XX:-ResizePLAB -XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch -XX:-UseBiasedLocking"' - - name: Configure memory + - name: Benchmark - Configure client memory lineinfile: dest: /opt/benchmark/bin/benchmark regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xmx4G"' - - name: Install benchmark systemd service + - name: Benchmark - Install systemd service template: src: "templates/benchmark-worker.service" dest: "/etc/systemd/system/benchmark-worker.service" - - systemd: + - name: Benchmark - Start service + systemd: state: restarted daemon_reload: yes name: "benchmark-worker" - - name: List host addresses hosts: localhost become: false tasks: - debug: - msg: "nats brokers {{ item }}" + msg: "Nats brokers {{ item }}" with_items: "{{ groups['nats'] }}" - debug: msg: "Benchmark client {{ item }}" with_items: "{{ groups['client'] }}" + - debug: + msg: "Prometheus servers {{ item }}" + with_items: "{{ groups['prometheus'] }}" \ No newline at end of file diff --git a/driver-nats/deploy/provision-nats-aws.tf b/driver-nats/deploy/provision-nats-aws.tf new file mode 100644 index 000000000..3307db02f --- /dev/null +++ b/driver-nats/deploy/provision-nats-aws.tf @@ -0,0 +1,176 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + random = { + source = "hashicorp/random" + } + } +} + +variable "public_key_path" { + description = <` with the right cluster name. E.g. + # + # cluster: test-cluster + cluster: local + +# Load and evaluate rules in these files every 'evaluation_interval' seconds. +# rule_files: + +scrape_configs: + + - job_name: "broker" + honor_labels: true # don't overwrite job & instance labels + static_configs: + - targets: +{% for broker in groups['nats'] %} + - {{ hostvars[broker].private_ip }}:9090 +{% endfor %} + + - job_name: "node_metrics" + honor_labels: true # don't overwrite job & instance labels + static_configs: + - targets: +{% for broker in groups['nats'] %} + - {{ hostvars[broker].private_ip }}:9100 +{% endfor %} \ No newline at end of file diff --git a/driver-nats/deploy/templates/workers.yaml b/driver-nats/deploy/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-nats/deploy/templates/workers.yaml +++ b/driver-nats/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-nats/deploy/terraform.tfvars b/driver-nats/deploy/terraform.tfvars index 14bbf86ee..c82e0db92 100644 --- a/driver-nats/deploy/terraform.tfvars +++ b/driver-nats/deploy/terraform.tfvars @@ -1,15 +1,16 @@ -region = "cn-shenzhen" -availability_zone = "cn-shenzhen-c" -private_key_file = "alicloud.pem" -key_name = "key-pair-from-terraform-nats" -image_id = "centos_7_04_64_20G_alibase_201701015.vhd" +public_key_path = "~/.ssh/nats_aws.pub" +region = "us-west-2" +az = "us-west-2a" +ami = "ami-08970fb2e5767e3b8" // RHEL-8 instance_types = { - "nats" = "ecs.se1.4xlarge" #4c16g - "client" = "ecs.n4.4xlarge" + "nats" = "i3en.6xlarge" + "client" = "m5n.8xlarge" + "prometheus" = "t2.large" } num_instances = { - "nats" = 1 - "client" = 2 -} \ No newline at end of file + "nats" = 3 + "client" = 4 + "prometheus" = 1 +} diff --git a/driver-nats/nats.yaml b/driver-nats/nats.yaml new file mode 100644 index 000000000..8a51250e6 --- /dev/null +++ b/driver-nats/nats.yaml @@ -0,0 +1,20 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: NATS +driverClass: io.openmessaging.benchmark.driver.nats.NatsBenchmarkDriver + +natsHostUrl: localhost:4222 + +replicationFactor: 3 diff --git a/driver-nats/pom.xml b/driver-nats/pom.xml index 97fe134b4..0d2052650 100644 --- a/driver-nats/pom.xml +++ b/driver-nats/pom.xml @@ -1,45 +1,40 @@ + - + 4.0.0 - messaging-benchmark io.openmessaging.benchmark + messaging-benchmark 0.0.1-SNAPSHOT - 4.0.0 driver-nats - - io.nats - jnats - 2.0.0 - ${project.groupId} driver-api ${project.version} + + io.nats + jnats + 2.16.3 + - \ No newline at end of file + diff --git a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkConsumer.java b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkConsumer.java index 9112efebe..8627475df 100644 --- a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkConsumer.java +++ b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkConsumer.java @@ -1,32 +1,22 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nats; -import io.nats.client.Connection; + import io.openmessaging.benchmark.driver.BenchmarkConsumer; public class NatsBenchmarkConsumer implements BenchmarkConsumer { - private Connection cn; - public NatsBenchmarkConsumer (Connection cn) { - this.cn = cn; - } - @Override public void close() throws Exception { - this.cn.close(); - } + @Override + public void close() {} } diff --git a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkDriver.java b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkDriver.java index 8e18c187e..8071f36df 100644 --- a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkDriver.java +++ b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkDriver.java @@ -1,102 +1,168 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nats; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.nats.client.Connection; import io.nats.client.Dispatcher; +import io.nats.client.ErrorListener; +import io.nats.client.JetStream; +import io.nats.client.JetStreamManagement; +import io.nats.client.JetStreamSubscription; +import io.nats.client.Message; import io.nats.client.Nats; import io.nats.client.Options; -import java.nio.charset.StandardCharsets; -import java.time.Duration; +import io.nats.client.PushSubscribeOptions; +import io.nats.client.api.ConsumerConfiguration; +import io.nats.client.api.StreamConfiguration; +import io.nats.client.api.StreamInfo; +import io.nats.client.support.JsonUtils; import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.BenchmarkDriver; import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.openmessaging.benchmark.driver.ConsumerCallback; import java.io.File; import java.io.IOException; +import java.time.Duration; import java.util.concurrent.CompletableFuture; import org.apache.bookkeeper.stats.StatsLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.nats.client.Connection; - public class NatsBenchmarkDriver implements BenchmarkDriver { private NatsConfig config; - @Override public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { + private Connection connection; + private JetStream jetStream; + private JetStreamManagement jetStreamManagement; + + @Override + public void initialize(File configurationFile, StatsLogger statsLogger) + throws IOException, InterruptedException { config = mapper.readValue(configurationFile, NatsConfig.class); log.info("read config file," + config.toString()); - } + this.connection = + Nats.connect( + new Options.Builder() + .server(config.natsHostUrl) + .maxReconnects(5) + .reconnectWait(Duration.ofSeconds(1)) + .connectionTimeout(Duration.ofSeconds(5)) + .pingInterval(Duration.ofSeconds(60)) + .errorListener( + new ErrorListener() { + @Override + public void errorOccurred(Connection conn, String error) { + log.error("Error on connection {}: {}", conn, error); + } - @Override public String getTopicNamePrefix() { - return "Nats-benchmark"; + @Override + public void exceptionOccurred(Connection conn, Exception exp) { + log.error("Exception on connection {}", conn, exp); + } + }) + .build()); + this.jetStream = connection.jetStream(); + this.jetStreamManagement = connection.jetStreamManagement(); } - @Override public CompletableFuture createTopic(String topic, int partitions) { - log.info("nats create a topic" + topic); - log.info("ignore partitions"); - CompletableFuture future = new CompletableFuture<>(); - future.complete(null); - return future; + @Override + public String getTopicNamePrefix() { + return "Nats-benchmark"; } - @Override public CompletableFuture createProducer(String topic) { - Connection natsProducer; + @Override + public CompletableFuture createTopic(String topic, int partitions) { try { - Options options = new Options.Builder().server(config.natsHostUrl).maxReconnects(5).build(); - natsProducer = Nats.connect(options); + JetStreamManagement jsm = connection.jetStreamManagement(); + StreamInfo streamInfo = + jsm.addStream( + StreamConfiguration.builder() + .name(topic) + .subjects(topic) + .storageType(config.storageType) + .maxBytes(config.maxBytes) + .replicas(config.replicationFactor) + .build()); + log.info("Created stream {} -- {}", topic, JsonUtils.getFormatted(streamInfo)); + return CompletableFuture.completedFuture(null); } catch (Exception e) { - log.error("createProducer excetopin " + e); - return null; + CompletableFuture f = new CompletableFuture<>(); + f.completeExceptionally(e); + return f; } - return CompletableFuture.completedFuture(new NatsBenchmarkProducer(natsProducer, topic)); } - @Override public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { - Dispatcher natsConsumer; - Connection cn; - log.info("createConsumer"); + @Override + public CompletableFuture createProducer(String topic) { + return CompletableFuture.completedFuture(new NatsBenchmarkProducer(jetStream, topic)); + } + + @Override + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { + + ConsumerConfiguration cc = + ConsumerConfiguration.builder() + .durable("durable-" + subscriptionName) + .deliverSubject("delivery-subject-" + subscriptionName) + .deliverGroup("group-" + subscriptionName) + .build(); + PushSubscribeOptions pso = PushSubscribeOptions.builder().configuration(cc).build(); + try { - Options options = new Options.Builder().server(config.natsHostUrl).maxReconnects(5).build(); - cn = Nats.connect(options); - natsConsumer = cn.createDispatcher((msg) -> { - consumerCallback.messageReceived(msg.getData(), Long.parseLong(msg.getReplyTo())); - }); - natsConsumer.subscribe(topic, subscriptionName); - cn.flush(Duration.ZERO); + jetStreamManagement.addOrUpdateConsumer(topic, cc); + + Dispatcher dispatcher = connection.createDispatcher(); + + JetStreamSubscription sub = + jetStream.subscribe( + topic, + dispatcher, + (Message msg) -> { + long publishTimestamp = readLongFromBytes(msg.getData()); + consumerCallback.messageReceived(msg.getData(), publishTimestamp); + msg.ack(); + }, + false, + pso); + return CompletableFuture.completedFuture(new NatsBenchmarkConsumer()); } catch (Exception e) { - log.error("createConsumer excetopin " + e); - return null; + CompletableFuture f = new CompletableFuture<>(); + f.completeExceptionally(e); + return f; } - log.info("createCOnsumer done"); - return CompletableFuture.completedFuture(new NatsBenchmarkConsumer(cn)); } - @Override public void close() throws Exception { - + @Override + public void close() throws Exception { + this.connection.close(); } private static final Logger log = LoggerFactory.getLogger(NatsBenchmarkDriver.class); - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static long readLongFromBytes(final byte[] b) { + long result = 0; + for (int i = 0; i < 8; i++) { + result <<= 8; + result |= (b[i] & 0xFF); + } + return result; + } } diff --git a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkProducer.java b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkProducer.java index 530b17880..1c9dd8a54 100644 --- a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkProducer.java +++ b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsBenchmarkProducer.java @@ -1,76 +1,47 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nats; -import io.nats.client.ConnectionListener; + +import io.nats.client.JetStream; import io.openmessaging.benchmark.driver.BenchmarkProducer; -import java.time.Duration; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import io.nats.client.Connection; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Semaphore; -import javax.sql.ConnectionEventListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class NatsBenchmarkProducer implements BenchmarkProducer { private final String topic; - private final Connection natsProducer; - private final ExecutorService executor = Executors.newCachedThreadPool(); - private final Semaphore semaphore = new Semaphore(1000); - public NatsBenchmarkProducer(final Connection natsProducer, final String topic) { - this.natsProducer = natsProducer; + private final JetStream jetStream; + + public NatsBenchmarkProducer(JetStream jetStream, final String topic) { + this.jetStream = jetStream; this.topic = topic; } - @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { - CompletableFuture future = new CompletableFuture<>(); - try { - semaphore.acquire(); + @Override + public CompletableFuture sendAsync(Optional key, byte[] payload) { + writeLongToBytes(System.currentTimeMillis(), payload); + return jetStream.publishAsync(topic, payload).thenApply(x -> null); + } - executor.submit(() -> { - try { - natsProducer.publish(topic, Long.toString(System.currentTimeMillis()), payload); -// natsProducer.flush(Duration.ofSeconds(1)); - } catch (Exception e) { - log.error("send exception" + e); - future.exceptionally(null); - } finally { - semaphore.release(); - } - future.complete(null); + @Override + public void close() throws Exception {} - }); - } catch (Exception e) { - log.error("send exception", e); - future.exceptionally(null); - semaphore.release(); + public static void writeLongToBytes(long l, byte[] dst) { + for (int i = 7; i >= 0; i--) { + dst[i] = (byte) (l & 0xFF); + l >>= 8; } - return future; - } - - @Override public void close() throws Exception { - log.info("close a producer"); - natsProducer.close(); } - private static final Logger log = LoggerFactory.getLogger(NatsBenchmarkProducer.class); } diff --git a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsConfig.java b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsConfig.java index 39cfd3318..d76a900b3 100644 --- a/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsConfig.java +++ b/driver-nats/src/main/java/io/openmessaging/benchmark/driver/nats/NatsConfig.java @@ -1,23 +1,28 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nats; + +import io.nats.client.api.StorageType; + public class NatsConfig { public String natsHostUrl; + + public int replicationFactor; + + public StorageType storageType = StorageType.File; + + // -1 is unlimited + public int maxBytes = -1; } diff --git a/driver-nsq/deploy/deploy.yaml b/driver-nsq/deploy/deploy.yaml index 55cbd8ea2..b7243e215 100644 --- a/driver-nsq/deploy/deploy.yaml +++ b/driver-nsq/deploy/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-nsq/deploy/templates/workers.yaml b/driver-nsq/deploy/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-nsq/deploy/templates/workers.yaml +++ b/driver-nsq/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-nsq/nsq.yaml b/driver-nsq/nsq.yaml index 86547b50f..3581b027a 100644 --- a/driver-nsq/nsq.yaml +++ b/driver-nsq/nsq.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-nsq/pom.xml b/driver-nsq/pom.xml index 2e5c505c9..377f1f983 100644 --- a/driver-nsq/pom.xml +++ b/driver-nsq/pom.xml @@ -1,44 +1,39 @@ + - + 4.0.0 - messaging-benchmark io.openmessaging.benchmark + messaging-benchmark 0.0.1-SNAPSHOT - 4.0.0 driver-nsq - - com.github.brainlag - nsq-client - 1.0.0.RC4 - ${project.groupId} driver-api ${project.version} + + com.github.brainlag + nsq-client + 1.0.0.RC4 + - \ No newline at end of file + diff --git a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkConsumer.java b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkConsumer.java index 89a5849dd..3e63c5e2a 100644 --- a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkConsumer.java +++ b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkConsumer.java @@ -1,32 +1,31 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nsq; + import com.github.brainlag.nsq.NSQConsumer; import io.openmessaging.benchmark.driver.BenchmarkConsumer; public class NsqBenchmarkConsumer implements BenchmarkConsumer { private NSQConsumer nsqConsumer; + public NsqBenchmarkConsumer(NSQConsumer nsqConsumer) { this.nsqConsumer = nsqConsumer; } - @Override public void close() throws Exception { + + @Override + public void close() throws Exception { this.nsqConsumer.shutdown(); } } diff --git a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkDriver.java b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkDriver.java index 79d417cb3..99f9f7586 100644 --- a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkDriver.java +++ b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkDriver.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nsq; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -28,29 +24,30 @@ import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.BenchmarkDriver; import io.openmessaging.benchmark.driver.BenchmarkProducer; - import io.openmessaging.benchmark.driver.ConsumerCallback; import java.io.File; import java.io.IOException; import java.util.concurrent.CompletableFuture; import org.apache.bookkeeper.stats.StatsLogger; -import org.apache.logging.log4j.LogManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NsqBenchmarkDriver implements BenchmarkDriver { private NsqConfig config; - @Override public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { + @Override + public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { config = mapper.readValue(configurationFile, NsqConfig.class); log.info("read config file," + config.toString()); } - @Override public String getTopicNamePrefix() { + @Override + public String getTopicNamePrefix() { return "Nsq-Benchmark"; } - @Override public CompletableFuture createTopic(String topic, int partitions) { + @Override + public CompletableFuture createTopic(String topic, int partitions) { log.info("create a topic" + topic); log.info("ignore partitions"); CompletableFuture future = new CompletableFuture<>(); @@ -58,7 +55,8 @@ public class NsqBenchmarkDriver implements BenchmarkDriver { return future; } - @Override public CompletableFuture createProducer(final String topic) { + @Override + public CompletableFuture createProducer(final String topic) { NSQProducer nsqProducer = new NSQProducer(); nsqProducer.addAddress(config.nsqdHost, 4150); nsqProducer.start(); @@ -67,19 +65,26 @@ public class NsqBenchmarkDriver implements BenchmarkDriver { return CompletableFuture.completedFuture(new NsqBenchmarkProducer(nsqProducer, topic)); } - @Override public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { - //Channel can be treat as subscriptionName + @Override + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { + // Channel can be treat as subscriptionName NSQLookup lookup = new DefaultNSQLookup(); lookup.addLookupAddress(config.lookupHost, 4161); - NSQConsumer nsqConsumer = new NSQConsumer(lookup, topic, subscriptionName, (message) -> { - //now mark the message as finished. - consumerCallback.messageReceived(message.getMessage(), message.getTimestamp().getTime()); - message.finished(); + NSQConsumer nsqConsumer = + new NSQConsumer( + lookup, + topic, + subscriptionName, + (message) -> { + // now mark the message as finished. + consumerCallback.messageReceived( + message.getMessage(), message.getTimestamp().getTime()); + message.finished(); - //or you could requeue it, which indicates a failure and puts it back on the queue. - //message.requeue(); - }); + // or you could requeue it, which indicates a failure and puts it back on the queue. + // message.requeue(); + }); nsqConsumer.start(); log.info("start a nsq consumer"); @@ -87,11 +92,11 @@ public class NsqBenchmarkDriver implements BenchmarkDriver { return CompletableFuture.completedFuture(new NsqBenchmarkConsumer(nsqConsumer)); } - @Override public void close() throws Exception { + @Override + public void close() throws Exception {} - } private static final Logger log = LoggerFactory.getLogger(NsqBenchmarkDriver.class); - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } diff --git a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkProducer.java b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkProducer.java index 6db3fee5c..f1f85c5e3 100644 --- a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkProducer.java +++ b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqBenchmarkProducer.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nsq; + import com.github.brainlag.nsq.NSQProducer; import com.github.brainlag.nsq.exceptions.NSQException; import io.openmessaging.benchmark.driver.BenchmarkProducer; @@ -41,26 +37,27 @@ public NsqBenchmarkProducer(final NSQProducer nsqProducer, final String topic) { this.topic = topic; } - @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { + @Override + public CompletableFuture sendAsync(Optional key, byte[] payload) { CompletableFuture future = new CompletableFuture<>(); try { semaphore.acquire(); - executor.submit(() -> { - try { - nsqProducer.produce(topic, payload); - } catch (NSQException e) { - log.error("send exception", e); - future.exceptionally(null); - } catch (TimeoutException e) { - log.error("send exception", e); - future.exceptionally(null); - } finally { - semaphore.release(); - } - future.complete(null); - - }); + executor.submit( + () -> { + try { + nsqProducer.produce(topic, payload); + } catch (NSQException e) { + log.error("send exception", e); + future.exceptionally(null); + } catch (TimeoutException e) { + log.error("send exception", e); + future.exceptionally(null); + } finally { + semaphore.release(); + } + future.complete(null); + }); } catch (InterruptedException e) { log.error("semaphore exception", e); future.exceptionally(null); @@ -69,8 +66,10 @@ public NsqBenchmarkProducer(final NSQProducer nsqProducer, final String topic) { return future; } - @Override public void close() throws Exception { + @Override + public void close() throws Exception { this.nsqProducer.shutdown(); } + private static final Logger log = LoggerFactory.getLogger(NsqBenchmarkProducer.class); } diff --git a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqConfig.java b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqConfig.java index 9ea5590a9..5658105e2 100644 --- a/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqConfig.java +++ b/driver-nsq/src/main/java/io/openmessaging/benchmark/driver/nsq/NsqConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.nsq; diff --git a/driver-pravega/README.md b/driver-pravega/README.md index 707f025db..5b45bb6f9 100644 --- a/driver-pravega/README.md +++ b/driver-pravega/README.md @@ -1,35 +1,44 @@ # PRAVEGA BENCHMARKS -This tutorial shows you how to run OpenMessaging benchmarks for [Pravega](https://pravega.io/). +This tutorial shows you how to run OpenMessaging benchmarks for [Pravega](https://pravega.io/). You can currently deploy to the following platforms: * [Amazon Web Services (AWS)](#deploy-a-pravega-cluster-on-amazon-web-services) # INITIAL SETUP + To begin with, you will need to clone the benchmark repo from the Pravega organization on GitHub: + ``` $ git clone https://github.com/openmessaging/openmessaging-benchmark.git $ cd openmessaging-benchmark ``` + You will also need to have [Maven](https://maven.apache.org/install.html) installed. # CREATE LOCAL ARTIFACTS -Once you have the repo cloned locally, you can create all the artifacts necessary to run the benchmarks with a single + +Once you have the repo cloned locally, you can create all the artifacts necessary to run the benchmarks with a single Maven command: + ``` $ mvn install ``` -If you want to use the pre-release version of Pravega or the master branch of Pravega, please + +If you want to use the pre-release version of Pravega or the master branch of Pravega, please check [how to build Pravega](doc/build_pravega.md). # DEPLOY A PRAVEGA CLUSTER ON AMAZON WEB SERVICES -You can deploy a Pravega cluster on AWS (for benchmarking purposes) using [Terraform 0.12.20](https://www.terraform.io/) and [Ansible 2.8.5](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html). -You’ll need to have both of those tools installed as well as the `terraform-inventory` [plugin](https://github.com/adammck/terraform-inventory) for Terraform. +You can deploy a Pravega cluster on AWS (for benchmarking purposes) using [Terraform 0.12.20](https://www.terraform.io/) +and [Ansible 2.8.5](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) (with a +a version of `Jinja2=<3.0.3`). +You’ll need to have both tools installed, as well as the `terraform-inventory` [plugin](https://github.com/adammck/terraform-inventory) for Terraform. + +You also need to install an Ansible modules to support metrics: -You also need to install an Ansible modules to support metrics. ``` -ansible-galaxy install cloudalchemy.node-exporter +ansible-galaxy install cloudalchemy.node_exporter ``` In addition, you’ll need to: @@ -38,53 +47,58 @@ In addition, you’ll need to: * [Install the `aws` CLI tool](https://aws.amazon.com/cli/) * [Configure the `aws` CLI tool](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) - # SSH KEYS + Once you’re all set up with AWS and have the necessary tools installed locally, you’ll need to create both a public and a private SSH key at `~/.ssh/pravega_aws` (private) and `~/.ssh/pravega_aws.pub` (public), respectively. ``` $ ssh-keygen -f ~/.ssh/pravega_aws ``` -When prompted to enter a passphrase, simply hit `Enter` twice. Then, make sure that the keys have been created: +When prompted to enter a passphrase, simply hit `Enter` twice. Then, make sure that the keys have been created: ``` $ ls ~/.ssh/pravega_aws* ``` # CREATE RESOURCES USING TERRAFORM + With SSH keys in place, you can create the necessary AWS resources using just a few Terraform commands: + ``` $ cd driver-pravega/deploy $ terraform init $ echo "yes" | terraform apply ``` + This will install the following [EC2](https://aws.amazon.com/ec2) instances (plus some other resources, such as a [Virtual Private Cloud](https://aws.amazon.com/vpc/) (VPC)): -| Resource | Description | Count | -| ----- | ----------- | ------ | -| Controller instances| The VMs on which a Pravega controller will run | 1 | -| Bookkeeper instances | The VMs on which a Bookkeeper and Segmentstore will run | 3 | -| ZooKeeper instances | The VMs on which a ZooKeeper node will run | 3 | -| Client instance | The VM from which the benchmarking suite itself will be run | 2 | +| Resource | Description | Count | +|----------------------|-------------------------------------------------------------|-------| +| Controller instances | The VMs on which a Pravega controller will run | 1 | +| Bookkeeper instances | The VMs on which a Bookkeeper and Segment Store will run | 3 | +| ZooKeeper instances | The VMs on which a ZooKeeper node will run | 3 | +| Client instance | The VM from which the benchmarking suite itself will be run | 2 | When you run `terraform apply`, you will be prompted to type `yes`. Type `yes` to continue with the installation or anything else to quit. # VARIABLES + There’s a handful of configurable parameters related to the Terraform deployment that you can alter by modifying the defaults in the `terraform.tfvars` file. -| Variable | Description | Default | -| ----- | ----------- | ------ | -| `region` | The AWS region in which the Pravega cluster will be deployed | `us-west-2` | -| `public_key_path` | The path to the SSH public key that you’ve generated | `~/.ssh/pravega_aws.pub` | -| `ami` | The [Amazon Machine Image (AWI)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) to be used by the cluster’s machines | `ami-9fa343e7` | -| `instance_types` | The EC2 instance types used by the various components | `i3.4xlarge` (BookKeeper bookies), `m5.large`(Controller), `t3.small` (ZooKeeper), `c5.4xlarge` (benchmarking client) | +| Variable | Description | Default | +|-------------------|--------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| `region` | The AWS region in which the Pravega cluster will be deployed | `us-east-2` | +| `public_key_path` | The path to the SSH public key that you’ve generated | `~/.ssh/pravega_aws.pub` | +| `ami` | The [Amazon Machine Image (AWI)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) to be used by the cluster’s machines | `ami-0bb2449c2217cb9b0` | +| `instance_types` | The EC2 instance types used by the various components | `i3en.2xlarge` (Segment Store + Bookkeeper), `m5n.xlarge`(Controller), `t2.small` (ZooKeeper), `m5n.xlarge` (benchmarking client), `t2.large` (metrics) | If you modify the `public_key_path`, make sure that you point to the appropriate SSH key path when running the [Ansible playbook](#_RUNNING_THE_ANSIBLE_PLAYBOOK). # RUNNING THE ANSIBLE PLAYBOOK With the appropriate infrastructure in place, you can install and start the Pravega cluster using Ansible with just one command: + ``` # Fixes "terraform-inventory had an execution error: Error reading tfstate file: 0.12 format error" $ export TF_STATE=./ @@ -93,14 +107,19 @@ $ ansible-playbook \ --inventory `which terraform-inventory` \ deploy.yaml ``` + If you’re using an SSH private key path different from `~/.ssh/pravega_aws`, you can specify that path using the `--private-key` flag, for example `--private-key=~/.ssh/my_key`. # SSHING INTO THE CLIENT HOST + In the [output](https://learn.hashicorp.com/terraform/getting-started/outputs.html) produced by Terraform, there’s a `client_ssh_host` variable that provides the IP address for the client EC2 host from which benchmarks can be run. You can SSH into that host using this command: + ``` $ ssh -i ~/.ssh/pravega_aws ec2-user@$(terraform output client_ssh_host) ``` + # RUNNING THE BENCHMARKS FROM THE CLIENT HOSTS + > The benchmark scripts can be run from the /opt/benchmark working directory. Once you’ve successfully SSHed into the client host, you can run any of the [existing benchmarking workloads](http://openmessaging.cloud/docs/benchmarks/#benchmarking-workloads) by specifying the YAML file for that workload when running the `benchmark` executable. All workloads are in the `workloads` folder. Here’s an example: @@ -110,24 +129,26 @@ $ sudo bin/benchmark \ --drivers driver-pravega/pravega.yaml \ workloads/1-topic-16-partitions-1kb.yaml ``` + > Although benchmarks are run from a specific client host, the benchmarks are run in distributed mode, across multiple client hosts. There are multiple Pravega “modes” for which you can run benchmarks. Each mode has its own YAML configuration file in the driver-pravega folder. -| Mode | Description | Config file | -| ----- | ----------- | ------ | -| Standard | Pravega with transaction disabled (at-least-once semantics) | [pravega.yaml](./pravega.yaml) | -| Exactly Once | Pravega with transaction enabled (exactly-once semantics) | [pravega-exactly-once.yaml](./pravega-exactly-once.yaml) | +| Mode | Description | Config file | +|--------------|-------------------------------------------------------------|----------------------------------------------------------| +| Standard | Pravega with transaction disabled (at-least-once semantics) | [pravega.yaml](./pravega.yaml) | +| Exactly Once | Pravega with transaction enabled (exactly-once semantics) | [pravega-exactly-once.yaml](./pravega-exactly-once.yaml) | The example used the “standard” mode as configured in `driver-pravega/pravega.yaml`. Here’s an example of running a benchmarking workload in exactly-once mode: + ``` $ sudo bin/benchmark \ --drivers driver-pravega/pravega-exactly-once.yaml \ workloads/1-topic-16-partitions-1kb.yaml ``` - # SPECIFY CLIENT HOSTS + By default, benchmarks will be run from the set of hosts created by Terraform. You can also specify a comma-separated list of client hosts using the `--workers` flag (or `-w` for short): ``` @@ -136,23 +157,31 @@ $ sudo bin/benchmark \ --workers 1.2.3.4:8080,4.5.6.7:8080 \ # or -w 1.2.3.4:8080,4.5.6.7:8080 workloads/1-topic-16-partitions-1kb.yaml ``` + # DOWNLOADING YOUR BENCHMARKING RESULTS + The OpenMessaging benchmarking suite stores results in JSON files in the `/opt/benchmark` folder on the client host from which the benchmarks are run. You can download those results files onto your local machine using `scp`. You can download all generated JSON results files using this command: ``` $ scp -i ~/.ssh/pravega_aws ec2-user@$(terraform output client_ssh_host):/opt/benchmark/*.json . ``` + # COLLECTING METRICS AND LOGS + See [metrics and logs](doc/metrics_and_logs.md). # TEARING DOWN YOUR BENCHMARKING INFRASTRUCTURE + Once you’re finished running your benchmarks, you should tear down the AWS infrastructure you deployed for the sake of saving costs. You can do that with one command: + ``` $ terraform destroy -force ``` + Make sure to let the process run to completion (it could take several minutes). Once the tear down is complete, all AWS resources that you created for the Pravega benchmarking suite will have been removed. # RUN IN KUBERNETES + See [run in Kubernetes](doc/run_in_k8s.md). # P3 Test Driver @@ -160,4 +189,5 @@ See [run in Kubernetes](doc/run_in_k8s.md). [P3 Test Driver](https://github.com/pravega/p3_test_driver) can be used to run multiple tests automatically and plot the results. # TROUBLESHOOTING + See [troubleshooting](doc/troubleshooting.md). diff --git a/driver-pravega/build-docker.sh b/driver-pravega/build-docker.sh index 00613b926..b9f2fb968 100755 --- a/driver-pravega/build-docker.sh +++ b/driver-pravega/build-docker.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # set -ex diff --git a/driver-pravega/deploy-k8s-components.sh b/driver-pravega/deploy-k8s-components.sh index a9c1a9329..cef4487de 100755 --- a/driver-pravega/deploy-k8s-components.sh +++ b/driver-pravega/deploy-k8s-components.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # set -ex diff --git a/driver-pravega/deploy/collect_logs_and_metrics.yaml b/driver-pravega/deploy/collect_logs_and_metrics.yaml index e012cb432..70e64ffa0 100644 --- a/driver-pravega/deploy/collect_logs_and_metrics.yaml +++ b/driver-pravega/deploy/collect_logs_and_metrics.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Get current time diff --git a/driver-pravega/deploy/deploy.yaml b/driver-pravega/deploy/deploy.yaml index 46de4928f..5aebfe169 100644 --- a/driver-pravega/deploy/deploy.yaml +++ b/driver-pravega/deploy/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Get common facts @@ -103,20 +98,6 @@ echo 'LANG=en_US.utf-8 LC_ALL=en_US.utf-8' > /etc/environment -#- name: Install nmon -# hosts: ["!tier2"] -# tags: ["nmon"] -# connection: ssh -# become: true -# tasks: -# - name: Download nmon -# unarchive: -# src: "http://sourceforge.net/projects/nmon/files/nmon16j.tar.gz" -# remote_src: yes -# dest: /tmp -# - command: cp /tmp/nmon_AMD64_ubuntu1804 /usr/local/bin/nmon -# - command: chmod a+x /usr/local/bin/nmon - - name: Metrics installation hosts: ["metrics"] tags: ["metrics"] @@ -125,13 +106,38 @@ tasks: - name: Add Extras Repo shell: yum-config-manager --enable rhui-REGION-rhel-server-extras - - name: Install RPM packages - yum: pkg={{ item }} state=latest - with_items: - - docker - - systemd: + when: + - ansible_facts['distribution'] == 'RedHat' + - ansible_facts['distribution_major_version'] | int <= 7 + - name: Docker repo + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: Create Docker repo dir + file: + path: "/etc/yum.repos.d/" + state: directory + - name: Add Docker Centos extras + copy: + dest: /etc/yum.repos.d/docker-ce.repo + content: | + [centos-extras] + name=Centos extras - $basearch + baseurl=http://mirror.centos.org/centos/7/extras/x86_64 + enabled=1 + gpgcheck=1 + gpgkey=http://centos.org/keys/RPM-GPG-KEY-CentOS-7 + - name: Installing docker + yum: + state: latest + pkg: ['slirp4netns', 'fuse-overlayfs', 'container-selinux', 'docker-ce'] + - name: Start docker + service: + name: docker state: started - name: "docker" enabled: yes - name: Prometheus installation @@ -197,7 +203,7 @@ hosts: ["!tier2"] tags: ["node-exporter"] roles: - - cloudalchemy.node-exporter + - cloudalchemy.node_exporter - name: ZooKeeper setup hosts: zookeeper @@ -309,7 +315,7 @@ path: "{{ item.path }}" state: unmounted with_items: - - { path: "/mnt/journal", src: "/dev/nvme0n1" } + - { path: "/mnt/journal", src: "/dev/nvme2n1" } - { path: "/mnt/storage", src: "/dev/nvme1n1" } - name: Format disks filesystem: @@ -317,7 +323,7 @@ dev: '{{ item }}' force: yes with_items: - - '/dev/nvme0n1' + - '/dev/nvme2n1' - '/dev/nvme1n1' - name: Mount disks mount: @@ -327,7 +333,7 @@ opts: defaults,noatime,nodiscard state: mounted with_items: - - { path: "/mnt/journal", src: "/dev/nvme0n1" } + - { path: "/mnt/journal", src: "/dev/nvme2n1" } - { path: "/mnt/storage", src: "/dev/nvme1n1" } - name: BookKeeper setup @@ -355,7 +361,7 @@ dest: "/opt/bookkeeper/bin/common.sh" - name: Format BookKeeper metadata in Zookeeper command: > - bin/bookkeeper shell metaformat -nonInteractive --force + bin/bookkeeper shell initnewcluster args: chdir: /opt/bookkeeper when: groups['bookkeeper'][0] == inventory_hostname diff --git a/driver-pravega/deploy/open_saved_metrics/docker-compose.yml b/driver-pravega/deploy/open_saved_metrics/docker-compose.yml index 01f0774e5..f57b90c09 100644 --- a/driver-pravega/deploy/open_saved_metrics/docker-compose.yml +++ b/driver-pravega/deploy/open_saved_metrics/docker-compose.yml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # version: '2' diff --git a/driver-pravega/deploy/open_saved_metrics/open_saved_metrics.sh b/driver-pravega/deploy/open_saved_metrics/open_saved_metrics.sh index d9cfacb23..75643fd77 100755 --- a/driver-pravega/deploy/open_saved_metrics/open_saved_metrics.sh +++ b/driver-pravega/deploy/open_saved_metrics/open_saved_metrics.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # set -e diff --git a/driver-pravega/deploy/provision-pravega-aws.tf b/driver-pravega/deploy/provision-pravega-aws.tf index 49f959a70..f3c4b6236 100644 --- a/driver-pravega/deploy/provision-pravega-aws.tf +++ b/driver-pravega/deploy/provision-pravega-aws.tf @@ -190,7 +190,7 @@ resource "aws_instance" "metrics" { # Change the EFS provisioned TP here resource "aws_efs_file_system" "tier2" { throughput_mode = "provisioned" - provisioned_throughput_in_mibps = 1000 + provisioned_throughput_in_mibps = 100 tags = { Name = "pravega-tier2" } diff --git a/driver-pravega/deploy/templates/bk_server.conf b/driver-pravega/deploy/templates/bk_server.conf index 91bf16448..4324303a9 100755 --- a/driver-pravega/deploy/templates/bk_server.conf +++ b/driver-pravega/deploy/templates/bk_server.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # The bookie server configuration are organized in sections diff --git a/driver-pravega/deploy/templates/bkenv.sh b/driver-pravega/deploy/templates/bkenv.sh index 7c3c4096d..e7250703a 100755 --- a/driver-pravega/deploy/templates/bkenv.sh +++ b/driver-pravega/deploy/templates/bkenv.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Set JAVA_HOME here to override the environment setting diff --git a/driver-pravega/deploy/templates/chrony.conf b/driver-pravega/deploy/templates/chrony.conf index 0e68c66a5..2ec5485aa 100644 --- a/driver-pravega/deploy/templates/chrony.conf +++ b/driver-pravega/deploy/templates/chrony.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Use public servers from the pool.ntp.org project. diff --git a/driver-pravega/deploy/templates/common.sh b/driver-pravega/deploy/templates/common.sh index e5dd6b59b..549eded18 100644 --- a/driver-pravega/deploy/templates/common.sh +++ b/driver-pravega/deploy/templates/common.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Check net.ipv6.bindv6only diff --git a/driver-pravega/deploy/templates/config.properties b/driver-pravega/deploy/templates/config.properties index 96efa778b..5628f864d 100644 --- a/driver-pravega/deploy/templates/config.properties +++ b/driver-pravega/deploy/templates/config.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # ## Instructions for using this file: diff --git a/driver-pravega/deploy/templates/controller.config.properties b/driver-pravega/deploy/templates/controller.config.properties index edc65d178..c387acdd8 100644 --- a/driver-pravega/deploy/templates/controller.config.properties +++ b/driver-pravega/deploy/templates/controller.config.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # ## Instructions for using this file: diff --git a/driver-pravega/deploy/templates/logback.xml b/driver-pravega/deploy/templates/logback.xml index 73cd0904f..ad30f68d0 100644 --- a/driver-pravega/deploy/templates/logback.xml +++ b/driver-pravega/deploy/templates/logback.xml @@ -1,22 +1,17 @@ diff --git a/driver-pravega/deploy/templates/prometheus.yml b/driver-pravega/deploy/templates/prometheus.yml index 8cc93a4ac..b3717a78d 100644 --- a/driver-pravega/deploy/templates/prometheus.yml +++ b/driver-pravega/deploy/templates/prometheus.yml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # my global config diff --git a/driver-pravega/deploy/templates/workers.yaml b/driver-pravega/deploy/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-pravega/deploy/templates/workers.yaml +++ b/driver-pravega/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-pravega/deploy/templates/zoo.cfg b/driver-pravega/deploy/templates/zoo.cfg index b33cad819..dbd337067 100644 --- a/driver-pravega/deploy/templates/zoo.cfg +++ b/driver-pravega/deploy/templates/zoo.cfg @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # The number of milliseconds of each tick diff --git a/driver-pravega/deploy/terraform.tfvars b/driver-pravega/deploy/terraform.tfvars index 52c9e863e..ecac89770 100644 --- a/driver-pravega/deploy/terraform.tfvars +++ b/driver-pravega/deploy/terraform.tfvars @@ -1,12 +1,12 @@ public_key_path = "~/.ssh/pravega_aws.pub" -region = "us-west-2" -ami = "ami-9fa343e7" // RHEL-7.4 us-west-2 +region = "us-east-2" +ami = "ami-0bb2449c2217cb9b0" // RHEL-7.9 us-east-2 instance_types = { "controller" = "m5.large" - "bookkeeper" = "i3en.6xlarge" + "bookkeeper" = "i3en.2xlarge" "zookeeper" = "t2.small" - "client" = "m5n.8xlarge" + "client" = "m5n.xlarge" "metrics" = "t2.large" } @@ -14,6 +14,6 @@ num_instances = { "controller" = 1 "bookkeeper" = 3 "zookeeper" = 3 - "client" = 2 + "client" = 1 "metrics" = 1 } diff --git a/driver-pravega/deploy/vars.yaml b/driver-pravega/deploy/vars.yaml index 0a37e8d9a..e6e9543aa 100644 --- a/driver-pravega/deploy/vars.yaml +++ b/driver-pravega/deploy/vars.yaml @@ -1,24 +1,19 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # --- -pravegaVersion: "0.10.1" +pravegaVersion: "0.12.0" zookeeperVersion: "3.5.5" bookkeeperVersion: "4.14.2" prometheusVersion: "2.2.1" diff --git a/driver-pravega/doc/build_pravega.md b/driver-pravega/doc/build_pravega.md index b1a82a20c..1808b7690 100644 --- a/driver-pravega/doc/build_pravega.md +++ b/driver-pravega/doc/build_pravega.md @@ -11,6 +11,7 @@ git checkout master This will build the file `pravega/build/distributions/pravega-0.9.0.tgz.` Then comment `pravegaSrc` and `pravegaSrcRemote: yes` and uncomment `pravegaSrc` `pravegaSrcRemote: no` in `driver-pravega/deploy/deploy.yaml` + ``` # Change below to use a published release of Pravega or a local build. # pravegaSrc: "https://github.com/pravega/pravega/releases/download/v{{ pravegaVersion }}/pravega-{{ pravegaVersion }}.tgz" @@ -19,12 +20,16 @@ Then comment `pravegaSrc` and `pravegaSrcRemote: yes` and uncomment `pravegaSrc` pravegaSrc: "../../../pravega/build/distributions/pravega-{{ pravegaVersion }}.tgz" pravegaSrcRemote: no ``` + If needed, change the variable `pravegaVersion` in [vars.yaml](../deploy/vars.yaml) to match the version built. If needed, change [pom.xml](../pom.xml) to match the version built. ## Build Benchmark + Add flag to skip license check`-Dlicense.skip=true` if license check failed. + ``` mvn clean install ``` + diff --git a/driver-pravega/doc/metrics_and_logs.md b/driver-pravega/doc/metrics_and_logs.md index 929492273..9e72570eb 100644 --- a/driver-pravega/doc/metrics_and_logs.md +++ b/driver-pravega/doc/metrics_and_logs.md @@ -44,12 +44,12 @@ Login using user name "admin" and any password. Configure Grafana with the following data sources: - - Prometheus - - Name: Prometheus - - HTTP URL: http://prometheus:9090 - - InfluxDB - - Name: pravega-influxdb - - HTTP URL: http://influxdb:8086 - - InfluxDB Details Database: pravega +- Prometheus + - Name: Prometheus + - HTTP URL: http://prometheus:9090 +- InfluxDB + - Name: pravega-influxdb + - HTTP URL: http://influxdb:8086 + - InfluxDB Details Database: pravega Load dashboards from [deploy/templates/dashboards](../deploy/templates/dashboards). diff --git a/driver-pravega/doc/run_in_k8s.md b/driver-pravega/doc/run_in_k8s.md index 73ee6aa5f..073bc2f89 100644 --- a/driver-pravega/doc/run_in_k8s.md +++ b/driver-pravega/doc/run_in_k8s.md @@ -7,6 +7,7 @@ ``` ## Run local driver on Kubernetes: + ``` kubectl run -n examples --rm -it --image pravega/openmessaging-benchmark:latest --serviceaccount examples-pravega openmessaging-benchmark ``` @@ -15,3 +16,5 @@ kubectl run -n examples --rm -it --image pravega/openmessaging-benchmark:latest ``` ./deploy-k8s-components.sh +``` + diff --git a/driver-pravega/doc/troubleshooting.md b/driver-pravega/doc/troubleshooting.md index 6ff3c0927..2ec033937 100644 --- a/driver-pravega/doc/troubleshooting.md +++ b/driver-pravega/doc/troubleshooting.md @@ -13,3 +13,4 @@ journalctl -u pravega-segmentstore ``` export TF_STATE=./ ``` + diff --git a/driver-pravega/driver-bash.sh b/driver-pravega/driver-bash.sh index 8a8549821..40d28bcd2 100755 --- a/driver-pravega/driver-bash.sh +++ b/driver-pravega/driver-bash.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # set -ex diff --git a/driver-pravega/pom.xml b/driver-pravega/pom.xml index 1afdbc2cf..d1d184f9e 100644 --- a/driver-pravega/pom.xml +++ b/driver-pravega/pom.xml @@ -1,21 +1,17 @@ + io.openmessaging.benchmark messaging-benchmark 0.0.1-SNAPSHOT - .. driver-pravega - 0.10.1 + 0.12.0 - - - jfrog - jfrog - https://oss.jfrog.org/jfrog-dependencies - - false - - - - ${project.groupId} driver-api ${project.version} - - - io.pravega - pravega-client - ${pravegaVersion} - - - io.pravega - pravega-keycloak-client - 0.9.0 + com.google.protobuf + protobuf-java-util + 3.21.5 - io.grpc grpc-all - 1.36.0 + 1.49.0 + + + io.netty + netty-all - io.perfmark perfmark-api - 0.23.0 + 0.25.0 compile - - io.netty - netty-all - 4.1.65.Final + io.pravega + pravega-client + ${pravegaVersion} - - com.google.protobuf - protobuf-java-util - 3.4.0 + io.pravega + pravega-keycloak-client + ${pravegaVersion} - org.apache.commons commons-lang3 - 3.7 + + + + false + + jfrog + jfrog + https://oss.jfrog.org/jfrog-dependencies + + + diff --git a/driver-pravega/pravega-exactly-once.yaml b/driver-pravega/pravega-exactly-once.yaml index 58ea0f709..eee7f8a3d 100644 --- a/driver-pravega/pravega-exactly-once.yaml +++ b/driver-pravega/pravega-exactly-once.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Pravega diff --git a/driver-pravega/pravega.yaml b/driver-pravega/pravega.yaml index 6b05d795d..f7c8546f0 100644 --- a/driver-pravega/pravega.yaml +++ b/driver-pravega/pravega.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Pravega diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkConsumer.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkConsumer.java index 767bdd3c9..07b99c57f 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkConsumer.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkConsumer.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega; + import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.ConsumerCallback; import io.pravega.client.EventStreamClientFactory; @@ -28,15 +24,14 @@ import io.pravega.client.stream.ReinitializationRequiredException; import io.pravega.client.stream.Stream; import io.pravega.client.stream.impl.ByteBufferSerializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.nio.ByteBuffer; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PravegaBenchmarkConsumer implements BenchmarkConsumer { private static final Logger log = LoggerFactory.getLogger(PravegaBenchmarkConsumer.class); @@ -45,43 +40,52 @@ public class PravegaBenchmarkConsumer implements BenchmarkConsumer { private final EventStreamReader reader; private final AtomicBoolean closed = new AtomicBoolean(false); - public PravegaBenchmarkConsumer(String streamName, String scopeName, String subscriptionName, ConsumerCallback consumerCallback, - EventStreamClientFactory clientFactory, ReaderGroupManager readerGroupManager, - boolean includeTimestampInEvent) { - log.info("PravegaBenchmarkConsumer: BEGIN: subscriptionName={}, streamName={}", subscriptionName, streamName); + public PravegaBenchmarkConsumer( + String streamName, + String scopeName, + String subscriptionName, + ConsumerCallback consumerCallback, + EventStreamClientFactory clientFactory, + ReaderGroupManager readerGroupManager, + boolean includeTimestampInEvent) { + log.info( + "PravegaBenchmarkConsumer: BEGIN: subscriptionName={}, streamName={}", + subscriptionName, + streamName); // Create reader group if it doesn't already exist. - final ReaderGroupConfig readerGroupConfig = ReaderGroupConfig.builder() - .stream(Stream.of(scopeName, streamName)) - .build(); + final ReaderGroupConfig readerGroupConfig = + ReaderGroupConfig.builder().stream(Stream.of(scopeName, streamName)).build(); readerGroupManager.createReaderGroup(subscriptionName, readerGroupConfig); // Create reader. - reader = clientFactory.createReader( - UUID.randomUUID().toString(), - subscriptionName, - new ByteBufferSerializer(), - ReaderConfig.builder().disableTimeWindows(true).build()); + reader = + clientFactory.createReader( + UUID.randomUUID().toString(), + subscriptionName, + new ByteBufferSerializer(), + ReaderConfig.builder().disableTimeWindows(true).build()); // Start a thread to read events. this.executor = Executors.newSingleThreadExecutor(); - this.executor.submit(() -> { - while (!closed.get()) { - try { - final ByteBuffer event = reader.readNextEvent(1000).getEvent(); - if (event != null) { - long eventTimestamp; - if (includeTimestampInEvent) { - eventTimestamp = event.getLong(); - } else { - // This will result in an invalid end-to-end latency measurement of 0 seconds. - eventTimestamp = TimeUnit.MICROSECONDS.toMillis(Long.MAX_VALUE); - } - consumerCallback.messageReceived(event, eventTimestamp); - } - } catch (ReinitializationRequiredException e) { - log.error("Exception during read", e); - throw e; - } - } - }); + this.executor.submit( + () -> { + while (!closed.get()) { + try { + final ByteBuffer event = reader.readNextEvent(1000).getEvent(); + if (event != null) { + long eventTimestamp; + if (includeTimestampInEvent) { + eventTimestamp = event.getLong(); + } else { + // This will result in an invalid end-to-end latency measurement of 0 seconds. + eventTimestamp = TimeUnit.MICROSECONDS.toMillis(Long.MAX_VALUE); + } + consumerCallback.messageReceived(event, eventTimestamp); + } + } catch (ReinitializationRequiredException e) { + log.error("Exception during read", e); + throw e; + } + } + }); } @Override diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkDriver.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkDriver.java index 67b245c54..5cb421491 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkDriver.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkDriver.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; @@ -33,21 +29,21 @@ import io.pravega.client.admin.StreamManager; import io.pravega.client.stream.ScalingPolicy; import io.pravega.client.stream.StreamConfiguration; -import org.apache.bookkeeper.stats.StatsLogger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.apache.bookkeeper.stats.StatsLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PravegaBenchmarkDriver implements BenchmarkDriver { private static final Logger log = LoggerFactory.getLogger(PravegaBenchmarkDriver.class); - private static final ObjectWriter objectWriter = new ObjectMapper().writerWithDefaultPrettyPrinter(); + private static final ObjectWriter objectWriter = + new ObjectMapper().writerWithDefaultPrettyPrinter(); private PravegaConfig config; private ClientConfig clientConfig; @@ -62,15 +58,17 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I config = readConfig(configurationFile); log.info("Pravega driver configuration: {}", objectWriter.writeValueAsString(config)); - clientConfig = ClientConfig.builder().controllerURI(URI.create(config.client.controllerURI)).build(); + clientConfig = + ClientConfig.builder().controllerURI(URI.create(config.client.controllerURI)).build(); scopeName = config.client.scopeName; streamManager = StreamManager.create(clientConfig); readerGroupManager = ReaderGroupManager.withScope(scopeName, clientConfig); clientFactory = EventStreamClientFactory.withScope(scopeName, clientConfig); } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static PravegaConfig readConfig(File configurationFile) throws IOException { return mapper.readValue(configurationFile, PravegaConfig.class); @@ -78,6 +76,9 @@ private static PravegaConfig readConfig(File configurationFile) throws IOExcepti /** * Clean Pravega stream name to only allow alpha-numeric and "-". + * + * @param name + * @return the cleaned name */ private String cleanName(String name) { return name.replaceAll("[^A-Za-z0-9-]", ""); @@ -100,15 +101,18 @@ public CompletableFuture createTopic(String topic, int partitions) { } ScalingPolicy scalingPolicy; // Create a fixed or auto-scaling Stream based on user configuration. - if (config.enableStreamAutoScaling && (config.eventsPerSecond != PravegaConfig.DEFAULT_STREAM_AUTOSCALING_VALUE || - config.kbytesPerSecond != PravegaConfig.DEFAULT_STREAM_AUTOSCALING_VALUE)) { - scalingPolicy = config.eventsPerSecond != PravegaConfig.DEFAULT_STREAM_AUTOSCALING_VALUE ? - ScalingPolicy.byEventRate(config.eventsPerSecond, 2, partitions) : - ScalingPolicy.byDataRate(config.kbytesPerSecond, 2, partitions); + if (config.enableStreamAutoScaling + && (config.eventsPerSecond != PravegaConfig.DEFAULT_STREAM_AUTOSCALING_VALUE + || config.kbytesPerSecond != PravegaConfig.DEFAULT_STREAM_AUTOSCALING_VALUE)) { + scalingPolicy = + config.eventsPerSecond != PravegaConfig.DEFAULT_STREAM_AUTOSCALING_VALUE + ? ScalingPolicy.byEventRate(config.eventsPerSecond, 2, partitions) + : ScalingPolicy.byDataRate(config.kbytesPerSecond, 2, partitions); } else { scalingPolicy = ScalingPolicy.fixed(partitions); } - streamManager.createStream(scopeName, topic, StreamConfiguration.builder().scalingPolicy(scalingPolicy).build()); + streamManager.createStream( + scopeName, topic, StreamConfiguration.builder().scalingPolicy(scalingPolicy).build()); return CompletableFuture.completedFuture(null); } @@ -117,22 +121,38 @@ public CompletableFuture createProducer(String topic) { topic = cleanName(topic); BenchmarkProducer producer = null; if (config.enableTransaction) { - producer = new PravegaBenchmarkTransactionProducer(topic, clientFactory, config.includeTimestampInEvent, - config.writer.enableConnectionPooling, config.eventsPerTransaction); + producer = + new PravegaBenchmarkTransactionProducer( + topic, + clientFactory, + config.includeTimestampInEvent, + config.writer.enableConnectionPooling, + config.eventsPerTransaction); } else { - producer = new PravegaBenchmarkProducer(topic, clientFactory, config.includeTimestampInEvent, - config.writer.enableConnectionPooling); + producer = + new PravegaBenchmarkProducer( + topic, + clientFactory, + config.includeTimestampInEvent, + config.writer.enableConnectionPooling); } return CompletableFuture.completedFuture(producer); } @Override - public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { topic = cleanName(topic); subscriptionName = cleanName(subscriptionName); - BenchmarkConsumer consumer = new PravegaBenchmarkConsumer(topic, scopeName, subscriptionName, consumerCallback, - clientFactory, readerGroupManager, config.includeTimestampInEvent); + BenchmarkConsumer consumer = + new PravegaBenchmarkConsumer( + topic, + scopeName, + subscriptionName, + consumerCallback, + clientFactory, + readerGroupManager, + config.includeTimestampInEvent); return CompletableFuture.completedFuture(consumer); } diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkProducer.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkProducer.java index db7615968..1319d8913 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkProducer.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkProducer.java @@ -1,34 +1,29 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega; + import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.pravega.client.EventStreamClientFactory; import io.pravega.client.stream.EventStreamWriter; import io.pravega.client.stream.EventWriterConfig; import io.pravega.client.stream.impl.ByteBufferSerializer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.nio.ByteBuffer; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PravegaBenchmarkProducer implements BenchmarkProducer { private static final Logger log = LoggerFactory.getLogger(PravegaBenchmarkProducer.class); @@ -37,23 +32,25 @@ public class PravegaBenchmarkProducer implements BenchmarkProducer { private final boolean includeTimestampInEvent; private ByteBuffer timestampAndPayload; - public PravegaBenchmarkProducer(String streamName, EventStreamClientFactory clientFactory, - boolean includeTimestampInEvent, - boolean enableConnectionPooling) { + public PravegaBenchmarkProducer( + String streamName, + EventStreamClientFactory clientFactory, + boolean includeTimestampInEvent, + boolean enableConnectionPooling) { log.info("PravegaBenchmarkProducer: BEGIN: streamName={}", streamName); - writer = clientFactory.createEventWriter( - streamName, - new ByteBufferSerializer(), - EventWriterConfig.builder() - .enableConnectionPooling(enableConnectionPooling) - .build()); + writer = + clientFactory.createEventWriter( + streamName, + new ByteBufferSerializer(), + EventWriterConfig.builder().enableConnectionPooling(enableConnectionPooling).build()); this.includeTimestampInEvent = includeTimestampInEvent; } @Override public CompletableFuture sendAsync(Optional key, byte[] payload) { if (includeTimestampInEvent) { - if (timestampAndPayload == null || timestampAndPayload.limit() != Long.BYTES + payload.length) { + if (timestampAndPayload == null + || timestampAndPayload.limit() != Long.BYTES + payload.length) { timestampAndPayload = ByteBuffer.allocate(Long.BYTES + payload.length); } else { timestampAndPayload.position(0); diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkTransactionProducer.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkTransactionProducer.java index d65bf2fea..fde2d00b1 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkTransactionProducer.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/PravegaBenchmarkTransactionProducer.java @@ -1,38 +1,33 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega; + +import com.google.errorprone.annotations.concurrent.GuardedBy; import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.pravega.client.EventStreamClientFactory; import io.pravega.client.stream.EventWriterConfig; -import io.pravega.client.stream.impl.ByteBufferSerializer; import io.pravega.client.stream.Transaction; import io.pravega.client.stream.TransactionalEventStreamWriter; import io.pravega.client.stream.TxnFailedException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.google.errorprone.annotations.concurrent.GuardedBy; - +import io.pravega.client.stream.impl.ByteBufferSerializer; import java.nio.ByteBuffer; import java.util.Optional; -import java.util.concurrent.CompletableFuture; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PravegaBenchmarkTransactionProducer implements BenchmarkProducer { private static final Logger log = LoggerFactory.getLogger(PravegaBenchmarkProducer.class); @@ -44,18 +39,26 @@ public class PravegaBenchmarkTransactionProducer implements BenchmarkProducer { // If null, a transaction has not been started. @GuardedBy("this") private Transaction transaction; + private final int eventsPerTransaction; private int eventCount = 0; private ByteBuffer timestampAndPayload; - public PravegaBenchmarkTransactionProducer(String streamName, EventStreamClientFactory clientFactory, - boolean includeTimestampInEvent, boolean enableConnectionPooling, int eventsPerTransaction) { + public PravegaBenchmarkTransactionProducer( + String streamName, + EventStreamClientFactory clientFactory, + boolean includeTimestampInEvent, + boolean enableConnectionPooling, + int eventsPerTransaction) { log.info("PravegaBenchmarkProducer: BEGIN: streamName={}", streamName); final String writerId = UUID.randomUUID().toString(); - transactionWriter = clientFactory.createTransactionalEventWriter(writerId, streamName, - new ByteBufferSerializer(), - EventWriterConfig.builder().enableConnectionPooling(enableConnectionPooling).build()); + transactionWriter = + clientFactory.createTransactionalEventWriter( + writerId, + streamName, + new ByteBufferSerializer(), + EventWriterConfig.builder().enableConnectionPooling(enableConnectionPooling).build()); this.eventsPerTransaction = eventsPerTransaction; this.includeTimestampInEvent = includeTimestampInEvent; } @@ -66,14 +69,16 @@ public CompletableFuture sendAsync(Optional key, byte[] payload) { if (transaction == null) { transaction = transactionWriter.beginTxn(); } - if (this.probeRequested(key)) { // Populate probe transaction with the sufficient amount of events. + if (this.probeRequested( + key)) { // Populate probe transaction with the sufficient amount of events. while (eventCount < this.eventsPerTransaction) { transaction.writeEvent(key.get(), ByteBuffer.wrap(payload)); eventCount++; } } if (includeTimestampInEvent) { - if (timestampAndPayload == null || timestampAndPayload.limit() != Long.BYTES + payload.length) { + if (timestampAndPayload == null + || timestampAndPayload.limit() != Long.BYTES + payload.length) { timestampAndPayload = ByteBuffer.allocate(Long.BYTES + payload.length); } else { timestampAndPayload.position(0); @@ -114,11 +119,13 @@ public void close() throws Exception { transactionWriter.close(); } - /** Indicates if producer probe had been requested by OpenMessaging benchmark. + /** + * Indicates if producer probe had been requested by OpenMessaging benchmark. + * * @param key - key provided to the probe. * @return true in case requested event had been created in context of producer probe. */ - private final boolean probeRequested(Optional key) { + private boolean probeRequested(Optional key) { // For the expected key, see: LocalWorker.probeProducers() final String expectedKey = "key"; return key.isPresent() && key.get().equals(expectedKey); diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaClientConfig.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaClientConfig.java index 2d98780b2..f1dd86b60 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaClientConfig.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaClientConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega.config; diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaConfig.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaConfig.java index 058872c17..d5c46d218 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaConfig.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaConfig.java @@ -1,26 +1,22 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega.config; public class PravegaConfig { - // By default, Stream auto-scaling is not configured. So the scaling thresholds are initialized with -1. - public static int DEFAULT_STREAM_AUTOSCALING_VALUE = -1; + // By default, Stream auto-scaling is not configured. So the scaling thresholds are initialized + // with -1. + public static final int DEFAULT_STREAM_AUTOSCALING_VALUE = -1; public PravegaClientConfig client; public PravegaWriterConfig writer; diff --git a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaWriterConfig.java b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaWriterConfig.java index 344bb5cb4..d470e8d31 100644 --- a/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaWriterConfig.java +++ b/driver-pravega/src/main/java/io/openmessaging/benchmark/driver/pravega/config/PravegaWriterConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pravega.config; diff --git a/driver-pravega/uninstall.sh b/driver-pravega/uninstall.sh index 32351eeb8..1cac531a4 100755 --- a/driver-pravega/uninstall.sh +++ b/driver-pravega/uninstall.sh @@ -1,21 +1,16 @@ #!/bin/bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # set -x diff --git a/driver-pulsar/README.md b/driver-pulsar/README.md index c01949d89..730b6f562 100644 --- a/driver-pulsar/README.md +++ b/driver-pulsar/README.md @@ -1,3 +1,65 @@ # Apache Pulsar benchmarks For instructions on running the OpenMessaging benchmarks for Pulsar, see the [official documentation](http://openmessaging.cloud/docs/benchmarks/pulsar/). + +## Supplement to the official documentation + +Before you run `ansible-playbook` with `terraform-inventory`, you must set the environment variable `TF_STATE`. i.e. the completed command should be: + +```bash +TF_STATE=. ansible-playbook \ + --user ec2-user \ + --inventory `which terraform-inventory` \ + deploy.yaml +``` + +### Ansible variable files + +The Ansible deployment script supports flexible configuration with a variable file, which is specified by `-e` option like: + +```bash +TF_STATE=. ansible-playbook \ + --user ec2-user \ + --inventory `which terraform-inventory` \ + -e @extra_vars.yaml \ + deploy.yaml +``` + +For example, if you changed the AWS instance type, the two SSD device paths might not be `/dev/nvme1n1` and `/dev/nvme2n1`. In this case, you can configure them like + +```yaml +disk_dev: + - /path/to/disk1 + - /path/to/disk2 +``` + +See more explanations in [the example variable file](./deploy/ssd/extra_vars.yaml). + +### Enable protocol handlers + +With the Ansible variable file, you can enable multiple protocol handlers in `protocol_handlers` variable. For example, given following configurations: + +```yaml +protocol_handlers: + - protocol: kafka + conf: kop.conf + url: https://github.com/streamnative/kop/releases/download/v2.9.2.5/pulsar-protocol-handler-kafka-2.9.2.5.nar + - protocol: mqtt + conf: mop.conf + url: https://github.com/streamnative/mop/releases/download/v2.9.2.5/pulsar-protocol-handler-mqtt-2.9.2.5.nar +``` + +It will download KoP and MoP from the given URLs. Then, the configuration templates will be formatted and appended to the `broker.conf`. The `conf` field is the name of the configuration template, which must be put under `templates` directory. + +### Restart the brokers with new configurations + +You can change the configuration files and then restart the cluster by executing the following command. + +```bash +TF_STATE=. ansible-playbook \ + --user ec2-user \ + --inventory `which terraform-inventory` \ + -e @extra_vars.yaml \ + restart-brokers.yaml +``` + diff --git a/driver-pulsar/deploy/ssd/alicloud/deploy.yaml b/driver-pulsar/deploy/ssd/alicloud/deploy.yaml index 3d9702706..f4ccd18e5 100644 --- a/driver-pulsar/deploy/ssd/alicloud/deploy.yaml +++ b/driver-pulsar/deploy/ssd/alicloud/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Prepare variable diff --git a/driver-pulsar/deploy/ssd/deploy-client-jars.yaml b/driver-pulsar/deploy/ssd/deploy-client-jars.yaml new file mode 100644 index 000000000..d210cba01 --- /dev/null +++ b/driver-pulsar/deploy/ssd/deploy-client-jars.yaml @@ -0,0 +1,30 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +- name: Deploy benchmark + hosts: client + connection: ssh + become: true + tasks: + - shell: rm -fr /opt/openmessaging-benchmark-0.0.1-SNAPSHOT + - shell: rm -f /opt/benchmark/lib/io.openmessaging.* + - unarchive: + src: ../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz + dest: /opt + - shell: cp -f /opt/openmessaging-benchmark-0.0.1-SNAPSHOT/lib/io.openmessaging.* /opt/benchmark/lib/ + - name: Benchmark - Start service + systemd: + state: restarted + daemon_reload: yes + name: "benchmark-worker" diff --git a/driver-pulsar/deploy/ssd/deploy_with_stats.yaml b/driver-pulsar/deploy/ssd/deploy.yaml similarity index 62% rename from driver-pulsar/deploy/ssd/deploy_with_stats.yaml rename to driver-pulsar/deploy/ssd/deploy.yaml index 146b2ddb2..48a816dbb 100644 --- a/driver-pulsar/deploy/ssd/deploy_with_stats.yaml +++ b/driver-pulsar/deploy/ssd/deploy.yaml @@ -1,22 +1,71 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # +- name: Initialize some default values + hosts: all + connection: ssh + tasks: + - set_fact: + private_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + - set_fact: + zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" + serviceUrl: "pulsar://{{ hostvars[groups['pulsar'][0]].private_ip }}:6650/" + httpUrl: "http://{{ hostvars[groups['pulsar'][0]].private_ip }}:8080/" + - set_fact: + pulsar_version: "{{ pulsar_version | default('2.11.0') }}" + node_exporter_version: "{{ node_exporter_version | default('1.2.2') }}" + prometheus_version: "{{ prometheus_version | default('2.31.1') }}" + disk_dev: "{{ disk_dev | default(['/dev/nvme1n1', '/dev/nvme2n1']) }}" + - set_fact: + pulsar_binary: + src: "https://downloads.apache.org/pulsar/pulsar-{{ pulsar_version }}/apache-pulsar-{{ pulsar_version }}-bin.tar.gz" + remote: yes + when: pulsar_binary is not defined + - set_fact: + node_exporter_binary: + src: "https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz" + remote: yes + when: node_exporter_binary is not defined + - set_fact: + prometheus_binary: + src: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}/prometheus-{{ prometheus_version }}.linux-amd64.tar.gz" + remote: yes + when: prometheus_binary is not defined + +- name: Format and mount disks for Zookeeper hosts + hosts: zookeeper + connection: ssh + become: true + tasks: + - name: Format disks + filesystem: + fstype: xfs + dev: '{{ item }}' + with_items: + - "{{ disk_dev[0] }}" + - "{{ disk_dev[1] }}" + - name: Mount disks + mount: + path: "{{ item.path }}" + src: "{{ item.src }}" + fstype: xfs + opts: defaults,noatime,nodiscard + state: mounted + with_items: + - { path: "/mnt/zookeeper/logs", src: "{{ disk_dev[0] }}" } + - { path: "/mnt/zookeeper/data", src: "{{ disk_dev[1] }}" } + - name: Format and mount disks for Pulsar/BookKeeper hosts hosts: pulsar connection: ssh @@ -27,8 +76,8 @@ fstype: xfs dev: '{{ item }}' with_items: - - '/dev/nvme1n1' - - '/dev/nvme2n1' + - "{{ disk_dev[0] }}" + - "{{ disk_dev[1] }}" - name: Mount disks mount: path: "{{ item.path }}" @@ -37,31 +86,28 @@ opts: defaults,noatime,nodiscard state: mounted with_items: - - { path: "/mnt/journal", src: "/dev/nvme1n1" } - - { path: "/mnt/storage", src: "/dev/nvme2n1" } + - { path: "/mnt/journal", src: "{{ disk_dev[0] }}" } + - { path: "/mnt/storage", src: "{{ disk_dev[1] }}" } - name: Install Node exporter on Brokers to collect system metrics hosts: pulsar become: true tasks: - - set_fact: - nodeExporterVersion: "1.2.2" - name: Add user node_exporter user: name: node_exporter shell: /bin/false system: true create_home: no - - name: Download and extract unarchive: - src: "https://github.com/prometheus/node_exporter/releases/download/v{{ nodeExporterVersion }}/node_exporter-{{ nodeExporterVersion }}.linux-amd64.tar.gz" + src: "{{ node_exporter_binary.src }}" dest: /tmp - remote_src: yes + remote_src: "{{ node_exporter_binary.remote }}" - name: Copy bin node_exporter to /usr/local/bin copy: - src: "/tmp/node_exporter-{{ nodeExporterVersion }}.linux-amd64/node_exporter" + src: "/tmp/node_exporter-{{ node_exporter_version }}.linux-amd64/node_exporter" remote_src: yes dest: /usr/local/bin/ owner: node_exporter @@ -102,46 +148,69 @@ timeout: 5 - name: Pulsar installation - hosts: all + hosts: pulsar:client:zookeeper connection: ssh become: true tasks: - name: Set performance profile command: tuned-adm profile latency-performance - name: Install RPM packages - yum: pkg={{ item }} state=latest - with_items: + yum: + state: latest + pkg: - wget - - java-11-openjdk - - java-11-openjdk-devel + - java-17-openjdk + - java-17-openjdk-devel - sysstat - vim - chrony - - set_fact: - zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" - serviceUrl: "pulsar://{{ hostvars[groups['pulsar'][0]].private_ip }}:6650/" - httpUrl: "http://{{ hostvars[groups['pulsar'][0]].private_ip }}:8080/" - pulsarVersion: "2.8.1" + when: ansible_facts['distribution'] == 'RedHat' - file: path=/opt/pulsar state=absent - file: path=/opt/pulsar state=directory - name: Download Pulsar binary package unarchive: - src: "https://downloads.apache.org/pulsar/pulsar-{{ pulsarVersion }}/apache-pulsar-{{ pulsarVersion }}-bin.tar.gz" - remote_src: yes + src: "{{ pulsar_binary.src }}" + remote_src: "{{ pulsar_binary.remote }}" dest: /opt/pulsar extra_opts: ["--strip-components=1"] - set_fact: - private_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" - max_heap_memory: "16g" - max_direct_memory: "48g" + max_heap_memory: "{{ pulsar_max_heap_memory | default('32g') }}" + max_direct_memory: "{{ pulsar_max_direct_memory | default('32g') }}" - template: src: "templates/pulsar_env.sh" dest: "/opt/pulsar/conf/pulsar_env.sh" + - template: + src: "templates/bkenv.sh" + dest: "/opt/pulsar/conf/bkenv.sh" - name: Change locale to en_US.utf-8 shell: | echo 'LANG=en_US.utf-8 LC_ALL=en_US.utf-8' > /etc/environment +#- name: Protocol Handlers installation +# hosts: pulsar +# connection: ssh +# become: true +# tasks: +# - file: path=/opt/pulsar/protocols state=absent +# - file: path=/opt/pulsar/protocols state=directory +# - name: Upload local protocol handlers +# copy: +# src: "{{ item.local_path }}" +# dest: /opt/pulsar/protocols +# loop: "{{ protocol_handlers }}" +# when: +# - protocol_handlers is defined +# - item.local_path is defined +# - name: Download protocol handlers +# get_url: +# url: "{{ item.url }}" +# dest: /opt/pulsar/protocols +# loop: "{{ protocol_handlers }}" +# when: +# - protocol_handlers is defined +# - item.local_path is not defined + - name: ZooKeeper setup hosts: zookeeper connection: ssh @@ -149,8 +218,8 @@ tasks: - set_fact: zid: "{{ groups['zookeeper'].index(inventory_hostname) }}" - max_heap_memory: "512m" - max_direct_memory: "512m" + max_heap_memory: "{{ zookeeper_max_heap_memory | default('32G') }}" + max_direct_memory: "{{ zookeeper_max_direct_memory | default('2G') }}" - file: path: "/opt/pulsar/{{ item }}" state: directory @@ -164,7 +233,7 @@ dest: "/opt/pulsar/conf/zookeeper.conf" - template: src: templates/myid - dest: "/opt/pulsar/data/zookeeper/myid" + dest: "/mnt/zookeeper/data/myid" - template: src: "templates/zookeeper.service" dest: "/etc/systemd/system/zookeeper.service" @@ -172,23 +241,23 @@ state: restarted daemon_reload: yes name: "zookeeper" - - command: > - bin/pulsar initialize-cluster-metadata --cluster local - --zookeeper localhost:2181 - --configuration-store localhost:2181 - --web-service-url {{ httpUrl }} - --broker-service-url {{ serviceUrl }} - args: - chdir: /opt/pulsar - when: groups['zookeeper'][0] == inventory_hostname - name: BookKeeper setup hosts: pulsar connection: ssh become: true - vars: - skip_journal: false tasks: + - command: > + bin/pulsar initialize-cluster-metadata --cluster local + --zookeeper {{ hostvars[groups['zookeeper'][0]].private_ip }}:2181 + --configuration-store {{ hostvars[groups['zookeeper'][0]].private_ip }}:2181 + --web-service-url {{ httpUrl }} + --broker-service-url {{ serviceUrl }} + args: + chdir: /opt/pulsar + when: groups['pulsar'][0] == inventory_hostname + - set_fact: + skip_journal: "{{ skip_journal | default(false) }}" - name: Apply BookKeeper configuration file [Bypass Journal] template: src: "templates/bookkeeper-skip-journal.conf" @@ -220,6 +289,32 @@ - template: src: "templates/pulsar.service" dest: "/etc/systemd/system/pulsar.service" +# - template: +# src: "templates/{{ item.conf }}" +# dest: "/opt/pulsar/conf/{{ item.conf }}" +# loop: "{{ protocol_handlers }}" +# when: protocol_handlers is defined +# - set_fact: +# protocols: "{{ protocols | default([]) + [ item.protocol ]}}" +# loop: "{{ protocol_handlers }}" +# when: protocol_handlers is defined +# - name: Enable protocol handlers +# lineinfile: +# path: /opt/pulsar/conf/broker.conf +# line: "messagingProtocols={{ protocols | join(',') }}" +# when: protocols is defined +# - name: Read configurations of all protocol handlers +# shell: | +# grep -v "^#" "{{ '/opt/pulsar/conf/' + item.conf }}" +# loop: "{{ protocol_handlers }}" +# when: protocol_handlers is defined +# register: conf_files +# - name: Update broker.conf for protocol handlers +# lineinfile: +# path: /opt/pulsar/conf/broker.conf +# line: "{{ item.stdout_lines | join('\n') }}" +# loop: "{{ conf_files.results }}" +# when: conf_files is defined - systemd: state: restarted daemon_reload: yes @@ -321,12 +416,12 @@ lineinfile: dest: /opt/benchmark/bin/benchmark-worker regexp: '^JVM_MEM=' - line: 'JVM_MEM="-Xms100G -Xmx100G -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=12 -XX:ConcGCThreads=12 -XX:+DisableExplicitGC -XX:-ResizePLAB"' + line: 'JVM_MEM="-Xms64G -Xmx64G -XX:+UseZGC"' - name: Configure memory lineinfile: dest: /opt/benchmark/bin/benchmark regexp: '^JVM_MEM=' - line: 'JVM_MEM="-Xmx4G"' + line: 'JVM_MEM="-Xmx16G"' - name: Install benchmark systemd service template: src: "templates/benchmark-worker.service" @@ -343,28 +438,41 @@ tasks: - name: Add Extras Repo shell: yum-config-manager --enable rhui-REGION-rhel-server-extras - - name: Install RPM packages - yum: pkg={{ item }} state=latest - with_items: - - docker - - set_fact: - prometheusVersion: "2.31.1" + when: + - ansible_facts['distribution'] == 'RedHat' + - ansible_facts['distribution_major_version'] | int <= 7 + - name: Docker repo + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: Installing docker + yum: + state: latest + pkg: ['docker-ce'] + - name: Start docker + service: + name: docker + state: started + enabled: yes - file: path=/opt/prometheus state=absent - file: path=/opt/prometheus state=directory - name: Download Prometheus Binary Package unarchive: - src: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheusVersion }}/prometheus-{{ prometheusVersion }}.linux-amd64.tar.gz" - remote_src: yes + src: "{{ prometheus_binary.src }}" + remote_src: "{{ prometheus_binary.remote }}" dest: /opt/prometheus extra_opts: ["--strip-components=1"] - - set_fact: - private_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" - name: Prometheus setup hosts: prometheus connection: ssh become: true tasks: + - file: path=/opt/pulsar state=absent + - file: path=/opt/pulsar state=directory - file: path: "/opt/prometheus/{{ item }}" state: directory diff --git a/driver-pulsar/deploy/ssd/extra_vars.yaml b/driver-pulsar/deploy/ssd/extra_vars.yaml new file mode 100644 index 000000000..6aaa38db9 --- /dev/null +++ b/driver-pulsar/deploy/ssd/extra_vars.yaml @@ -0,0 +1,57 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +pulsar_version: 2.11.0 +node_exporter_version: 1.2.2 +prometheus_version: 2.31.1 + +pulsar_max_heap_memory: 32g +pulsar_max_direct_memory: 32g + +zookeeper_max_heap_memory: 10g +zookeeper_max_direct_memory: 2g + +# Set it with true if you want BookKeeper to skip the journal writes. +skip_journal: false + +# By default, ansible downloads binaries from network. The download URL is determined automatically by the version. +# To specific another URL to download, you should configure `remote` with `yes` and `src` with the new URL. +# To upload local binaries, you should configure `remote` with `no` and `src` with the local path. +#pulsar_binary: +# src: ./apache-pulsar-2.9.1-bin.tar.gz +# remote: no +# +#node_exporter_binary: +# src: ./node_exporter-1.2.2.linux-amd64.tar.gz +# remote: no +# +#prometheus_binary: +# src: ./prometheus-2.31.1.linux-amd64.tar.gz +# remote: no + +# The two disk device paths as BookKeeper journal and storage disks +disk_dev: + - /dev/nvme1n1 + - /dev/nvme2n1 + +# Each item represents a protocol handler. If `local_path` is defined, the NAR file will be uploaded from local path instead of downloading from `url`. +protocol_handlers: + - protocol: kafka + conf: kop.conf + url: https://github.com/streamnative/kop/releases/download/v2.9.2.5/pulsar-protocol-handler-kafka-2.9.2.5.nar + #local_path: ./pulsar-protocol-handler-kafka-2.9.2.5.nar + - protocol: mqtt + conf: mop.conf + url: https://github.com/streamnative/mop/releases/download/v2.9.2.5/pulsar-protocol-handler-mqtt-2.9.2.5.nar + #local_path: ./pulsar-protocol-handler-mqtt-2.9.2.5.nar diff --git a/driver-pulsar/deploy/ssd/provision-pulsar-aws.tf b/driver-pulsar/deploy/ssd/provision-pulsar-aws.tf index 7c54a89bf..34e67700b 100644 --- a/driver-pulsar/deploy/ssd/provision-pulsar-aws.tf +++ b/driver-pulsar/deploy/ssd/provision-pulsar-aws.tf @@ -1,10 +1,14 @@ -provider "aws" { - region = "${var.region}" - version = "3.50" -} - -provider "random" { - version = "3.1" +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 3.0" + } + random = { + source = "hashicorp/random" + version = "3.1" + } + } } variable "public_key_path" { @@ -27,15 +31,13 @@ variable "key_name" { } variable "region" {} - +variable "az" {} variable "ami" {} +variable "instance_types" {} +variable "num_instances" {} -variable "instance_types" { - type = map(string) -} - -variable "num_instances" { - type = map(string) +provider "aws" { + region = var.region } # Create a VPC to launch our instances into @@ -49,26 +51,27 @@ resource "aws_vpc" "benchmark_vpc" { # Create an internet gateway to give our subnet access to the outside world resource "aws_internet_gateway" "pulsar" { - vpc_id = "${aws_vpc.benchmark_vpc.id}" + vpc_id = aws_vpc.benchmark_vpc.id } # Grant the VPC internet access on its main route table resource "aws_route" "internet_access" { - route_table_id = "${aws_vpc.benchmark_vpc.main_route_table_id}" + route_table_id = aws_vpc.benchmark_vpc.main_route_table_id destination_cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.pulsar.id}" + gateway_id = aws_internet_gateway.pulsar.id } # Create a subnet to launch our instances into resource "aws_subnet" "benchmark_subnet" { - vpc_id = "${aws_vpc.benchmark_vpc.id}" + vpc_id = aws_vpc.benchmark_vpc.id cidr_block = "10.0.0.0/24" map_public_ip_on_launch = true + availability_zone = var.az } resource "aws_security_group" "benchmark_security_group" { name = "terraform-pulsar-${random_id.hash.hex}" - vpc_id = "${aws_vpc.benchmark_vpc.id}" + vpc_id = aws_vpc.benchmark_vpc.id # SSH access from anywhere ingress { @@ -115,16 +118,17 @@ resource "aws_security_group" "benchmark_security_group" { resource "aws_key_pair" "auth" { key_name = "${var.key_name}-${random_id.hash.hex}" - public_key = "${file(var.public_key_path)}" + public_key = file(var.public_key_path) } resource "aws_instance" "zookeeper" { - ami = "${var.ami}" - instance_type = "${var.instance_types["zookeeper"]}" - key_name = "${aws_key_pair.auth.id}" - subnet_id = "${aws_subnet.benchmark_subnet.id}" - vpc_security_group_ids = ["${aws_security_group.benchmark_security_group.id}"] - count = "${var.num_instances["zookeeper"]}" + ami = var.ami + instance_type = var.instance_types["zookeeper"] + key_name = aws_key_pair.auth.id + subnet_id = aws_subnet.benchmark_subnet.id + vpc_security_group_ids = [ + aws_security_group.benchmark_security_group.id] + count = var.num_instances["zookeeper"] tags = { Name = "zk-${count.index}" @@ -132,12 +136,13 @@ resource "aws_instance" "zookeeper" { } resource "aws_instance" "pulsar" { - ami = "${var.ami}" - instance_type = "${var.instance_types["pulsar"]}" - key_name = "${aws_key_pair.auth.id}" - subnet_id = "${aws_subnet.benchmark_subnet.id}" - vpc_security_group_ids = ["${aws_security_group.benchmark_security_group.id}"] - count = "${var.num_instances["pulsar"]}" + ami = var.ami + instance_type = var.instance_types["pulsar"] + key_name = aws_key_pair.auth.id + subnet_id = aws_subnet.benchmark_subnet.id + vpc_security_group_ids = [ + aws_security_group.benchmark_security_group.id] + count = var.num_instances["pulsar"] tags = { Name = "pulsar-${count.index}" @@ -145,12 +150,13 @@ resource "aws_instance" "pulsar" { } resource "aws_instance" "client" { - ami = "${var.ami}" - instance_type = "${var.instance_types["client"]}" - key_name = "${aws_key_pair.auth.id}" - subnet_id = "${aws_subnet.benchmark_subnet.id}" - vpc_security_group_ids = ["${aws_security_group.benchmark_security_group.id}"] - count = "${var.num_instances["client"]}" + ami = var.ami + instance_type = var.instance_types["client"] + key_name = aws_key_pair.auth.id + subnet_id = aws_subnet.benchmark_subnet.id + vpc_security_group_ids = [ + aws_security_group.benchmark_security_group.id] + count = var.num_instances["client"] tags = { Name = "pulsar-client-${count.index}" @@ -158,22 +164,51 @@ resource "aws_instance" "client" { } resource "aws_instance" "prometheus" { - ami = "${var.ami}" - instance_type = "${var.instance_types["prometheus"]}" - key_name = "${aws_key_pair.auth.id}" - subnet_id = "${aws_subnet.benchmark_subnet.id}" - vpc_security_group_ids = ["${aws_security_group.benchmark_security_group.id}"] - count = "${var.num_instances["prometheus"]}" + ami = var.ami + instance_type = var.instance_types["prometheus"] + key_name = aws_key_pair.auth.id + subnet_id = aws_subnet.benchmark_subnet.id + vpc_security_group_ids = [ + aws_security_group.benchmark_security_group.id] + count = var.num_instances["prometheus"] tags = { Name = "prometheus-${count.index}" } } +output "zookeeper" { + value = { + for instance in aws_instance.zookeeper : + instance.public_ip => instance.private_ip + } +} + +output "pulsar" { + value = { + for instance in aws_instance.pulsar : + instance.public_ip => instance.private_ip + } +} + +output "client" { + value = { + for instance in aws_instance.client : + instance.public_ip => instance.private_ip + } +} + +output "prometheus" { + value = { + for instance in aws_instance.prometheus : + instance.public_ip => instance.private_ip + } +} + output "client_ssh_host" { - value = "${aws_instance.client.0.public_ip}" + value = aws_instance.client.0.public_ip } output "prometheus_host" { - value = "${aws_instance.prometheus.0.public_ip}" + value = aws_instance.prometheus.0.public_ip } diff --git a/driver-pulsar/deploy/ssd/restart-brokers.yaml b/driver-pulsar/deploy/ssd/restart-brokers.yaml new file mode 100644 index 000000000..0c3bf98c1 --- /dev/null +++ b/driver-pulsar/deploy/ssd/restart-brokers.yaml @@ -0,0 +1,80 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +- name: Initialize variables + hosts: all + connection: ssh + tasks: + - set_fact: + private_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" + zookeeperServers: "{{ groups['zookeeper'] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) | map('regex_replace', '^(.*)$', '\\1:2181') | join(',') }}" + +- name: Restart brokers with new configurations + hosts: pulsar + become: true + tasks: + - set_fact: + max_heap_memory: "{{ pulsar_max_heap_memory | default('16g') }}" + max_direct_memory: "{{ pulsar_max_direct_memory | default('48g') }}" + - systemd: + state: stopped + name: pulsar + - name: Set up pulsar.service + template: + src: templates/pulsar.service + dest: /etc/systemd/system/pulsar.service + - name: Set up pulsar_env.sh + template: + src: templates/pulsar_env.sh + dest: /opt/pulsar/conf/pulsar_env.sh + - name: Set up broker.conf + template: + src: templates/broker.conf + dest: /opt/pulsar/conf/broker.conf + - name: Set up configurations of protocol handlers + template: + src: "templates/{{ item.conf }}" + dest: "/opt/pulsar/conf/{{ item.conf }}" + loop: "{{ protocol_handlers }}" + when: protocol_handlers is defined + - set_fact: + protocols: "{{ protocols | default([]) + [ item.protocol ] }}" + loop: "{{ protocol_handlers }}" + when: protocol_handlers is defined + - name: Enable protocol handlers + lineinfile: + path: /opt/pulsar/conf/broker.conf + line: "messagingProtocols={{ protocols | join(',') }}" + - name: Read configurations of all protocol handlers + shell: | + grep -v "^#" "{{ '/opt/pulsar/conf/' + item.conf }}" + loop: "{{ protocol_handlers }}" + when: protocol_handlers is defined + register: conf_files + - name: Read configurations of all protocol handlers + shell: | + grep -v "^#" "{{ '/opt/pulsar/conf/' + item.conf }}" + loop: "{{ protocol_handlers }}" + when: protocol_handlers is defined + register: conf_files + - name: Update broker.conf for protocol handlers + lineinfile: + path: /opt/pulsar/conf/broker.conf + line: "{{ item.stdout_lines | join('\n') }}" + loop: "{{ conf_files.results }}" + when: conf_files is defined + - systemd: + state: started + daemon_reload: yes + name: pulsar diff --git a/driver-pulsar/deploy/ssd/restart-workers.yaml b/driver-pulsar/deploy/ssd/restart-workers.yaml new file mode 100644 index 000000000..2c1e563b7 --- /dev/null +++ b/driver-pulsar/deploy/ssd/restart-workers.yaml @@ -0,0 +1,24 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +- name: Benchmarking worker restart + hosts: client + connection: ssh + become: true + tasks: + - name: Benchmark - Start service + systemd: + state: restarted + daemon_reload: yes + name: "benchmark-worker" diff --git a/driver-pulsar/deploy/ssd/templates/bkenv.sh b/driver-pulsar/deploy/ssd/templates/bkenv.sh new file mode 100644 index 000000000..ab530c297 --- /dev/null +++ b/driver-pulsar/deploy/ssd/templates/bkenv.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# NOTE: this script is intentionally not executable. It is only meant to be sourced for environment variables. + +# Set JAVA_HOME here to override the environment setting +# JAVA_HOME= + +# default settings for starting bookkeeper + +# Configuration file of settings used in bookie server +BOOKIE_CONF=${BOOKIE_CONF:-"$BK_HOME/conf/bookkeeper.conf"} + +# Log4j configuration file +# BOOKIE_LOG_CONF= + +# Logs location +BOOKIE_LOG_DIR=${BOOKIE_LOG_DIR:-"${PULSAR_LOG_DIR}"} + +# Memory size options +BOOKIE_MEM=${BOOKIE_MEM:-${PULSAR_MEM:-"-Xms{{ max_heap_memory }} -Xmx{{ max_heap_memory }} -XX:MaxDirectMemorySize={{ max_direct_memory }}"}} + +# Garbage collection options +BOOKIE_GC=${BOOKIE_GC:-${PULSAR_GC:-"-XX:+UseZGC -XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch"}} + +if [ -z "$JAVA_HOME" ]; then + JAVA_BIN=java +else + JAVA_BIN="$JAVA_HOME/bin/java" +fi +for token in $("$JAVA_BIN" -version 2>&1 | grep 'version "'); do + if [[ $token =~ \"([[:digit:]]+)\.([[:digit:]]+)(.*)\" ]]; then + if [[ ${BASH_REMATCH[1]} == "1" ]]; then + JAVA_MAJOR_VERSION=${BASH_REMATCH[2]} + else + JAVA_MAJOR_VERSION=${BASH_REMATCH[1]} + fi + break + elif [[ $token =~ \"([[:digit:]]+)(.*)\" ]]; then + # Process the java versions without dots, such as `17-internal`. + JAVA_MAJOR_VERSION=${BASH_REMATCH[1]} + break + fi +done + +if [[ -z "$BOOKIE_GC_LOG" ]]; then + # fallback to PULSAR_GC_LOG if it is set + BOOKIE_GC_LOG="$PULSAR_GC_LOG" +fi + +BOOKIE_GC_LOG_DIR=${BOOKIE_GC_LOG_DIR:-"${PULSAR_GC_LOG_DIR:-"${BOOKIE_LOG_DIR}"}"} + +if [[ -z "$BOOKIE_GC_LOG" ]]; then + if [[ $JAVA_MAJOR_VERSION -gt 8 ]]; then + BOOKIE_GC_LOG="-Xlog:gc*,safepoint:${BOOKIE_GC_LOG_DIR}/pulsar_bookie_gc_%p.log:time,uptime,tags:filecount=10,filesize=20M" + if [[ $JAVA_MAJOR_VERSION -ge 17 ]]; then + # Use async logging on Java 17+ https://bugs.openjdk.java.net/browse/JDK-8264323 + BOOKIE_GC_LOG="-Xlog:async ${BOOKIE_GC_LOG}" + fi + else + # Java 8 gc log options + BOOKIE_GC_LOG="-Xloggc:${BOOKIE_GC_LOG_DIR}/pulsar_bookie_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=20M" + fi +fi + +# Extra options to be passed to the jvm +BOOKIE_EXTRA_OPTS="${BOOKIE_EXTRA_OPTS:-"-Dio.netty.leakDetectionLevel=disabled ${PULSAR_EXTRA_OPTS:-"-Dio.netty.recycler.maxCapacityPerThread=4096"}"}" + +# Add extra paths to the bookkeeper classpath +# BOOKIE_EXTRA_CLASSPATH= + +#Folder where the Bookie server PID file should be stored +#BOOKIE_PID_DIR= + +#Wait time before forcefully kill the Bookie server instance, if the stop is not successful +#BOOKIE_STOP_TIMEOUT= + +#Entry formatter class to format entries. +#ENTRY_FORMATTER_CLASS= \ No newline at end of file diff --git a/driver-pulsar/deploy/ssd/templates/bookkeeper-skip-journal.conf b/driver-pulsar/deploy/ssd/templates/bookkeeper-skip-journal.conf index c86749f89..f09876a65 100644 --- a/driver-pulsar/deploy/ssd/templates/bookkeeper-skip-journal.conf +++ b/driver-pulsar/deploy/ssd/templates/bookkeeper-skip-journal.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-pulsar/deploy/ssd/templates/bookkeeper.conf b/driver-pulsar/deploy/ssd/templates/bookkeeper.conf index 8140634a9..dbd9631e3 100644 --- a/driver-pulsar/deploy/ssd/templates/bookkeeper.conf +++ b/driver-pulsar/deploy/ssd/templates/bookkeeper.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -29,6 +24,13 @@ ledgerDirectories=/mnt/storage/0,/mnt/storage/1 journalSyncData=true journalWriteData=true +# Entry log flush interval in bytes. +# Default is 0. 0 or less disables this feature and effectively flush +# happens on log rotation. +# Flushing in smaller chunks but more frequently reduces spikes in disk +# I/O. Flushing too frequently may also affect performance negatively. +flushEntrylogBytes=67108864 + ## Regular Bookie settings # Port that bookie server listen on diff --git a/driver-pulsar/deploy/ssd/templates/broker.conf b/driver-pulsar/deploy/ssd/templates/broker.conf index be6ca2c9f..bea319ea0 100644 --- a/driver-pulsar/deploy/ssd/templates/broker.conf +++ b/driver-pulsar/deploy/ssd/templates/broker.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,20 +18,23 @@ # Zookeeper quorum connection string zookeeperServers={{ zookeeperServers }} - # Global Zookeeper quorum connection string globalZookeeperServers={{ zookeeperServers }} - # Hostname or IP address the service advertises to the outside world. If not set, the value of InetAddress.getLocalHost().getHostName() is used. advertisedAddress={{ hostvars[inventory_hostname].private_ip }} - # Name of the cluster to which this broker belongs to clusterName=local - loadBalancerAutoUnloadSplitBundlesEnabled=false - defaultNumberOfNamespaceBundles=64 - managedLedgerNewEntriesCheckDelayInMillis=0 - -bookkeeperNumberOfChannelsPerBookie=64 \ No newline at end of file +bookkeeperNumberOfChannelsPerBookie=64 +managedLedgerCacheEvictionFrequency=0.2 +# Increasing from default to avoid throttling lookups +maxConcurrentLookupRequest=500000 +loadBalancerOverrideBrokerNicSpeedGbps=25 +forceDeleteTenantAllowed=true +forceDeleteNamespaceAllowed=true +exposeManagedLedgerMetricsInPrometheus=false +exposeTopicLevelMetricsInPrometheus=false +systemTopicEnabled=false +topicLevelPoliciesEnabled=false diff --git a/driver-pulsar/deploy/ssd/templates/chrony.conf b/driver-pulsar/deploy/ssd/templates/chrony.conf index 0e68c66a5..2ec5485aa 100644 --- a/driver-pulsar/deploy/ssd/templates/chrony.conf +++ b/driver-pulsar/deploy/ssd/templates/chrony.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Use public servers from the pool.ntp.org project. diff --git a/driver-pulsar/deploy/ssd/templates/client.conf b/driver-pulsar/deploy/ssd/templates/client.conf index 81c65772a..a1da5d8a4 100644 --- a/driver-pulsar/deploy/ssd/templates/client.conf +++ b/driver-pulsar/deploy/ssd/templates/client.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-pulsar/deploy/ssd/templates/kop.conf b/driver-pulsar/deploy/ssd/templates/kop.conf new file mode 100644 index 000000000..710593b63 --- /dev/null +++ b/driver-pulsar/deploy/ssd/templates/kop.conf @@ -0,0 +1,19 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +kafkaListeners=PLAINTEXT://{{ hostvars[inventory_hostname].private_ip }}:9092 +kafkaAdvertisedListeners=PLAINTEXT://{{ hostvars[inventory_hostname].private_ip }}:9092 +allowAutoTopicCreationType=partitioned +brokerEntryMetadataInterceptors=org.apache.pulsar.common.intercept.AppendIndexMetadataInterceptor +brokerDeleteInactiveTopicsEnabled=false diff --git a/driver-pulsar/deploy/ssd/templates/mop.conf b/driver-pulsar/deploy/ssd/templates/mop.conf new file mode 100644 index 000000000..8b1470110 --- /dev/null +++ b/driver-pulsar/deploy/ssd/templates/mop.conf @@ -0,0 +1,15 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +mqttListeners=mqtt://{{ hostvars[inventory_hostname].private_ip }}:1883 diff --git a/driver-pulsar/deploy/ssd/templates/prometheus.yml b/driver-pulsar/deploy/ssd/templates/prometheus.yml index 131c23790..a539eba74 100644 --- a/driver-pulsar/deploy/ssd/templates/prometheus.yml +++ b/driver-pulsar/deploy/ssd/templates/prometheus.yml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # --- diff --git a/driver-pulsar/deploy/ssd/templates/pulsar-dashboard.service b/driver-pulsar/deploy/ssd/templates/pulsar-dashboard.service index cd73422e8..a3ee6a0ef 100644 --- a/driver-pulsar/deploy/ssd/templates/pulsar-dashboard.service +++ b/driver-pulsar/deploy/ssd/templates/pulsar-dashboard.service @@ -1,14 +1,12 @@ [Unit] Description=Pulsar Dashboard -After=docker.service -Requires=docker.service After=prometheus.service Requires=prometheus.service [Service] WorkingDirectory=/opt/pulsar ExecStartPre=/usr/bin/docker pull streamnative/apache-pulsar-grafana-dashboard:latest -ExecStart=/usr/bin/docker run --restart=always --name=systemd_pulsar_dashboard -p3000:3000 -e PULSAR_PROMETHEUS_URL=http://{{ hostvars[groups['prometheus'][0]].private_ip }}:9090/ -e PULSAR_CLUSTER=local streamnative/apache-pulsar-grafana-dashboard:0.0.8 +ExecStart=/usr/bin/docker run --restart=always --name=systemd_pulsar_dashboard -p3000:3000 -e PULSAR_PROMETHEUS_URL=http://{{ hostvars[groups['prometheus'][0]].private_ip }}:9090/ -e PULSAR_CLUSTER=local streamnative/apache-pulsar-grafana-dashboard:latest ExecStop=/usr/bin/docker stop systemd_pulsar_dashboard ExecStopPost=/usr/bin/docker rm -f systemd_pulsar_dashboard ExecReload=/usr/bin/docker restart systemd_pulsar_dashboard diff --git a/driver-pulsar/deploy/ssd/templates/pulsar_env.sh b/driver-pulsar/deploy/ssd/templates/pulsar_env.sh index 18eb12cf6..f13d0332c 100644 --- a/driver-pulsar/deploy/ssd/templates/pulsar_env.sh +++ b/driver-pulsar/deploy/ssd/templates/pulsar_env.sh @@ -1,21 +1,16 @@ #!/usr/bin/env bash # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # Set JAVA_HOME here to override the environment setting @@ -42,17 +37,48 @@ # PULSAR_GLOBAL_ZK_CONF= # Extra options to be passed to the jvm -PULSAR_MEM=" -Xms{{ max_heap_memory }} -Xmx{{ max_heap_memory }} -XX:MaxDirectMemorySize={{ max_direct_memory }}" +PULSAR_MEM=${PULSAR_MEM:-" -Xms{{ max_heap_memory }} -Xmx{{ max_heap_memory }} -XX:MaxDirectMemorySize={{ max_direct_memory }}"} # Garbage collection options -PULSAR_GC=" -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=12 -XX:ConcGCThreads=12 -XX:+DisableExplicitGC -XX:-ResizePLAB" -PULSAR_GC="${PULSAR_GC} -XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch -XX:-UseBiasedLocking" +PULSAR_GC=${PULSAR_GC:-"-XX:+UseZGC -XX:+PerfDisableSharedMem -XX:+AlwaysPreTouch"} -# Extra options to be passed to the jvm -PULSAR_EXTRA_OPTS="${PULSAR_EXTRA_OPTS} ${PULSAR_MEM} ${PULSAR_GC} -Dio.netty.leakDetectionLevel=disabled -Dio.netty.recycler.maxCapacity.default=1000 -Dio.netty.recycler.linkCapacity=1024" +if [ -z "$JAVA_HOME" ]; then + JAVA_BIN=java +else + JAVA_BIN="$JAVA_HOME/bin/java" +fi +for token in $("$JAVA_BIN" -version 2>&1 | grep 'version "'); do + if [[ $token =~ \"([[:digit:]]+)\.([[:digit:]]+)(.*)\" ]]; then + if [[ ${BASH_REMATCH[1]} == "1" ]]; then + JAVA_MAJOR_VERSION=${BASH_REMATCH[2]} + else + JAVA_MAJOR_VERSION=${BASH_REMATCH[1]} + fi + break + elif [[ $token =~ \"([[:digit:]]+)(.*)\" ]]; then + # Process the java versions without dots, such as `17-internal`. + JAVA_MAJOR_VERSION=${BASH_REMATCH[1]} + break + fi +done + +PULSAR_GC_LOG_DIR=${PULSAR_GC_LOG_DIR:-"${PULSAR_LOG_DIR}"} -# Extra options to be passed to the BookKeeper JVM -BOOKIE_EXTRA_OPTS="${PULSAR_EXTRA_OPTS} ${PULSAR_MEM} ${PULSAR_GC} -Dio.netty.leakDetectionLevel=disabled -Dio.netty.recycler.maxCapacity.default=1000 -Dio.netty.recycler.linkCapacity=1024" +if [[ -z "$PULSAR_GC_LOG" ]]; then + if [[ $JAVA_MAJOR_VERSION -gt 8 ]]; then + PULSAR_GC_LOG="-Xlog:gc*,safepoint:${PULSAR_GC_LOG_DIR}/pulsar_gc_%p.log:time,uptime,tags:filecount=10,filesize=20M" + if [[ $JAVA_MAJOR_VERSION -ge 17 ]]; then + # Use async logging on Java 17+ https://bugs.openjdk.java.net/browse/JDK-8264323 + PULSAR_GC_LOG="-Xlog:async ${PULSAR_GC_LOG}" + fi + else + # Java 8 gc log options + PULSAR_GC_LOG="-Xloggc:${PULSAR_GC_LOG_DIR}/pulsar_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=20M" + fi +fi + +# Extra options to be passed to the jvm +PULSAR_EXTRA_OPTS="${PULSAR_EXTRA_OPTS:-" -Dpulsar.allocator.exit_on_oom=true -Dio.netty.recycler.maxCapacityPerThread=4096"}" # Add extra paths to the bookkeeper classpath # PULSAR_EXTRA_CLASSPATH= @@ -60,5 +86,5 @@ BOOKIE_EXTRA_OPTS="${PULSAR_EXTRA_OPTS} ${PULSAR_MEM} ${PULSAR_GC} -Dio.netty.le #Folder where the Bookie server PID file should be stored #PULSAR_PID_DIR= -#Wait time before forcefully kill the pulser server instance, if the stop is not successful +#Wait time before forcefully kill the pulsar server instance, if the stop is not successful #PULSAR_STOP_TIMEOUT= diff --git a/driver-pulsar/deploy/ssd/templates/workers.yaml b/driver-pulsar/deploy/ssd/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-pulsar/deploy/ssd/templates/workers.yaml +++ b/driver-pulsar/deploy/ssd/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-pulsar/deploy/ssd/templates/zoo.cfg b/driver-pulsar/deploy/ssd/templates/zoo.cfg index b33cad819..56097ca6a 100644 --- a/driver-pulsar/deploy/ssd/templates/zoo.cfg +++ b/driver-pulsar/deploy/ssd/templates/zoo.cfg @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # # The number of milliseconds of each tick @@ -26,7 +21,8 @@ initLimit=10 # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. -dataDir=data/zookeeper +dataLogDir=/mnt/zookeeper/logs +dataDir=/mnt/zookeeper/data # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. @@ -43,7 +39,8 @@ autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature autopurge.purgeInterval=1 - +metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider +metricsProvider.httpPort=8000 {% for zk in groups['zookeeper'] %} server.{{ hostvars[zk].zid }}={{ hostvars[zk].private_ip }}:2888:3888 {% endfor %} diff --git a/driver-pulsar/deploy/ssd/terraform.tfvars b/driver-pulsar/deploy/ssd/terraform.tfvars index 6da7404a6..7164caa2d 100644 --- a/driver-pulsar/deploy/ssd/terraform.tfvars +++ b/driver-pulsar/deploy/ssd/terraform.tfvars @@ -1,17 +1,18 @@ public_key_path = "~/.ssh/pulsar_aws.pub" region = "us-west-2" -ami = "ami-9fa343e7" // RHEL-7.4 +az = "us-west-2a" +ami = "ami-08970fb2e5767e3b8" // RHEL-8 instance_types = { - "pulsar" = "i3en.6xlarge" - "zookeeper" = "t2.small" - "client" = "m5n.8xlarge" - "prometheus" = "t2.large" + "pulsar" = "i3en.6xlarge" + "zookeeper" = "i3en.2xlarge" + "client" = "m5n.8xlarge" + "prometheus" = "t2.large" } num_instances = { - "client" = 4 - "pulsar" = 3 - "zookeeper" = 3 - "prometheus" = 1 + "client" = 4 + "pulsar" = 5 + "zookeeper" = 3 + "prometheus" = 1 } diff --git a/driver-pulsar/pom.xml b/driver-pulsar/pom.xml index 5a0939551..5032b74f8 100644 --- a/driver-pulsar/pom.xml +++ b/driver-pulsar/pom.xml @@ -1,54 +1,47 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + - driver-pulsar - - 2.8.1 - + driver-pulsar + + 2.11.0 + - - - ${project.groupId} - driver-api - ${project.version} - - - - org.apache.pulsar - pulsar-client-all - ${pulsar.version} - - - - com.google.guava - guava - - + + + ${project.groupId} + driver-api + ${project.version} + + + com.google.guava + guava + + + org.apache.pulsar + pulsar-client-all + ${pulsar.version} + + diff --git a/driver-pulsar/pulsar-effectively-once.yaml b/driver-pulsar/pulsar-effectively-once.yaml index c89a93138..ec3e8e07e 100644 --- a/driver-pulsar/pulsar-effectively-once.yaml +++ b/driver-pulsar/pulsar-effectively-once.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Pulsar-effectively-once diff --git a/driver-pulsar/pulsar.yaml b/driver-pulsar/pulsar.yaml index 25846a091..bbb46a996 100644 --- a/driver-pulsar/pulsar.yaml +++ b/driver-pulsar/pulsar.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Pulsar @@ -50,4 +45,5 @@ producer: pendingQueueSize: 0 consumer: - receiverQueueSize: 10000 \ No newline at end of file + receiverQueueSize: 10000 + subscriptionType: Failover diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkConsumer.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkConsumer.java index 19421393b..064cf8e98 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkConsumer.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkConsumer.java @@ -1,23 +1,20 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar; +import static java.util.Collections.unmodifiableList; + import io.openmessaging.benchmark.driver.BenchmarkConsumer; import java.nio.ByteBuffer; import java.util.List; @@ -28,7 +25,7 @@ public class PulsarBenchmarkConsumer implements BenchmarkConsumer { private final List> consumer; public PulsarBenchmarkConsumer(List> consumer) { - this.consumer = consumer; + this.consumer = unmodifiableList(consumer); } @Override diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkDriver.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkDriver.java index 82d966c1e..f65fe4f48 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkDriver.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkDriver.java @@ -1,24 +1,31 @@ - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.google.common.collect.Sets; +import com.google.common.io.BaseEncoding; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.pulsar.config.PulsarClientConfig.PersistenceConfiguration; +import io.openmessaging.benchmark.driver.pulsar.config.PulsarConfig; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; @@ -28,7 +35,6 @@ import java.util.Random; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; - import java.util.stream.Collectors; import org.apache.bookkeeper.stats.StatsLogger; import org.apache.pulsar.client.admin.PulsarAdmin; @@ -41,7 +47,6 @@ import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.Schema; import org.apache.pulsar.client.api.SizeUnit; -import org.apache.pulsar.client.api.SubscriptionType; import org.apache.pulsar.common.policies.data.BacklogQuota; import org.apache.pulsar.common.policies.data.BacklogQuota.RetentionPolicy; import org.apache.pulsar.common.policies.data.PersistencePolicies; @@ -50,20 +55,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectWriter; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import com.google.common.collect.Sets; -import com.google.common.io.BaseEncoding; - -import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import io.openmessaging.benchmark.driver.BenchmarkDriver; -import io.openmessaging.benchmark.driver.BenchmarkProducer; -import io.openmessaging.benchmark.driver.ConsumerCallback; -import io.openmessaging.benchmark.driver.pulsar.config.PulsarClientConfig.PersistenceConfiguration; -import io.openmessaging.benchmark.driver.pulsar.config.PulsarConfig; - public class PulsarBenchmarkDriver implements BenchmarkDriver { private PulsarClient client; @@ -71,8 +62,6 @@ public class PulsarBenchmarkDriver implements BenchmarkDriver { private PulsarConfig config; - - private String namespace; private ProducerBuilder producerBuilder; @@ -81,32 +70,40 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I this.config = readConfig(configurationFile); log.info("Pulsar driver configuration: {}", writer.writeValueAsString(config)); - ClientBuilder clientBuilder = PulsarClient.builder() - .ioThreads(config.client.ioThreads) - .connectionsPerBroker(config.client.connectionsPerBroker) - .statsInterval(0, TimeUnit.SECONDS) - .serviceUrl(config.client.serviceUrl) - .maxConcurrentLookupRequests(50000) - .maxLookupRequests(100000) - .memoryLimit(config.client.clientMemoryLimitMB, SizeUnit.MEGA_BYTES) - .listenerThreads(Runtime.getRuntime().availableProcessors()); + ClientBuilder clientBuilder = + PulsarClient.builder() + .ioThreads(config.client.ioThreads) + .connectionsPerBroker(config.client.connectionsPerBroker) + .statsInterval(0, TimeUnit.SECONDS) + .serviceUrl(config.client.serviceUrl) + .maxConcurrentLookupRequests(config.client.maxConcurrentLookupRequests) + .maxLookupRequests(Integer.MAX_VALUE) + .memoryLimit(config.client.clientMemoryLimitMB, SizeUnit.MEGA_BYTES) + .operationTimeout(10, TimeUnit.MINUTES) + .listenerThreads(Runtime.getRuntime().availableProcessors()); if (config.client.serviceUrl.startsWith("pulsar+ssl")) { - clientBuilder.allowTlsInsecureConnection(config.client.tlsAllowInsecureConnection) - .enableTlsHostnameVerification(config.client.tlsEnableHostnameVerification) - .tlsTrustCertsFilePath(config.client.tlsTrustCertsFilePath); + clientBuilder + .allowTlsInsecureConnection(config.client.tlsAllowInsecureConnection) + .enableTlsHostnameVerification(config.client.tlsEnableHostnameVerification) + .tlsTrustCertsFilePath(config.client.tlsTrustCertsFilePath); } - PulsarAdminBuilder pulsarAdminBuilder = PulsarAdmin.builder().serviceHttpUrl(config.client.httpUrl); + PulsarAdminBuilder pulsarAdminBuilder = + PulsarAdmin.builder().serviceHttpUrl(config.client.httpUrl); if (config.client.httpUrl.startsWith("https")) { - pulsarAdminBuilder.allowTlsInsecureConnection(config.client.tlsAllowInsecureConnection) - .enableTlsHostnameVerification(config.client.tlsEnableHostnameVerification) - .tlsTrustCertsFilePath(config.client.tlsTrustCertsFilePath); + pulsarAdminBuilder + .allowTlsInsecureConnection(config.client.tlsAllowInsecureConnection) + .enableTlsHostnameVerification(config.client.tlsEnableHostnameVerification) + .tlsTrustCertsFilePath(config.client.tlsTrustCertsFilePath); } - if (config.client.authentication.plugin != null && !config.client.authentication.plugin.isEmpty()) { - clientBuilder.authentication(config.client.authentication.plugin, config.client.authentication.data); - pulsarAdminBuilder.authentication(config.client.authentication.plugin, config.client.authentication.data); + if (config.client.authentication.plugin != null + && !config.client.authentication.plugin.isEmpty()) { + clientBuilder.authentication( + config.client.authentication.plugin, config.client.authentication.data); + pulsarAdminBuilder.authentication( + config.client.authentication.plugin, config.client.authentication.data); } client = clientBuilder.build(); @@ -117,14 +114,17 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I log.info("Created Pulsar admin client for HTTP URL {}", config.client.httpUrl); - producerBuilder = client.newProducer() - .enableBatching(config.producer.batchingEnabled) - .batchingMaxPublishDelay(config.producer.batchingMaxPublishDelayMs, TimeUnit.MILLISECONDS) - .batchingMaxMessages(Integer.MAX_VALUE) - .batchingMaxBytes(config.producer.batchingMaxBytes) - .blockIfQueueFull(config.producer.blockIfQueueFull) - .sendTimeout(0, TimeUnit.MILLISECONDS) - .maxPendingMessages(config.producer.pendingQueueSize); + producerBuilder = + client + .newProducer() + .enableBatching(config.producer.batchingEnabled) + .batchingMaxPublishDelay( + config.producer.batchingMaxPublishDelayMs, TimeUnit.MILLISECONDS) + .batchingMaxMessages(Integer.MAX_VALUE) + .batchingMaxBytes(config.producer.batchingMaxBytes) + .blockIfQueueFull(config.producer.blockIfQueueFull) + .sendTimeout(0, TimeUnit.MILLISECONDS) + .maxPendingMessages(config.producer.pendingQueueSize); try { // Create namespace and set the configuration @@ -132,8 +132,14 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I String cluster = config.client.clusterName; if (!adminClient.tenants().getTenants().contains(tenant)) { try { - adminClient.tenants().createTenant(tenant, - TenantInfo.builder().adminRoles(Collections.emptySet()).allowedClusters(Sets.newHashSet(cluster)).build()); + adminClient + .tenants() + .createTenant( + tenant, + TenantInfo.builder() + .adminRoles(Collections.emptySet()) + .allowedClusters(Sets.newHashSet(cluster)) + .build()); } catch (ConflictException e) { // Ignore. This can happen when multiple workers are initializing at the same time } @@ -145,18 +151,27 @@ public void initialize(File configurationFile, StatsLogger statsLogger) throws I log.info("Created Pulsar namespace {}", namespace); PersistenceConfiguration p = config.client.persistence; - adminClient.namespaces().setPersistence(namespace, - new PersistencePolicies(p.ensembleSize, p.writeQuorum, p.ackQuorum, 1.0)); - - adminClient.namespaces().setBacklogQuota(namespace, - BacklogQuota.builder() - .limitSize(-1L) - .limitTime(-1) - .retentionPolicy(RetentionPolicy.producer_exception) - .build()); + adminClient + .namespaces() + .setPersistence( + namespace, new PersistencePolicies(p.ensembleSize, p.writeQuorum, p.ackQuorum, 1.0)); + + adminClient + .namespaces() + .setBacklogQuota( + namespace, + BacklogQuota.builder() + .limitSize(-1L) + .limitTime(-1) + .retentionPolicy(RetentionPolicy.producer_exception) + .build()); adminClient.namespaces().setDeduplicationStatus(namespace, p.deduplicationEnabled); - log.info("Applied persistence configuration for namespace {}/{}/{}: {}", tenant, cluster, namespace, - writer.writeValueAsString(p)); + log.info( + "Applied persistence configuration for namespace {}/{}/{}: {}", + tenant, + cluster, + namespace, + writer.writeValueAsString(p)); } catch (PulsarAdminException e) { throw new IOException(e); @@ -180,37 +195,42 @@ public CompletableFuture createTopic(String topic, int partitions) { @Override public CompletableFuture createProducer(String topic) { - return producerBuilder.topic(topic).createAsync() - .thenApply(PulsarBenchmarkProducer::new); + return producerBuilder.topic(topic).createAsync().thenApply(PulsarBenchmarkProducer::new); } @Override - public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { List>> futures = new ArrayList<>(); - return client.getPartitionsForTopic(topic) - .thenCompose(partitions -> { - partitions.forEach(p -> futures.add(createInternalConsumer(p, subscriptionName, consumerCallback))); - return FutureUtil.waitForAll(futures); - }).thenApply(__ -> new PulsarBenchmarkConsumer( - futures.stream().map(CompletableFuture::join).collect(Collectors.toList()) - ) - ); + return client + .getPartitionsForTopic(topic) + .thenCompose( + partitions -> { + partitions.forEach( + p -> futures.add(createInternalConsumer(p, subscriptionName, consumerCallback))); + return FutureUtil.waitForAll(futures); + }) + .thenApply( + __ -> + new PulsarBenchmarkConsumer( + futures.stream().map(CompletableFuture::join).collect(Collectors.toList()))); } - CompletableFuture> createInternalConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { - return client.newConsumer(Schema.BYTEBUFFER) + CompletableFuture> createInternalConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { + return client + .newConsumer(Schema.BYTEBUFFER) .priorityLevel(0) - .subscriptionType(SubscriptionType.Failover) - .messageListener((c, msg) -> { - try { - consumerCallback.messageReceived(msg.getValue(), msg.getPublishTime()); - c.acknowledgeAsync(msg); - } finally { - msg.release(); - } - }) + .subscriptionType(config.consumer.subscriptionType) + .messageListener( + (c, msg) -> { + try { + consumerCallback.messageReceived(msg.getValue(), msg.getPublishTime()); + c.acknowledgeAsync(msg); + } finally { + msg.release(); + } + }) .topic(topic) .subscriptionName(subscriptionName) .receiverQueueSize(config.consumer.receiverQueueSize) @@ -234,7 +254,8 @@ public void close() throws Exception { log.info("Pulsar benchmark driver successfully shut down"); } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static PulsarConfig readConfig(File configurationFile) throws IOException { @@ -243,7 +264,7 @@ private static PulsarConfig readConfig(File configurationFile) throws IOExceptio private static final Random random = new Random(); - private static final String getRandomString() { + private static String getRandomString() { byte[] buffer = new byte[5]; random.nextBytes(buffer); return BaseEncoding.base64Url().omitPadding().encode(buffer); diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkProducer.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkProducer.java index 475511c26..80adb2add 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkProducer.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/PulsarBenchmarkProducer.java @@ -1,31 +1,25 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.Optional; import java.util.concurrent.CompletableFuture; - import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.TypedMessageBuilder; -import io.openmessaging.benchmark.driver.BenchmarkProducer; - public class PulsarBenchmarkProducer implements BenchmarkProducer { private final Producer producer; @@ -48,5 +42,4 @@ public CompletableFuture sendAsync(Optional key, byte[] payload) { return msgBuilder.sendAsync().thenApply(msgId -> null); } - } diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarClientConfig.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarClientConfig.java index 04c828fd5..0dedaa5d2 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarClientConfig.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarClientConfig.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar.config; + import org.apache.pulsar.common.naming.TopicDomain; public class PulsarClientConfig { @@ -31,6 +27,8 @@ public class PulsarClientConfig { public int connectionsPerBroker = 8; + public int maxConcurrentLookupRequests = 1000; + public String namespacePrefix; public String clusterName; diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConfig.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConfig.java index e9ffb50d3..8bcb24622 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConfig.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar.config; diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConsumerConfig.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConsumerConfig.java index 0cac20559..d3ac54902 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConsumerConfig.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarConsumerConfig.java @@ -1,24 +1,23 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar.config; + +import org.apache.pulsar.client.api.SubscriptionType; + public class PulsarConsumerConfig { public int receiverQueueSize = 10000; + public SubscriptionType subscriptionType = SubscriptionType.Failover; } diff --git a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarProducerConfig.java b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarProducerConfig.java index 73b015d0d..0cfa555f4 100644 --- a/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarProducerConfig.java +++ b/driver-pulsar/src/main/java/io/openmessaging/benchmark/driver/pulsar/config/PulsarProducerConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.pulsar.config; diff --git a/driver-rabbitmq/README.md b/driver-rabbitmq/README.md index b1bbc0ca9..9b2731784 100644 --- a/driver-rabbitmq/README.md +++ b/driver-rabbitmq/README.md @@ -12,7 +12,7 @@ This folder houses all of the assets necessary to run benchmarks for [RabbitMQ]( In order to create the local artifacts necessary to run the RabbitMQ benchmarks in AWS, you'll need to have [Maven](https://maven.apache.org/install.html) installed. Once Maven's installed, you can create the necessary artifacts with a single Maven command: ```bash -$ git clone https://github.com/streamlio/messaging-benchmark +$ git clone https://github.com/openmessaging/benchmark.git % cd messaging-benchmark $ mvn install ``` @@ -53,10 +53,11 @@ $ terraform apply That will install the following [EC2](https://aws.amazon.com/ec2) instances (plus some other resources, such as a [Virtual Private Cloud](https://aws.amazon.com/vpc/) (VPC)): -Resource | Description | Count -:--------|:------------|:----- -RabbitMQ instances | The VMs on which RabbitMQ brokers will run | 3 -Client instance | The VM from which the benchmarking suite itself will be run | 1 +| Resource | Description | Count | +|:--------------------|:------------------------------------------------------------|:------| +| RabbitMQ instances | The VMs on which RabbitMQ brokers will run | 3 | +| Client instance | The VM from which the benchmarking suite itself will be run | 1 | +| Prometheus instance | The VM on which metrics services will be run | 1 | When you run `terraform apply`, you will be prompted to type `yes`. Type `yes` to continue with the installation or anything else to quit. @@ -66,21 +67,23 @@ Once the installation is complete, you will see a confirmation message listing t There's a handful of configurable parameters related to the Terraform deployment that you can alter by modifying the defaults in the `terraform.tfvars` file. -Variable | Description | Default -:--------|:------------|:------- -`region` | The AWS region in which the RabbitMQ cluster will be deployed | `us-west-2` -`public_key_path` | The path to the SSH public key that you've generated | `~/.ssh/rabbitmq_aws.pub` -`ami` | The [Amazon Machine Image](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) (AWI) to be used by the cluster's machines | [`ami-9fa343e7`](https://access.redhat.com/articles/3135091) -`instance_types` | The EC2 instance types used by the various components | `i3.4xlarge` (RabbitMQ brokers), `c4.8xlarge` (benchmarking client) +| Variable | Description | Default | +|:------------------|:------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------| +| `region` | The AWS region in which the RabbitMQ cluster will be deployed | `us-west-2` | +| `az` | The availability zone in which the RabbitMQ cluster will be deployed | `us-west-2a` | +| `public_key_path` | The path to the SSH public key that you've generated | `~/.ssh/rabbitmq_aws.pub` | +| `ami` | The [Amazon Machine Image](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) (AWI) to be used by the cluster's machines | [`ami-9fa343e7`](https://access.redhat.com/articles/3135091) | +| `instance_types` | The EC2 instance types used by the various components | `i3.4xlarge` (RabbitMQ brokers), `c4.8xlarge` (benchmarking client) | > If you modify the `public_key_path`, make sure that you point to the appropriate SSH key path when running the [Ansible playbook](#running-the-ansible-playbook). ### Running the Ansible playbook -With the appropriate infrastructure in place, you can install and start the RabbitMQ cluster using Ansible with just one command: +With the appropriate infrastructure in place, you can install and start the RabbitMQ cluster using Ansible with just one command. +Note that a `TFSTATE` environment must point to the folder in which the `tf.state` file is located. ```bash -$ ansible-playbook \ +$ TF_STATE=. ansible-playbook \ --user ec2-user \ --inventory `which terraform-inventory` \ deploy.yaml @@ -102,11 +105,37 @@ Once you've successfully SSHed into the client host, you can run all [available ```bash $ cd /opt/benchmark -$ sudo bin/benchmark --drivers driver-rabbitmq/rabbitmq.yaml workloads/*.yaml +$ sudo bin/benchmark --drivers driver-rabbitmq/rabbitmq-classic.yaml workloads/*.yaml ``` You can also run specific workloads in the `workloads` folder. Here's an example: ```bash -$ sudo bin/benchmark --drivers driver-rabbotmq/rabbitmq.yaml workloads/1-topic-16-partitions-1kb.yaml -``` \ No newline at end of file +$ sudo bin/benchmark --drivers driver-rabbotmq/rabbitmq-classic.yaml workloads/1-topic-1-partitions-1kb.yaml +``` + +## Monitoring + +### Native + +The `rabbitmq_management` plugin is installed, and the HTTP endpoint is **publicly** exposed on all RabbitMQ instances +on port `15672`. This allows access to the management UI which provides some basic status metrics. It should also be +possible to access the management REST API at this endpoint. + +Note that the connection is authenticated but not currently encrypted and so passwords will be passed in plain text. Use +the `admin` account configured in the [Terraform](deploy/provision-rabbitmq-aws.tf) file to log in. + +### Prometheus + +The `rabbitmq_prometheus` plugin is installed and Prometheus is installed on a standalone instance, along with +[Node Exporter](https://github.com/prometheus/node_exporter) on all brokers to allow the collection of system metrics. +Prometheus exposes a public endpoint `http://${prometheus_host}:9090`. See +'[RabbitMQ.com — Monitoring with Prometheus & Grafana](https://www.rabbitmq.com/prometheus.html)' for more information. + +### Grafana + +Grafana and a set of standard dashboards are installed alongside Prometheus. These are exposed on a public endpoint +`http://${prometheus_host}:3000`. Credentials are `admin`/`admin`. Dashboards included: +* [RabbitMQ's standard dashboards](https://grafana.com/rabbitmq) +* [Node Exporter dashboard](https://grafana.com/grafana/dashboards/1860-node-exporter-full/) + diff --git a/driver-rabbitmq/deploy/alicloud/deploy.yaml b/driver-rabbitmq/deploy/alicloud/deploy.yaml index a4b13405a..994f8e1e1 100644 --- a/driver-rabbitmq/deploy/alicloud/deploy.yaml +++ b/driver-rabbitmq/deploy/alicloud/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Prepare variable @@ -202,7 +197,7 @@ mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT /opt/benchmark - name: Configure service URL lineinfile: - dest: /opt/benchmark/driver-rabbitmq/rabbitmq.yaml + dest: /opt/benchmark/driver-rabbitmq/rabbitmq-classic.yaml regexp: '^brokerAddress\: ' line: 'brokerAddress: rabbitmaster' - template: diff --git a/driver-rabbitmq/deploy/deploy-client-jars.yaml b/driver-rabbitmq/deploy/deploy-client-jars.yaml new file mode 100644 index 000000000..d210cba01 --- /dev/null +++ b/driver-rabbitmq/deploy/deploy-client-jars.yaml @@ -0,0 +1,30 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +- name: Deploy benchmark + hosts: client + connection: ssh + become: true + tasks: + - shell: rm -fr /opt/openmessaging-benchmark-0.0.1-SNAPSHOT + - shell: rm -f /opt/benchmark/lib/io.openmessaging.* + - unarchive: + src: ../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz + dest: /opt + - shell: cp -f /opt/openmessaging-benchmark-0.0.1-SNAPSHOT/lib/io.openmessaging.* /opt/benchmark/lib/ + - name: Benchmark - Start service + systemd: + state: restarted + daemon_reload: yes + name: "benchmark-worker" diff --git a/driver-rabbitmq/deploy/deploy.yaml b/driver-rabbitmq/deploy/deploy.yaml index 37fae4cfd..cc5909b7d 100644 --- a/driver-rabbitmq/deploy/deploy.yaml +++ b/driver-rabbitmq/deploy/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Format and mount disks for RabbitMQ hosts @@ -22,13 +17,13 @@ connection: ssh become: true tasks: - - name: Format disks + - name: RabbitMQ - Format disks filesystem: fstype: xfs dev: '{{ item }}' with_items: - '/dev/nvme1n1' - - name: Mount disks + - name: RabbitMQ - Mount disks mount: path: "{{ item.path }}" src: "{{ item.src }}" @@ -37,7 +32,7 @@ state: mounted with_items: - { path: "/mnt/data", src: "/dev/nvme1n1" } - - name: Set permissions + - name: RabbitMQ - Set filesystem permissions file: path: "/mnt/data" state: touch @@ -47,90 +42,112 @@ hosts: rabbitmq connection: ssh tasks: - - set_fact: - erlangVersion: 23.3.4.10 - rabbitMqVersion: 3.9.11 - - name: Install RPM packages + - name: RabbitMQ - Set software versions + set_fact: + erlangVersion: 24.3.4.5 + rabbitMqVersion: 3.10.7 + - name: RabbitMQ - Install RPM packages yum: pkg={{ item }} state=latest with_items: - wget - sysstat - vim - socat - - name: Install Erlang + - name: RabbitMQ - Install Erlang yum: - name: https://github.com/rabbitmq/erlang-rpm/releases/download/v{{ erlangVersion }}/erlang-{{ erlangVersion }}-1.el7.x86_64.rpm + name: https://github.com/rabbitmq/erlang-rpm/releases/download/v{{ erlangVersion }}/erlang-{{ erlangVersion }}-1.el8.x86_64.rpm state: present - - name: Install Rabbitmq Server + disable_gpg_check: yes + - name: RabbitMQ - Install RabbitMQ Server yum: - name: https://github.com/rabbitmq/rabbitmq-server/releases/download/v{{ rabbitMqVersion }}/rabbitmq-server-{{ rabbitMqVersion }}-1.el7.noarch.rpm + name: https://github.com/rabbitmq/rabbitmq-server/releases/download/v{{ rabbitMqVersion }}/rabbitmq-server-{{ rabbitMqVersion }}-1.el8.noarch.rpm state: present + disable_gpg_check: yes - - name: Create rabbitmq-env.conf file + - name: RabbitMQ - Create rabbitmq.conf file + template: + src: "templates/rabbitmq.conf" + dest: "/etc/rabbitmq/rabbitmq.conf" + + - name: RabbitMQ - Create rabbitmq-env.conf file template: src: "templates/rabbitmq-env.conf" dest: "/etc/rabbitmq/rabbitmq-env.conf" - - systemd: + - name: RabbitMQ - Start standalone + systemd: state: started daemon_reload: yes name: "rabbitmq-server" - - name: Install web management + - name: RabbitMQ - Install web management plugin shell: rabbitmq-plugins enable rabbitmq_management - systemd: state: restarted daemon_reload: yes name: "rabbitmq-server" + - name: RabbitMQ - Install Prometheus monitoring plugin + shell: rabbitmq-plugins enable rabbitmq_prometheus + - name: RabbitMQ - Restart standalone + systemd: + state: restarted + daemon_reload: yes + name: "rabbitmq-server" - - name: Clear servers' Erlang cookie + - name: RabbitMQ - Clear Erlang cookie file: path: /var/lib/rabbitmq/.erlang.cookie state: absent - - name: Copy Erlang cookie + - name: RabbitMQ - Copy Erlang cookie copy: src=erlang.cookie dest=/var/lib/rabbitmq/.erlang.cookie owner=rabbitmq group=rabbitmq mode=0400 - - systemd: + - name: RabbitMQ - Restart standalone + systemd: state: restarted daemon_reload: yes name: "rabbitmq-server" + tags: [restart-rabbitmq] - - name: RabbitMQ status + - name: RabbitMQ - Check cluster status shell: rabbitmqctl cluster_status register: result - debug: msg: '{{ result.stdout }}' - - name: Rabbit cluster stop slaves + - name: RabbitMQ - Stop cluster followers shell: rabbitmqctl stop_app when: inventory_hostname != hostvars[groups['rabbitmq'][0]].inventory_hostname - - name: Rabbit cluster slaves join master + - name: RabbitMQ - Join followers to leader shell: rabbitmqctl join_cluster rabbit@{{ hostvars[groups['rabbitmq'][0]].private_ip }} when: inventory_hostname != hostvars[groups['rabbitmq'][0]].inventory_hostname - - name: Start RabbitMQ cluster slaves + - name: RabbitMQ - Set cluster name + shell: rabbitmqctl set_cluster_name benchmark_rabbitmq + when: inventory_hostname == hostvars[groups['rabbitmq'][0]].inventory_hostname + + - name: RabbitMQ - Start cluster followers shell: rabbitmqctl start_app when: inventory_hostname != hostvars[groups['rabbitmq'][0]].inventory_hostname - - name: Show RabbitMQ cluster status + - name: RabbitMQ - Show cluster status shell: rabbitmqctl cluster_status register: result - debug: msg: '{{ result.stdout }}' - - name: create admin/admin profile + - name: RabbitMQ - Create admin/admin profile shell: rabbitmqctl add_user admin admin when: inventory_hostname == hostvars[groups['rabbitmq'][0]].inventory_hostname - - name: set admin tag + - name: RabbitMQ - Set admin tag shell: rabbitmqctl set_user_tags admin administrator when: inventory_hostname == hostvars[groups['rabbitmq'][0]].inventory_hostname - - name: set admin permission + - name: RabbitMQ - Set admin permission shell: rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*" when: inventory_hostname == hostvars[groups['rabbitmq'][0]].inventory_hostname - - name: Create high availability policy + - name: RabbitMQ - Create high availability policy shell: rabbitmqctl set_policy ha-all "^" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}' when: inventory_hostname == hostvars[groups['rabbitmq'][0]].inventory_hostname @@ -139,21 +156,204 @@ connection: ssh become: true tasks: - - name: Set up chronyd + - name: Chrony - Configure template: src: "templates/chrony.conf" dest: "/etc/chrony.conf" - - systemd: + - name: Chrony - Restart + systemd: state: restarted daemon_reload: yes name: "chronyd" -- name: Rabbitmq benchmarking client setup +- name: Install RabbitMQ Prometheus node exporters + hosts: rabbitmq + connection: ssh + become: true + tasks: + - name: NodeExporter - Set software versions + set_fact: + nodeExporterVersion: 1.2.2 + - name: NodeExporter - Set binary source URL + set_fact: + nodeExporterBinary: + src: "https://github.com/prometheus/node_exporter/releases/download/v{{ nodeExporterVersion }}/node_exporter-{{ nodeExporterVersion }}.linux-amd64.tar.gz" + remote: yes + when: nodeExporterBinary is not defined + - name: NodeExporter - Add node_exporter user + user: + name: node_exporter + shell: /bin/false + system: true + create_home: no + - name: NodeExporter - Download and extract + unarchive: + src: "{{ nodeExporterBinary.src }}" + dest: /tmp + remote_src: "{{ nodeExporterBinary.remote }}" + - name: NodeExporter - Install binary + copy: + src: "/tmp/node_exporter-{{ nodeExporterVersion }}.linux-amd64/node_exporter" + remote_src: yes + dest: /usr/local/bin/ + owner: node_exporter + group: node_exporter + mode: u+x,g+x,o+x + - name: NodeExporter - Create service + blockinfile: + path: /etc/systemd/system/node_exporter.service + block: | + [Unit] + Description=Prometheus Node Exporter + Wants=network-online.target + After=network-online.target + [Service] + User=node_exporter + Group=node_exporter + Type=simple + ExecStart=/usr/local/bin/node_exporter + [Install] + WantedBy=multi-user.target + create: true + - name: NodeExporter - Reload daemon configuration + systemd: + daemon_reload: yes + - name: NodeExporter - Start and enable service + service: + name: node_exporter + state: started + enabled: yes + - name: NodeExporter - Check port 9100 availability + wait_for: + port: 9100 + state: started + timeout: 5 + + +- name: Prometheus installation + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Prometheus - Set software versions + set_fact: + prometheusVersion: 2.31.1 + - name: Prometheus - Set binary source URL + set_fact: + prometheusBinary: + src: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheusVersion }}/prometheus-{{ prometheusVersion }}.linux-amd64.tar.gz" + remote: yes + - name: Prometheus - Add RHEL yum repo + shell: yum-config-manager --enable rhui-REGION-rhel-server-extras + when: + - ansible_facts['distribution'] == 'RedHat' + - ansible_facts['distribution_major_version'] | int <= 7 + - name: Prometheus - Create install folders + file: path=/opt/prometheus/data state=absent + - file: path=/opt/prometheus/data state=directory + - name: Prometheus - Download and unarchive binary + unarchive: + src: "{{ prometheusBinary.src }}" + remote_src: "{{ prometheusBinary.remote }}" + dest: /opt/prometheus + extra_opts: ["--strip-components=1"] + +- name: Prometheus setup + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Prometheus - Configure systemd + template: + src: "templates/prometheus.service" + dest: "/etc/systemd/system/prometheus.service" + - name: Prometheus - Configure service + template: + src: "templates/prometheus.yml" + dest: "/opt/prometheus/prometheus.yml" + - name: Prometheus - Restart service + systemd: + state: restarted + daemon_reload: yes + name: "prometheus" + +- name: Grafana installation + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Grafana - Configure yum Docker repo + yum_repository: + name: docker + description: repo for docker + baseurl: "https://download.docker.com/linux/centos/{{ ansible_facts['distribution_major_version'] }}/x86_64/stable/" + gpgcheck: no + when: ansible_facts['distribution'] == 'RedHat' + - name: Grafana - Install Docker + yum: + state: latest + pkg: ['docker-ce'] + - name: Grafana - Start docker + service: + name: docker + state: started + enabled: yes + - name: Grafana - Create install folders + file: path=/opt/grafana state=absent + - file: path=/opt/grafana state=directory + - file: path=/repos/rabbitmq-server state=absent + - file: path=/repos/rabbitmq-server state=directory + - file: path=/repos/grafana-dashboard state=absent + - file: path=/repos/grafana-dashboard state=directory + - name: Grafana - Install Git RPM packages + yum: pkg={{ item }} state=latest + with_items: + - git + - name: Grafana - Clone RabbitMQ repository + git: + repo: https://github.com/rabbitmq/rabbitmq-server.git + dest: /repos/rabbitmq-server + clone: yes + update: yes + - name: Grafana - Clone rfmoz/grafana-dashboard repository + git: + repo: https://github.com/rfmoz/grafana-dashboards.git + dest: /repos/grafana-dashboard + clone: yes + update: yes + - name: Grafana - Copy node_exporter dashboard + copy: remote_src=True src=/repos/grafana-dashboard/prometheus/node-exporter-full.json dest=/repos/rabbitmq-server/deps/rabbitmq_prometheus/docker/grafana/dashboards/ + +- name: Grafana setup + hosts: prometheus + connection: ssh + become: true + tasks: + - name: Grafana - Create data folders + file: path=/opt/rabbitmq state=absent + - file: path=/opt/rabbitmq state=directory + - name: Grafana - Configure Prometheus datasource + template: + src: "templates/grafana-datasource.yml" + dest: "/opt/rabbitmq/grafana-datasource.yml" + - name: Grafana - Configure systemd + template: + src: "templates/rabbitmq-dashboard.service" + dest: "/etc/systemd/system/rabbitmq-dashboard.service" + - name: Grafana - Restart Grafana + systemd: + state: restarted + daemon_reload: yes + name: "rabbitmq-dashboard.service" + +- name: RabbitMQ benchmarking client setup hosts: client connection: ssh become: true tasks: - - name: Install RPM packages + - name: Benchmark - Tune kernel + shell: tuned-adm profile latency-performance + - name: Benchmark - Install RPM packages yum: pkg={{ item }} state=latest with_items: - wget @@ -161,41 +361,55 @@ - java-11-openjdk-devel - sysstat - vim - - name: Copy benchmark code + - name: Benchmark - Clean folder + file: path=/opt/benchmark state=absent + tags: [client-code] + - name: Benchmark - Copy and unpack unarchive: src: ../../package/target/openmessaging-benchmark-0.0.1-SNAPSHOT-bin.tar.gz dest: /opt - - shell: > - tuned-adm profile latency-performance && - mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT /opt/benchmark - - - template: + tags: [client-code] + - name: Benchmark - Install binary + shell: mv /opt/openmessaging-benchmark-0.0.1-SNAPSHOT /opt/benchmark + tags: [client-code] + - name: Benchmark - Configure worker + template: src: "templates/workers.yaml" dest: "/opt/benchmark/workers.yaml" - - - name: Configure service URL - lineinfile: - dest: /opt/benchmark/driver-rabbitmq/rabbitmq.yaml - regexp: '^brokerAddress\: ' - line: "brokerAddress: {{ hostvars[groups['rabbitmq'][0]].private_ip }}" - - name: Configure benchmark-worker memory + tags: [client-code] + - name: Benchmark - Configure classic driver + template: + src: "templates/rabbitmq-classic.yaml" + dest: "/opt/benchmark/driver-rabbitmq/rabbitmq-classic.yaml" + tags: [client-code] + - name: Benchmark - Configure quorum driver + template: + src: "templates/rabbitmq-quorum.yaml" + dest: "/opt/benchmark/driver-rabbitmq/rabbitmq-quorum.yaml" + tags: [client-code] + - name: Benchmark - Configure worker JVM memory lineinfile: dest: /opt/benchmark/bin/benchmark-worker regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xms100G -Xmx100G -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:ParallelGCThreads=12 -XX:ConcGCThreads=12 -XX:+DisableExplicitGC -XX:-ResizePLAB"' - - name: Configure benchmark memory + tags: [client-code] + - name: Benchmark - Configure client JVM memory lineinfile: dest: /opt/benchmark/bin/benchmark regexp: '^JVM_MEM=' line: 'JVM_MEM="-Xmx4G"' - - name: Install benchmark-worker systemd service + tags: [client-code] + - name: Benchmark - Install systemd service template: src: "templates/benchmark-worker.service" dest: "/etc/systemd/system/benchmark-worker.service" - - systemd: + tags: [client-code] + - name: Benchmark - Start worker + systemd: state: restarted daemon_reload: yes name: "benchmark-worker" + tags: [client-code] - name: List host addresses hosts: localhost @@ -207,4 +421,6 @@ - debug: msg: "Benchmark client {{ item }}" with_items: "{{ groups['client'] }}" - + - debug: + msg: "Prometheus servers {{ item }}" + with_items: "{{ groups['prometheus'] }}" diff --git a/driver-rabbitmq/deploy/provision-rabbitmq-aws.tf b/driver-rabbitmq/deploy/provision-rabbitmq-aws.tf index 08dce56cc..49fa67342 100644 --- a/driver-rabbitmq/deploy/provision-rabbitmq-aws.tf +++ b/driver-rabbitmq/deploy/provision-rabbitmq-aws.tf @@ -1,3 +1,14 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + } + random = { + source = "hashicorp/random" + } + } +} + variable "public_key_path" { description = <` with the right cluster name. E.g. + # + # cluster: test-cluster + cluster: local + +# Load and evaluate rules in these files every 'evaluation_interval' seconds. +# rule_files: + +scrape_configs: + + - job_name: "broker" + honor_labels: true # don't overwrite job & instance labels + static_configs: + - targets: +{% for broker in groups['rabbitmq'] %} + - {{ hostvars[broker].private_ip }}:15692 +{% endfor %} + + - job_name: "node_metrics" + honor_labels: true # don't overwrite job & instance labels + static_configs: + - targets: +{% for broker in groups['rabbitmq'] %} + - {{ hostvars[broker].private_ip }}:9100 +{% endfor %} \ No newline at end of file diff --git a/driver-rabbitmq/deploy/templates/rabbitmq-classic.yaml b/driver-rabbitmq/deploy/templates/rabbitmq-classic.yaml new file mode 100644 index 000000000..cd5be803e --- /dev/null +++ b/driver-rabbitmq/deploy/templates/rabbitmq-classic.yaml @@ -0,0 +1,26 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +name: RabbitMQ +driverClass: io.openmessaging.benchmark.driver.rabbitmq.RabbitMqBenchmarkDriver + +# RabbitMq client specific configurations + +amqpUris: +{% for pulsar in groups['rabbitmq'] %} + - amqp://admin:admin@{{ hostvars[pulsar].private_ip }}:5672 +{% endfor %} +messagePersistence: true +queueType: CLASSIC diff --git a/driver-rabbitmq/deploy/templates/rabbitmq-dashboard.service b/driver-rabbitmq/deploy/templates/rabbitmq-dashboard.service new file mode 100644 index 000000000..a22de7045 --- /dev/null +++ b/driver-rabbitmq/deploy/templates/rabbitmq-dashboard.service @@ -0,0 +1,23 @@ +[Unit] +Description=Pulsar Dashboard +After=prometheus.service +Requires=prometheus.service + +[Service] +WorkingDirectory=/opt/grafana +ExecStartPre=/usr/bin/docker pull grafana/grafana:8.3.4 +ExecStart=/usr/bin/docker run \ + --restart=always \ + --name=systemd_rabbitmq_dashboard \ + -p3000:3000 \ + -e GF_INSTALL_PLUGINS="flant-statusmap-panel,grafana-piechart-panel" \ + -v /opt/rabbitmq/grafana-datasource.yml:/etc/grafana/provisioning/datasources/prometheus.yaml \ + -v /repos/rabbitmq-server/deps/rabbitmq_prometheus/docker/grafana/dashboards.yml:/etc/grafana/provisioning/dashboards/rabbitmq.yaml \ + -v /repos/rabbitmq-server/deps/rabbitmq_prometheus/docker/grafana/dashboards:/dashboards \ + grafana/grafana:8.3.4 +ExecStop=/usr/bin/docker stop systemd_rabbitmq_dashboard +ExecStopPost=/usr/bin/docker rm -f systemd_rabbitmq_dashboard +ExecReload=/usr/bin/docker restart systemd_rabbitmq_dashboard + +[Install] +WantedBy=multi-user.target diff --git a/driver-rabbitmq/deploy/templates/rabbitmq-env.conf b/driver-rabbitmq/deploy/templates/rabbitmq-env.conf index e34b66033..443cf7f97 100644 --- a/driver-rabbitmq/deploy/templates/rabbitmq-env.conf +++ b/driver-rabbitmq/deploy/templates/rabbitmq-env.conf @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # MNESIA_BASE=/mnt/data diff --git a/driver-rabbitmq/deploy/templates/rabbitmq-quorum.yaml b/driver-rabbitmq/deploy/templates/rabbitmq-quorum.yaml new file mode 100644 index 000000000..121bfcc0d --- /dev/null +++ b/driver-rabbitmq/deploy/templates/rabbitmq-quorum.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +name: RabbitMQ +driverClass: io.openmessaging.benchmark.driver.rabbitmq.RabbitMqBenchmarkDriver + +# RabbitMq client specific configurations + +# RMQ struggles to create more than 10 quroum queues at a time, so we batch with a delay +producerCreationDelay: 100 +producerCreationBatchSize: 5 +consumerCreationDelay: 100 +consumerCreationBatchSize: 5 + +amqpUris: +{% for pulsar in groups['rabbitmq'] %} + - amqp://admin:admin@{{ hostvars[pulsar].private_ip }}:5672 +{% endfor %} + +# messagePersistence setting is ignored in the quorum implementation +queueType: QUORUM diff --git a/driver-rabbitmq/deploy/templates/rabbitmq.conf b/driver-rabbitmq/deploy/templates/rabbitmq.conf new file mode 100644 index 000000000..c8541df14 --- /dev/null +++ b/driver-rabbitmq/deploy/templates/rabbitmq.conf @@ -0,0 +1,17 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +## Pauses all nodes on the minority side of a partition. The cluster +## MUST have an odd number of nodes (3, 5, etc) +cluster_partition_handling = pause_minority diff --git a/driver-rabbitmq/deploy/templates/workers.yaml b/driver-rabbitmq/deploy/templates/workers.yaml index c9ef4e456..1415c4807 100644 --- a/driver-rabbitmq/deploy/templates/workers.yaml +++ b/driver-rabbitmq/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-rabbitmq/deploy/terraform.tfvars b/driver-rabbitmq/deploy/terraform.tfvars index 273acd4d1..edacce0de 100644 --- a/driver-rabbitmq/deploy/terraform.tfvars +++ b/driver-rabbitmq/deploy/terraform.tfvars @@ -1,13 +1,16 @@ public_key_path = "~/.ssh/rabbitmq_aws.pub" region = "us-west-2" -ami = "ami-9fa343e7" // RHEL-7.4 +az = "us-west-2a" +ami = "ami-08970fb2e5767e3b8" // RHEL-8 instance_types = { - "rabbitmq" = "i3en.6xlarge" - "client" = "m5n.8xlarge" + "rabbitmq" = "i3en.6xlarge" + "client" = "m5n.8xlarge" + "prometheus" = "t2.large" } num_instances = { - "rabbitmq" = 3 - "client" = 4 -} \ No newline at end of file + "rabbitmq" = 3 + "client" = 4 + "prometheus" = 1 +} diff --git a/driver-rabbitmq/pom.xml b/driver-rabbitmq/pom.xml index 5685e0d4a..6d1001bdf 100644 --- a/driver-rabbitmq/pom.xml +++ b/driver-rabbitmq/pom.xml @@ -1,44 +1,51 @@ + - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - - driver-rabbitmq + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + driver-rabbitmq - - - ${project.groupId} - driver-api - ${project.version} - - - - com.rabbitmq - amqp-client - 4.8.0 - - - \ No newline at end of file + + + ${project.groupId} + driver-api + ${project.version} + + + com.rabbitmq + amqp-client + 5.18.0 + + + io.netty + netty-all + + + org.assertj + assertj-core + + + org.junit.jupiter + junit-jupiter + + + diff --git a/driver-rabbitmq/rabbitmq.yaml b/driver-rabbitmq/rabbitmq.yaml index 7ba41ff65..1132a559c 100644 --- a/driver-rabbitmq/rabbitmq.yaml +++ b/driver-rabbitmq/rabbitmq.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # @@ -23,5 +18,12 @@ driverClass: io.openmessaging.benchmark.driver.rabbitmq.RabbitMqBenchmarkDriver # RabbitMq client specific configurations -brokerAddress: localhost -messagePersistence: false \ No newline at end of file +producerCreationDelay: 100 +producerCreationBatchSize: 5 +consumerCreationDelay: 100 +consumerCreationBatchSize: 5 + +amqpUris: + - amqp://localhost +messagePersistence: false +queueType: QUORUM diff --git a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkConsumer.java b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkConsumer.java index 95f8d32ec..27f87d36e 100644 --- a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkConsumer.java +++ b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkConsumer.java @@ -1,39 +1,39 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rabbitmq; -import java.io.IOException; import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; - import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.ConsumerCallback; +import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RabbitMqBenchmarkConsumer extends DefaultConsumer implements BenchmarkConsumer { + private static final Logger log = LoggerFactory.getLogger(RabbitMqBenchmarkConsumer.class); + private final Channel channel; private final ConsumerCallback callback; - public RabbitMqBenchmarkConsumer(Channel channel, String queueName, ConsumerCallback callback) throws IOException { + public RabbitMqBenchmarkConsumer(Channel channel, String queueName, ConsumerCallback callback) + throws IOException { super(channel); this.channel = channel; @@ -42,16 +42,17 @@ public RabbitMqBenchmarkConsumer(Channel channel, String queueName, ConsumerCall } @Override - public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) - throws IOException { + public void handleDelivery( + String consumerTag, Envelope envelope, BasicProperties properties, byte[] body) { callback.messageReceived(body, properties.getTimestamp().getTime()); } @Override public void close() throws Exception { - if (this.channel.isOpen()) { - this.channel.close(); + try { + channel.close(); + } catch (AlreadyClosedException e) { + log.warn("Channel already closed", e); } } - } diff --git a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkDriver.java b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkDriver.java index 5f9913da2..5d639b545 100644 --- a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkDriver.java +++ b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkDriver.java @@ -1,78 +1,93 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rabbitmq; -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.TimeoutException; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.rabbitmq.client.Address; +import com.rabbitmq.client.AlreadyClosedException; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; - +import io.netty.handler.codec.http.QueryStringDecoder; import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.BenchmarkDriver; import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.ResourceCreator; +import io.openmessaging.benchmark.driver.ResourceCreator.CreationResult; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; import org.apache.bookkeeper.stats.StatsLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RabbitMqBenchmarkDriver implements BenchmarkDriver { private RabbitMqConfig config; + private final AtomicInteger uriIndex = new AtomicInteger(); + /** + * Map of client's primary broker to the connection -- the connection may still be able to fall + * back to secondary brokers. + */ + private final Map connections = new ConcurrentHashMap<>(); - private Connection connection; @Override public void initialize(File configurationFile, StatsLogger statsLogger) throws IOException { config = mapper.readValue(configurationFile, RabbitMqConfig.class); - - ConnectionFactory connectionFactory = new ConnectionFactory(); - connectionFactory.setAutomaticRecoveryEnabled(true); - connectionFactory.setHost(config.brokerAddress); - connectionFactory.setUsername("admin"); - connectionFactory.setPassword("admin"); - - try { - connection = connectionFactory.newConnection(); - } catch (TimeoutException e) { - e.printStackTrace(); - } } - - @Override - public void close() throws Exception { - if (connection != null && connection.isOpen()) { - connection.close(); + public void close() { + for (Iterator> it = connections.entrySet().iterator(); + it.hasNext(); ) { + Connection connection = it.next().getValue(); + try { + connection.close(); + } catch (AlreadyClosedException e) { + log.warn("Connection already closed", e); + } catch (Exception e) { + log.error("Couldn't close connection", e); + } + it.remove(); } } @Override public String getTopicNamePrefix() { - return "test-topic"; + // Distribute topics by performing a round-robin on AMQP URIs + String primaryBrokerUri = + config.amqpUris.get(uriIndex.getAndIncrement() % config.amqpUris.size()); + URI configUri = URI.create(primaryBrokerUri); + URI topicUri = configUri.resolve(configUri.getRawPath() + "?exchange=test-exchange"); + return topicUri.toString(); } @Override @@ -89,44 +104,154 @@ public CompletableFuture createTopic(String topic, int partitions) { @Override public CompletableFuture createProducer(String topic) { - Channel channel = null; - try { - channel = connection.createChannel(); - channel.exchangeDeclare(topic, BuiltinExchangeType.FANOUT, true); - channel.confirmSelect(); - } catch (IOException e) { - e.printStackTrace(); - } - return CompletableFuture.completedFuture(new RabbitMqBenchmarkProducer(channel, topic, config.messagePersistence)); + CompletableFuture future = new CompletableFuture<>(); + ForkJoinPool.commonPool() + .execute( + () -> { + try { + String uri = topic.split("\\?")[0]; + Connection connection = getOrCreateConnection(uri); + Channel channel = connection.createChannel(); + String exchange = getExchangeName(topic); + channel.exchangeDeclare(exchange, BuiltinExchangeType.FANOUT, true); + channel.confirmSelect(); + future.complete( + new RabbitMqBenchmarkProducer(channel, exchange, config.messagePersistence)); + } catch (Exception e) { + future.completeExceptionally(e); + } + }); + return future; } @Override - public CompletableFuture createConsumer(String topic, String subscriptionName, - ConsumerCallback consumerCallback) { + public CompletableFuture> createProducers(List producers) { + return new ResourceCreator( + "producer", + config.producerCreationBatchSize, + config.producerCreationDelay, + ps -> ps.stream().collect(toMap(p -> p, p -> createProducer(p.getTopic()))), + fc -> { + try { + return new CreationResult<>(fc.get(), true); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (ExecutionException e) { + log.debug(e.getMessage()); + return new CreationResult<>(null, false); + } + }) + .create(producers); + } + + @Override + public CompletableFuture> createConsumers(List consumers) { + return new ResourceCreator( + "consumer", + config.consumerCreationBatchSize, + config.consumerCreationDelay, + cs -> + cs.stream() + .collect( + toMap( + c -> c, + c -> + createConsumer( + c.getTopic(), + c.getSubscriptionName(), + c.getConsumerCallback()))), + fc -> { + try { + return new CreationResult<>(fc.get(), true); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } catch (ExecutionException e) { + log.debug(e.getMessage()); + return new CreationResult<>(null, false); + } + }) + .create(consumers); + } + + @Override + public CompletableFuture createConsumer( + String topic, String subscriptionName, ConsumerCallback consumerCallback) { CompletableFuture future = new CompletableFuture<>(); - ForkJoinPool.commonPool().execute(() -> { - try { - String queueName = topic + "-" + subscriptionName; - Channel channel = null; - try { - channel = connection.createChannel(); - channel.exchangeDeclare(topic, BuiltinExchangeType.FANOUT, true); - } catch (IOException e) { - e.printStackTrace(); - } - // Create the queue - channel.queueDeclare(queueName, true, false, false, Collections.emptyMap()); - channel.queueBind(queueName, topic, ""); - future.complete(new RabbitMqBenchmarkConsumer(channel, queueName, consumerCallback)); - } catch (IOException e) { - future.completeExceptionally(e); - } - }); + ForkJoinPool.commonPool() + .execute( + () -> { + try { + String uri = topic.split("\\?")[0]; + Connection connection = getOrCreateConnection(uri); + Channel channel = connection.createChannel(); + String exchange = getExchangeName(topic); + String queueName = exchange + "-" + subscriptionName; + channel.exchangeDeclare(exchange, BuiltinExchangeType.FANOUT, true); + // Create the queue + channel.queueDeclare( + queueName, true, false, false, config.queueType.queueOptions()); + channel.queueBind(queueName, exchange, ""); + future.complete( + new RabbitMqBenchmarkConsumer(channel, queueName, consumerCallback)); + } catch (IOException e) { + future.completeExceptionally(e); + } + }); return future; } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private String getExchangeName(String uri) { + QueryStringDecoder decoder = new QueryStringDecoder(uri); + Map> parameters = decoder.parameters(); + + if (!parameters.containsKey("exchange")) { + throw new IllegalArgumentException("Missing exchange param"); + } + return parameters.get("exchange").get(0); + } + + private Connection getOrCreateConnection(String primaryBrokerUri) { + return connections.computeIfAbsent( + primaryBrokerUri, + p -> { + // RabbitMQ will pick the first available address from the list. Future reconnection + // attempts will pick a random accessible address from the provided list. + List

addresses = + Stream.concat(Stream.of(p), config.amqpUris.stream().filter(s -> !s.equals(p))) + .map(s -> newURI(s)) + .map(u -> new Address(u.getHost(), u.getPort())) + .collect(toList()); + try { + ConnectionFactory connectionFactory = new ConnectionFactory(); + connectionFactory.setAutomaticRecoveryEnabled(true); + String userInfo = newURI(primaryBrokerUri).getUserInfo(); + if (userInfo != null) { + String[] userInfoElems = userInfo.split(":"); + connectionFactory.setUsername(userInfoElems[0]); + connectionFactory.setPassword(userInfoElems[1]); + } + return connectionFactory.newConnection(addresses); + } catch (Exception e) { + throw new RuntimeException("Couldn't establish connection to: " + primaryBrokerUri, e); + } + }); + } + + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + private static final Logger log = LoggerFactory.getLogger(RabbitMqBenchmarkDriver.class); + + private static URI newURI(String uri) { + try { + return new URI(uri); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } } diff --git a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkProducer.java b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkProducer.java index ed58966ae..d7d3841ad 100644 --- a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkProducer.java +++ b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqBenchmarkProducer.java @@ -1,24 +1,24 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rabbitmq; + +import com.rabbitmq.client.AMQP.BasicProperties; +import com.rabbitmq.client.AlreadyClosedException; +import com.rabbitmq.client.Channel; import com.rabbitmq.client.ConfirmListener; +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.Collections; import java.util.Date; import java.util.Iterator; @@ -26,87 +26,93 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.CompletableFuture; - -import com.rabbitmq.client.AMQP.BasicProperties; -import com.rabbitmq.client.Channel; - -import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class RabbitMqBenchmarkProducer implements BenchmarkProducer { + private static final Logger log = LoggerFactory.getLogger(RabbitMqBenchmarkProducer.class); + private final Channel channel; private final String exchange; private final ConfirmListener listener; - /**To record msg and it's future structure.**/ + /** To record msg and it's future structure. */ volatile SortedSet ackSet = Collections.synchronizedSortedSet(new TreeSet<>()); - private final ConcurrentHashMap> futureConcurrentHashMap = new ConcurrentHashMap<>(); + + private final ConcurrentHashMap> futureConcurrentHashMap = + new ConcurrentHashMap<>(); private final boolean messagePersistence; public RabbitMqBenchmarkProducer(Channel channel, String exchange, boolean messagePersistence) { this.channel = channel; this.exchange = exchange; this.messagePersistence = messagePersistence; - this.listener = new ConfirmListener() { - @Override - public void handleNack(long deliveryTag, boolean multiple) { - if (multiple) { - SortedSet treeHeadSet = ackSet.headSet(deliveryTag + 1); - synchronized(ackSet) { - for(Iterator iterator = treeHeadSet.iterator(); iterator.hasNext();) { - long value = iterator.next(); - iterator.remove(); - CompletableFuture future = futureConcurrentHashMap.get(value); + this.listener = + new ConfirmListener() { + @Override + public void handleNack(long deliveryTag, boolean multiple) { + if (multiple) { + SortedSet treeHeadSet = ackSet.headSet(deliveryTag + 1); + synchronized (ackSet) { + for (Iterator iterator = treeHeadSet.iterator(); iterator.hasNext(); ) { + long value = iterator.next(); + iterator.remove(); + CompletableFuture future = futureConcurrentHashMap.get(value); + if (future != null) { + future.completeExceptionally( + new RuntimeException("Message was negatively acknowledged")); + futureConcurrentHashMap.remove(value); + } + } + treeHeadSet.clear(); + } + + } else { + CompletableFuture future = futureConcurrentHashMap.get(deliveryTag); if (future != null) { - future.completeExceptionally(new RuntimeException("Message was negatively acknowledged")); - futureConcurrentHashMap.remove(value); + future.completeExceptionally( + new RuntimeException("Message was negatively acknowledged")); + futureConcurrentHashMap.remove(deliveryTag); } + ackSet.remove(deliveryTag); } - treeHeadSet.clear(); } - } else { - CompletableFuture future = futureConcurrentHashMap.get(deliveryTag); - if (future != null) { - future.completeExceptionally(new RuntimeException("Message was negatively acknowledged")); - futureConcurrentHashMap.remove(deliveryTag); - } - ackSet.remove(deliveryTag); - } - } - @Override - public void handleAck(long deliveryTag, boolean multiple) { - if (multiple) { - SortedSet treeHeadSet = ackSet.headSet(deliveryTag + 1); - synchronized(ackSet) { - for(long value : treeHeadSet) { - CompletableFuture future = futureConcurrentHashMap.get(value); + @Override + public void handleAck(long deliveryTag, boolean multiple) { + if (multiple) { + SortedSet treeHeadSet = ackSet.headSet(deliveryTag + 1); + synchronized (ackSet) { + for (long value : treeHeadSet) { + CompletableFuture future = futureConcurrentHashMap.get(value); + if (future != null) { + future.complete(null); + futureConcurrentHashMap.remove(value); + } + } + treeHeadSet.clear(); + } + } else { + CompletableFuture future = futureConcurrentHashMap.get(deliveryTag); if (future != null) { future.complete(null); - futureConcurrentHashMap.remove(value); + futureConcurrentHashMap.remove(deliveryTag); } + ackSet.remove(deliveryTag); } - treeHeadSet.clear(); } - } else { - CompletableFuture future = futureConcurrentHashMap.get(deliveryTag); - if (future != null) { - future.complete(null); - futureConcurrentHashMap.remove(deliveryTag); - } - ackSet.remove(deliveryTag); - } - - } - }; + }; channel.addConfirmListener(listener); } @Override public void close() throws Exception { - if (channel.isOpen()) { + try { channel.removeConfirmListener(listener); channel.close(); + } catch (AlreadyClosedException e) { + log.warn("Channel already closed", e); } } @@ -131,5 +137,4 @@ public CompletableFuture sendAsync(Optional key, byte[] payload) { return future; } - } diff --git a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfig.java b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfig.java index d632ba153..15a67b1bf 100644 --- a/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfig.java +++ b/driver-rabbitmq/src/main/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfig.java @@ -1,24 +1,55 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rabbitmq; +import static io.openmessaging.benchmark.driver.rabbitmq.RabbitMqConfig.QueueType.CLASSIC; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + public class RabbitMqConfig { - public String brokerAddress; + + public List amqpUris = new ArrayList<>(); public boolean messagePersistence = false; + public QueueType queueType = CLASSIC; + public long producerCreationDelay = 100; + public int producerCreationBatchSize = 5; + public long consumerCreationDelay = 100; + public int consumerCreationBatchSize = 5; + + public enum QueueType { + CLASSIC { + @Override + Map queueOptions() { + return Collections.emptyMap(); + } + }, + QUORUM { + @Override + Map queueOptions() { + return Collections.singletonMap("x-queue-type", "quorum"); + } + }, + STREAM { + @Override + Map queueOptions() { + return Collections.singletonMap("x-queue-type", "stream"); + } + }; + + abstract Map queueOptions(); + } } diff --git a/driver-rabbitmq/src/test/java/io/openmessaging/benchmark/driver/rabbitmq/QueueTypeTest.java b/driver-rabbitmq/src/test/java/io/openmessaging/benchmark/driver/rabbitmq/QueueTypeTest.java new file mode 100644 index 000000000..4ff840b60 --- /dev/null +++ b/driver-rabbitmq/src/test/java/io/openmessaging/benchmark/driver/rabbitmq/QueueTypeTest.java @@ -0,0 +1,36 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.rabbitmq; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class QueueTypeTest { + + @Test + public void classic() { + assertThat(RabbitMqConfig.QueueType.CLASSIC.queueOptions()).isEmpty(); + } + + @Test + public void quorum() { + assertThat(RabbitMqConfig.QueueType.QUORUM.queueOptions()) + .satisfies( + o -> { + assertThat(o).containsEntry("x-queue-type", "quorum"); + assertThat(o).hasSize(1); + }); + } +} diff --git a/driver-rabbitmq/src/test/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfigTest.java b/driver-rabbitmq/src/test/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfigTest.java new file mode 100644 index 000000000..925974c4e --- /dev/null +++ b/driver-rabbitmq/src/test/java/io/openmessaging/benchmark/driver/rabbitmq/RabbitMqConfigTest.java @@ -0,0 +1,50 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.rabbitmq; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +class RabbitMqConfigTest { + + @Test + public void deserialize() throws JsonProcessingException { + String config = + "{\"amqpUris\":[\"amqp://local\"],\"messagePersistence\":true,\"queueType\":\"QUORUM\"}"; + RabbitMqConfig value = new ObjectMapper().readValue(config, RabbitMqConfig.class); + assertThat(value) + .satisfies( + v -> { + assertThat(v.amqpUris).containsOnly("amqp://local"); + assertThat(v.messagePersistence).isTrue(); + assertThat(v.queueType).isEqualTo(RabbitMqConfig.QueueType.QUORUM); + }); + } + + @Test + public void deserializeWithDefaults() throws JsonProcessingException { + String config = "{\"amqpUris\":[\"amqp://local\"]}"; + RabbitMqConfig value = new ObjectMapper().readValue(config, RabbitMqConfig.class); + assertThat(value) + .satisfies( + v -> { + assertThat(v.amqpUris).containsOnly("amqp://local"); + assertThat(v.messagePersistence).isFalse(); + assertThat(v.queueType).isEqualTo(RabbitMqConfig.QueueType.CLASSIC); + }); + } +} diff --git a/driver-redis/pom.xml b/driver-redis/pom.xml index 2942da669..32f877b1b 100644 --- a/driver-redis/pom.xml +++ b/driver-redis/pom.xml @@ -1,32 +1,27 @@ + - + 4.0.0 - messaging-benchmark io.openmessaging.benchmark + messaging-benchmark 0.0.1-SNAPSHOT - 4.0.0 driver-redis @@ -36,19 +31,15 @@ driver-api ${project.version} - - - redis.clients - jedis - 3.6.0 - - com.google.guava guava - - + + redis.clients + jedis + 5.0.0 + diff --git a/driver-redis/redis.yaml b/driver-redis/redis.yaml index d63c37960..cca084a40 100644 --- a/driver-redis/redis.yaml +++ b/driver-redis/redis.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Redis diff --git a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkConsumer.java b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkConsumer.java index b3da91975..4e8bb88e8 100644 --- a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkConsumer.java +++ b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkConsumer.java @@ -1,40 +1,35 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.redis; +import static java.nio.charset.StandardCharsets.UTF_8; + import io.openmessaging.benchmark.driver.BenchmarkConsumer; import io.openmessaging.benchmark.driver.ConsumerCallback; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.StreamEntry; -import redis.clients.jedis.StreamEntryID; -import redis.clients.jedis.params.XReadGroupParams; - -import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.StreamEntryID; +import redis.clients.jedis.params.XReadGroupParams; +import redis.clients.jedis.resps.StreamEntry; public class RedisBenchmarkConsumer implements BenchmarkConsumer { private final JedisPool pool; @@ -45,7 +40,12 @@ public class RedisBenchmarkConsumer implements BenchmarkConsumer { private final Future consumerTask; private volatile boolean closing = false; - public RedisBenchmarkConsumer(final String consumerId, final String topic, final String subscriptionName, final JedisPool pool, ConsumerCallback consumerCallback) { + public RedisBenchmarkConsumer( + final String consumerId, + final String topic, + final String subscriptionName, + final JedisPool pool, + ConsumerCallback consumerCallback) { this.pool = pool; this.topic = topic; this.subscriptionName = subscriptionName; @@ -53,31 +53,34 @@ public RedisBenchmarkConsumer(final String consumerId, final String topic, final this.executor = Executors.newSingleThreadExecutor(); Jedis jedis = this.pool.getResource(); + this.consumerTask = + this.executor.submit( + () -> { + while (!closing) { + try { + Map streamQuery = + Collections.singletonMap(this.topic, StreamEntryID.UNRECEIVED_ENTRY); + List>> range = + jedis.xreadGroup( + this.subscriptionName, + this.consumerId, + XReadGroupParams.xReadGroupParams().block(0), + streamQuery); + if (range != null) { + for (Map.Entry> streamEntries : range) { + for (StreamEntry entry : streamEntries.getValue()) { + long timestamp = entry.getID().getTime(); + byte[] payload = entry.getFields().get("payload").getBytes(UTF_8); + consumerCallback.messageReceived(payload, timestamp); + } + } + } - this.consumerTask = this.executor.submit(() -> { - while (!closing) { - try { - Map streamQuery = Collections.singletonMap(this.topic, StreamEntryID.UNRECEIVED_ENTRY); - List>> range = jedis.xreadGroup(this.subscriptionName, this.consumerId, - XReadGroupParams.xReadGroupParams().block(0), streamQuery); - if (range!=null){ - for (Map.Entry> streamEntries: - range) { - for (StreamEntry entry: - streamEntries.getValue()) { - long timestamp = entry.getID().getTime(); - byte[]payload = entry.getFields().get("payload").getBytes(StandardCharsets.UTF_8); - consumerCallback.messageReceived(payload, timestamp); + } catch (Exception e) { + log.error("Failed to read from consumer instance.", e); + } } - } - } - - } catch (Exception e) { - log.error("Failed to read from consumer instance.", e); - } - } - }); - + }); } @Override @@ -87,6 +90,6 @@ public void close() throws Exception { consumerTask.get(); pool.close(); } - private static final Logger log = LoggerFactory.getLogger(RedisBenchmarkDriver.class); + private static final Logger log = LoggerFactory.getLogger(RedisBenchmarkDriver.class); } diff --git a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkDriver.java b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkDriver.java index ed1a28552..d1ef95c3d 100644 --- a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkDriver.java +++ b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkDriver.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.redis; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; @@ -26,25 +22,26 @@ import io.openmessaging.benchmark.driver.BenchmarkDriver; import io.openmessaging.benchmark.driver.BenchmarkProducer; import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.redis.client.RedisClientConfig; import java.io.File; import java.io.IOException; import java.util.Random; import java.util.concurrent.CompletableFuture; import org.apache.bookkeeper.stats.StatsLogger; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.*; -import io.openmessaging.benchmark.driver.redis.client.RedisClientConfig; - +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; public class RedisBenchmarkDriver implements BenchmarkDriver { JedisPool jedisPool; private RedisClientConfig clientConfig; @Override - public void initialize(final File configurationFile, final StatsLogger statsLogger) throws IOException { + public void initialize(final File configurationFile, final StatsLogger statsLogger) + throws IOException { this.clientConfig = readConfig(configurationFile); - } @Override @@ -54,8 +51,7 @@ public String getTopicNamePrefix() { @Override public CompletableFuture createTopic(final String topic, final int partitions) { - return CompletableFuture.runAsync(() -> { - }); + return CompletableFuture.runAsync(() -> {}); } @Override @@ -67,9 +63,9 @@ public CompletableFuture createProducer(final String topic) { } @Override - public CompletableFuture createConsumer(final String topic, final String subscriptionName, - final ConsumerCallback consumerCallback) { - String consumerId = "consumer-"+getRandomString(); + public CompletableFuture createConsumer( + final String topic, final String subscriptionName, final ConsumerCallback consumerCallback) { + String consumerId = "consumer-" + getRandomString(); if (jedisPool == null) { setupJedisConn(); } @@ -78,21 +74,37 @@ public CompletableFuture createConsumer(final String topic, f } catch (Exception e) { log.info("Failed to create consumer instance.", e); } - return CompletableFuture.completedFuture(new RedisBenchmarkConsumer( consumerId, topic, subscriptionName,jedisPool, consumerCallback)); + return CompletableFuture.completedFuture( + new RedisBenchmarkConsumer( + consumerId, topic, subscriptionName, jedisPool, consumerCallback)); } private void setupJedisConn() { - JedisPoolConfig poolConfig = new JedisPoolConfig(); + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxTotal(this.clientConfig.jedisPoolMaxTotal); poolConfig.setMaxIdle(this.clientConfig.jedisPoolMaxIdle); - if( this.clientConfig.redisPass != null ){ - if ( this.clientConfig.redisUser != null){ - jedisPool = new JedisPool(poolConfig, this.clientConfig.redisHost, this.clientConfig.redisPort, 2000, this.clientConfig.redisPass, this.clientConfig.redisUser); + if (this.clientConfig.redisPass != null) { + if (this.clientConfig.redisUser != null) { + jedisPool = + new JedisPool( + poolConfig, + this.clientConfig.redisHost, + this.clientConfig.redisPort, + 2000, + this.clientConfig.redisPass, + this.clientConfig.redisUser); } else { - jedisPool = new JedisPool(poolConfig, this.clientConfig.redisHost, this.clientConfig.redisPort,2000, this.clientConfig.redisPass ); - } + jedisPool = + new JedisPool( + poolConfig, + this.clientConfig.redisHost, + this.clientConfig.redisPort, + 2000, + this.clientConfig.redisPass); + } } else { - jedisPool = new JedisPool(poolConfig, this.clientConfig.redisHost, this.clientConfig.redisPort,2000 ); + jedisPool = + new JedisPool(poolConfig, this.clientConfig.redisHost, this.clientConfig.redisPort, 2000); } } @@ -103,8 +115,9 @@ public void close() throws Exception { } } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static RedisClientConfig readConfig(File configurationFile) throws IOException { return mapper.readValue(configurationFile, RedisClientConfig.class); @@ -112,7 +125,7 @@ private static RedisClientConfig readConfig(File configurationFile) throws IOExc private static final Random random = new Random(); - private static final String getRandomString() { + private static String getRandomString() { byte[] buffer = new byte[5]; random.nextBytes(buffer); return BaseEncoding.base64Url().omitPadding().encode(buffer); diff --git a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkProducer.java b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkProducer.java index d98d664f9..ead1047ac 100644 --- a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkProducer.java +++ b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/RedisBenchmarkProducer.java @@ -1,30 +1,27 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.redis; +import static java.nio.charset.StandardCharsets.UTF_8; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.HashMap; import java.util.Map; - import java.util.Optional; import java.util.concurrent.CompletableFuture; -import io.openmessaging.benchmark.driver.BenchmarkProducer; -import redis.clients.jedis.*; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; import redis.clients.jedis.params.XAddParams; public class RedisBenchmarkProducer implements BenchmarkProducer { @@ -41,19 +38,19 @@ public RedisBenchmarkProducer(final JedisPool pool, final String rmqTopic) { @Override public CompletableFuture sendAsync(final Optional key, final byte[] payload) { Map map1 = new HashMap<>(); - map1.put("payload".getBytes(), payload); + map1.put("payload".getBytes(UTF_8), payload); if (key.isPresent()) { - map1.put("key".getBytes(), key.toString().getBytes()); + map1.put("key".getBytes(UTF_8), key.toString().getBytes(UTF_8)); } CompletableFuture future = new CompletableFuture<>(); - try (Jedis jedis = this.pool.getResource()) { - jedis.xadd(this.rmqTopic.getBytes(),map1, this.xaddParams); - future.complete(null); - } catch (Exception e) { - future.completeExceptionally(e); - } + try (Jedis jedis = this.pool.getResource()) { + jedis.xadd(this.rmqTopic.getBytes(UTF_8), map1, this.xaddParams); + future.complete(null); + } catch (Exception e) { + future.completeExceptionally(e); + } return future; } diff --git a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/client/RedisClientConfig.java b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/client/RedisClientConfig.java index e5e6905c8..899f752ef 100644 --- a/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/client/RedisClientConfig.java +++ b/driver-redis/src/main/java/io/openmessaging/benchmark/driver/redis/client/RedisClientConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.redis.client; diff --git a/driver-rocketmq/deploy/deploy.yaml b/driver-rocketmq/deploy/deploy.yaml index e53594a2b..5278cdca6 100644 --- a/driver-rocketmq/deploy/deploy.yaml +++ b/driver-rocketmq/deploy/deploy.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # - name: Hosts addresses diff --git a/driver-rocketmq/deploy/templates/rmq-broker.properties b/driver-rocketmq/deploy/templates/rmq-broker.properties index 96574aabf..e79bec68b 100644 --- a/driver-rocketmq/deploy/templates/rmq-broker.properties +++ b/driver-rocketmq/deploy/templates/rmq-broker.properties @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # brokerClusterName=DefaultCluster diff --git a/driver-rocketmq/deploy/templates/rmq-namesrv.properties b/driver-rocketmq/deploy/templates/rmq-namesrv.properties index d8a500d9d..3663c15d8 100644 --- a/driver-rocketmq/deploy/templates/rmq-namesrv.properties +++ b/driver-rocketmq/deploy/templates/rmq-namesrv.properties @@ -1,19 +1,14 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-rocketmq/deploy/templates/workers.yaml b/driver-rocketmq/deploy/templates/workers.yaml index 7d3bbe9e0..c0dd19380 100644 --- a/driver-rocketmq/deploy/templates/workers.yaml +++ b/driver-rocketmq/deploy/templates/workers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # diff --git a/driver-rocketmq/pom.xml b/driver-rocketmq/pom.xml index 1e789fdac..3cd0a9139 100644 --- a/driver-rocketmq/pom.xml +++ b/driver-rocketmq/pom.xml @@ -1,51 +1,64 @@ + - + 4.0.0 - messaging-benchmark io.openmessaging.benchmark + messaging-benchmark 0.0.1-SNAPSHOT - 4.0.0 driver-rocketmq + + 5.1.4 + + ${project.groupId} driver-api ${project.version} - + + com.google.guava + guava + + + org.apache.rocketmq + rocketmq-acl + ${rocketmq.version} + org.apache.rocketmq rocketmq-client - 4.3.0 + ${rocketmq.version} org.apache.rocketmq rocketmq-tools - 4.3.0 + ${rocketmq.version} + + + ch.qos.logback + logback-classic + + diff --git a/driver-rocketmq/rocketmq.yaml b/driver-rocketmq/rocketmq.yaml index b30dc4dc0..b9b608088 100644 --- a/driver-rocketmq/rocketmq.yaml +++ b/driver-rocketmq/rocketmq.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: RocketMQ @@ -24,3 +19,15 @@ driverClass: io.openmessaging.benchmark.driver.rocketmq.RocketMQBenchmarkDriver clusterName: DefaultCluster namesrvAddr: 127.0.0.1:9876 vipChannelEnabled: false + +batchCQ: true +autoBatch: true +# batchMaxBytes: 32768 +# batchMaxDelayMs: 10 +# totalBatchMaxBytes: 33554432 + +enableBackpressure: true +backpressureConcurrency: 1024 + +accessKey: +secretKey: \ No newline at end of file diff --git a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkConsumer.java b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkConsumer.java index 5935bef2b..97a7e4912 100644 --- a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkConsumer.java +++ b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkConsumer.java @@ -1,30 +1,26 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rocketmq; + import io.openmessaging.benchmark.driver.BenchmarkConsumer; -import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; +import org.apache.rocketmq.client.consumer.MQPushConsumer; public class RocketMQBenchmarkConsumer implements BenchmarkConsumer { - private final DefaultMQPushConsumer rmqConsumer; + private final MQPushConsumer rmqConsumer; - public RocketMQBenchmarkConsumer(final DefaultMQPushConsumer rmqConsumer) { + public RocketMQBenchmarkConsumer(final MQPushConsumer rmqConsumer) { this.rmqConsumer = rmqConsumer; } diff --git a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkDriver.java b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkDriver.java index ccb1202e8..ccad035fd 100644 --- a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkDriver.java +++ b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkDriver.java @@ -1,23 +1,19 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rocketmq; + import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; @@ -30,18 +26,31 @@ import io.openmessaging.benchmark.driver.rocketmq.client.RocketMQClientConfig; import java.io.File; import java.io.IOException; +import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import org.apache.bookkeeper.stats.StatsLogger; +import org.apache.commons.lang3.StringUtils; +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; +import org.apache.rocketmq.client.consumer.rebalance.AllocateMessageQueueAveragely; +import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.common.TopicAttributes; import org.apache.rocketmq.common.TopicConfig; import org.apache.rocketmq.common.message.MessageExt; +import org.apache.rocketmq.remoting.RPCHook; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; +import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.apache.rocketmq.tools.admin.MQAdminExt; import org.apache.rocketmq.tools.command.CommandUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,11 +59,21 @@ public class RocketMQBenchmarkDriver implements BenchmarkDriver { private DefaultMQAdminExt rmqAdmin; private RocketMQClientConfig rmqClientConfig; DefaultMQProducer rmqProducer; + private RPCHook rpcHook; + @Override - public void initialize(final File configurationFile, final StatsLogger statsLogger) throws IOException { + public void initialize(final File configurationFile, final StatsLogger statsLogger) + throws IOException { this.rmqClientConfig = readConfig(configurationFile); - - this.rmqAdmin = new DefaultMQAdminExt(); + if (isAclEnabled()) { + rpcHook = + new AclClientRPCHook( + new SessionCredentials( + this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey)); + this.rmqAdmin = new DefaultMQAdminExt(rpcHook); + } else { + this.rmqAdmin = new DefaultMQAdminExt(); + } this.rmqAdmin.setNamesrvAddr(this.rmqClientConfig.namesrvAddr); this.rmqAdmin.setInstanceName("AdminInstance-" + getRandomString()); try { @@ -62,7 +81,6 @@ public void initialize(final File configurationFile, final StatsLogger statsLogg } catch (MQClientException e) { log.error("Start the RocketMQ admin tool failed."); } - } @Override @@ -70,45 +88,105 @@ public String getTopicNamePrefix() { return "RocketMQ-Benchmark"; } + Map> cachedBrokerAddr = new ConcurrentHashMap<>(); + + int fetchCnt = 0; + + private synchronized Set fetchMasterAndSlaveAddrByClusterName( + final MQAdminExt adminExt, final String clusterName) + throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, + MQBrokerException, InterruptedException { + Set brokerList = cachedBrokerAddr.get(clusterName); + if (brokerList == null) { + brokerList = + CommandUtil.fetchMasterAndSlaveAddrByClusterName( + adminExt, this.rmqClientConfig.clusterName); + cachedBrokerAddr.put(clusterName, brokerList); + if (brokerList.isEmpty()) { + throw new RuntimeException("get brokerAddr return null, clusterName: " + clusterName); + } + } + if (fetchCnt++ % 100 == 0) { + log.info("fetch brokerAddr count: " + fetchCnt); + } + return brokerList; + } + @Override public CompletableFuture createTopic(final String topic, final int partitions) { - return CompletableFuture.runAsync(() -> { - TopicConfig topicConfig = new TopicConfig(); - topicConfig.setOrder(false); - topicConfig.setPerm(6); - topicConfig.setReadQueueNums(partitions); - topicConfig.setWriteQueueNums(partitions); - topicConfig.setTopicName(topic); + return CompletableFuture.runAsync( + () -> { + TopicConfig topicConfig = new TopicConfig(); + topicConfig.setOrder(false); + topicConfig.setPerm(6); + topicConfig.setReadQueueNums(partitions); + topicConfig.setWriteQueueNums(partitions); + topicConfig.setTopicName(topic); + if (Boolean.TRUE.equals(this.rmqClientConfig.batchCQ)) { + topicConfig + .getAttributes() + .put("+" + TopicAttributes.QUEUE_TYPE_ATTRIBUTE.getName(), "BatchCQ"); + } - try { - Set brokerList = CommandUtil.fetchMasterAddrByClusterName(this.rmqAdmin, this.rmqClientConfig.clusterName); - topicConfig.setReadQueueNums(Math.max(1, partitions / brokerList.size())); - topicConfig.setWriteQueueNums(Math.max(1, partitions / brokerList.size())); - - for (String brokerAddr : brokerList) { - this.rmqAdmin.createAndUpdateTopicConfig(brokerAddr, topicConfig); - } - } catch (Exception e) { - throw new RuntimeException(String.format("Failed to create topic [%s] to cluster [%s]", topic, this.rmqClientConfig.clusterName), e); - } - }); + try { + Set brokerList = + fetchMasterAndSlaveAddrByClusterName( + this.rmqAdmin, this.rmqClientConfig.clusterName); + topicConfig.setReadQueueNums(Math.max(1, partitions / brokerList.size())); + topicConfig.setWriteQueueNums(Math.max(1, partitions / brokerList.size())); + + for (String brokerAddr : brokerList) { + this.rmqAdmin.createAndUpdateTopicConfig(brokerAddr, topicConfig); + } + } catch (Exception e) { + throw new RuntimeException( + String.format( + "Failed to create topic [%s] to cluster [%s]", + topic, this.rmqClientConfig.clusterName), + e); + } + }); } @Override public CompletableFuture createProducer(final String topic) { if (rmqProducer == null) { - rmqProducer = new DefaultMQProducer("ProducerGroup_" + getRandomString()); + if (isAclEnabled()) { + rmqProducer = new DefaultMQProducer("ProducerGroup_" + getRandomString(), rpcHook); + } else { + rmqProducer = new DefaultMQProducer("ProducerGroup_" + getRandomString()); + } rmqProducer.setNamesrvAddr(this.rmqClientConfig.namesrvAddr); rmqProducer.setInstanceName("ProducerInstance" + getRandomString()); - if(null != this.rmqClientConfig.vipChannelEnabled){ + if (null != this.rmqClientConfig.vipChannelEnabled) { rmqProducer.setVipChannelEnabled(this.rmqClientConfig.vipChannelEnabled); } - if(null != this.rmqClientConfig.maxMessageSize){ + if (null != this.rmqClientConfig.maxMessageSize) { rmqProducer.setMaxMessageSize(this.rmqClientConfig.maxMessageSize); } - if(null != this.rmqClientConfig.compressMsgBodyOverHowmuch){ + if (null != this.rmqClientConfig.compressMsgBodyOverHowmuch) { rmqProducer.setCompressMsgBodyOverHowmuch(this.rmqClientConfig.compressMsgBodyOverHowmuch); } + + if (null != this.rmqClientConfig.autoBatch) { + rmqProducer.setAutoBatch(this.rmqClientConfig.autoBatch); + } + if (null != this.rmqClientConfig.batchMaxBytes) { + rmqProducer.batchMaxBytes(this.rmqClientConfig.batchMaxBytes); + } + if (null != this.rmqClientConfig.batchMaxDelayMs) { + rmqProducer.batchMaxDelayMs(this.rmqClientConfig.batchMaxDelayMs); + } + if (null != this.rmqClientConfig.totalBatchMaxBytes) { + rmqProducer.totalBatchMaxBytes(this.rmqClientConfig.totalBatchMaxBytes); + } + if (null != this.rmqClientConfig.enableBackpressure) { + rmqProducer.setEnableBackpressureForAsyncMode(this.rmqClientConfig.enableBackpressure); + } + if (null != this.rmqClientConfig.backpressureConcurrency) { + rmqProducer.setBackPressureForAsyncSendNum(this.rmqClientConfig.backpressureConcurrency); + } + try { rmqProducer.start(); } catch (MQClientException e) { @@ -120,22 +198,30 @@ public CompletableFuture createProducer(final String topic) { } @Override - public CompletableFuture createConsumer(final String topic, final String subscriptionName, - final ConsumerCallback consumerCallback) { - DefaultMQPushConsumer rmqConsumer = new DefaultMQPushConsumer(subscriptionName); + public CompletableFuture createConsumer( + final String topic, final String subscriptionName, final ConsumerCallback consumerCallback) { + DefaultMQPushConsumer rmqConsumer; + if (isAclEnabled()) { + rmqConsumer = + new DefaultMQPushConsumer(subscriptionName, rpcHook, new AllocateMessageQueueAveragely()); + } else { + rmqConsumer = new DefaultMQPushConsumer(subscriptionName); + } rmqConsumer.setNamesrvAddr(this.rmqClientConfig.namesrvAddr); rmqConsumer.setInstanceName("ConsumerInstance" + getRandomString()); - if(null != this.rmqClientConfig.vipChannelEnabled){ + if (null != this.rmqClientConfig.vipChannelEnabled) { rmqConsumer.setVipChannelEnabled(this.rmqClientConfig.vipChannelEnabled); } try { rmqConsumer.subscribe(topic, "*"); - rmqConsumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> { - for (MessageExt message : msgs) { - consumerCallback.messageReceived(message.getBody(), message.getBornTimestamp()); - } - return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; - }); + rmqConsumer.registerMessageListener( + (MessageListenerConcurrently) + (msgs, context) -> { + for (MessageExt message : msgs) { + consumerCallback.messageReceived(message.getBody(), message.getBornTimestamp()); + } + return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; + }); rmqConsumer.start(); } catch (MQClientException e) { log.error("Failed to create consumer instance.", e); @@ -144,6 +230,11 @@ public CompletableFuture createConsumer(final String topic, f return CompletableFuture.completedFuture(new RocketMQBenchmarkConsumer(rmqConsumer)); } + public boolean isAclEnabled() { + return !(StringUtils.isAnyBlank(this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey) + || StringUtils.isAnyEmpty(this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey)); + } + @Override public void close() throws Exception { if (this.rmqProducer != null) { @@ -152,8 +243,9 @@ public void close() throws Exception { this.rmqAdmin.shutdown(); } - private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); private static RocketMQClientConfig readConfig(File configurationFile) throws IOException { return mapper.readValue(configurationFile, RocketMQClientConfig.class); @@ -161,7 +253,7 @@ private static RocketMQClientConfig readConfig(File configurationFile) throws IO private static final Random random = new Random(); - private static final String getRandomString() { + private static String getRandomString() { byte[] buffer = new byte[5]; random.nextBytes(buffer); return BaseEncoding.base64Url().omitPadding().encode(buffer); diff --git a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkProducer.java b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkProducer.java index d1008c30f..bd80bf558 100644 --- a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkProducer.java +++ b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQBenchmarkProducer.java @@ -1,38 +1,32 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rocketmq; + +import io.openmessaging.benchmark.driver.BenchmarkProducer; import java.util.Optional; import java.util.concurrent.CompletableFuture; - -import org.apache.rocketmq.client.producer.DefaultMQProducer; +import org.apache.rocketmq.client.producer.MQProducer; import org.apache.rocketmq.client.producer.SendCallback; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.message.Message; -import io.openmessaging.benchmark.driver.BenchmarkProducer; - public class RocketMQBenchmarkProducer implements BenchmarkProducer { - private final DefaultMQProducer rmqProducer; + private final MQProducer rmqProducer; private final String rmqTopic; - public RocketMQBenchmarkProducer(final DefaultMQProducer rmqProducer, final String rmqTopic) { + public RocketMQBenchmarkProducer(final MQProducer rmqProducer, final String rmqTopic) { this.rmqProducer = rmqProducer; this.rmqTopic = rmqTopic; } @@ -46,17 +40,19 @@ public CompletableFuture sendAsync(final Optional key, final byte[ CompletableFuture future = new CompletableFuture<>(); try { - this.rmqProducer.send(message, new SendCallback() { - @Override - public void onSuccess(final SendResult sendResult) { - future.complete(null); - } + this.rmqProducer.send( + message, + new SendCallback() { + @Override + public void onSuccess(final SendResult sendResult) { + future.complete(null); + } - @Override - public void onException(final Throwable e) { - future.completeExceptionally(e); - } - }); + @Override + public void onException(final Throwable e) { + future.completeExceptionally(e); + } + }); } catch (Exception e) { future.completeExceptionally(e); } diff --git a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClientConfig.java b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClientConfig.java index fbfaa32d2..26cb109bb 100644 --- a/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClientConfig.java +++ b/driver-rocketmq/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClientConfig.java @@ -1,20 +1,15 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package io.openmessaging.benchmark.driver.rocketmq.client; @@ -24,4 +19,14 @@ public class RocketMQClientConfig { public Boolean vipChannelEnabled; public Integer maxMessageSize; public Integer compressMsgBodyOverHowmuch; + public Boolean batchCQ; + public Boolean autoBatch; + public Integer batchMaxBytes; + public Integer batchMaxDelayMs; + public Integer totalBatchMaxBytes; + + public Boolean enableBackpressure; + public Integer backpressureConcurrency; + public String accessKey; + public String secretKey; } diff --git a/driver-rocketmq5/pom.xml b/driver-rocketmq5/pom.xml new file mode 100644 index 000000000..c3de982bf --- /dev/null +++ b/driver-rocketmq5/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + driver-rocketmq5 + + + 5.0.7 + 5.1.0 + 29.0-jre + + + + + ${project.groupId} + driver-api + ${project.version} + + + com.google.guava + guava + ${guava.version} + + + + org.apache.rocketmq + rocketmq-client-java + ${rocketmq-client-java-version} + + + org.apache.rocketmq + rocketmq-tools + ${rocketmq.version} + + + ch.qos.logback + logback-classic + + + + + + diff --git a/driver-rocketmq5/rocketmq.yaml b/driver-rocketmq5/rocketmq.yaml new file mode 100644 index 000000000..cda85a17a --- /dev/null +++ b/driver-rocketmq5/rocketmq.yaml @@ -0,0 +1,32 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: RocketMQ5 +driverClass: io.openmessaging.benchmark.driver.rocketmq.RocketMQ5BenchmarkDriver + +# The RocketMQ nameserver address +namesrvAddr: x.x.x.x:9876 +# The RocketMQ broker cluster name +clusterName: rocketmq-broker-xxxx +# The proxy address to connect for grpc client. +grpcEndpoint: 127.0.0.1:8081 +# 是否生产定时消息,否:生产普通消息,是:生产定时/延时消息且通过delayTimeInSec设置延迟时间 +sendDelayMsg: false +delayTimeInSec: 60 +# (Optional) The admin credential +adminAccessKey: xxxx +adminSecretKey: xxxx +# (Optional) The credential that clients connect to proxy. +accessKey: xxxxxx +secretKey: xxxxx diff --git a/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkConsumer.java b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkConsumer.java new file mode 100644 index 000000000..23d96cb05 --- /dev/null +++ b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkConsumer.java @@ -0,0 +1,31 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.rocketmq; + + +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import org.apache.rocketmq.client.apis.consumer.PushConsumer; + +public class RocketMQ5BenchmarkConsumer implements BenchmarkConsumer { + private final PushConsumer rmqConsumer; + + public RocketMQ5BenchmarkConsumer(final PushConsumer rmqConsumer) { + this.rmqConsumer = rmqConsumer; + } + + @Override + public void close() throws Exception { + this.rmqConsumer.close(); + } +} diff --git a/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkDriver.java b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkDriver.java new file mode 100644 index 000000000..38dc85f23 --- /dev/null +++ b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkDriver.java @@ -0,0 +1,294 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.rocketmq; + + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.google.common.io.BaseEncoding; +import io.openmessaging.benchmark.driver.BenchmarkConsumer; +import io.openmessaging.benchmark.driver.BenchmarkDriver; +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import io.openmessaging.benchmark.driver.ConsumerCallback; +import io.openmessaging.benchmark.driver.rocketmq.client.RocketMQClient5Config; +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.bookkeeper.stats.StatsLogger; +import org.apache.rocketmq.acl.common.AclClientRPCHook; +import org.apache.rocketmq.acl.common.SessionCredentials; +import org.apache.rocketmq.client.apis.ClientConfiguration; +import org.apache.rocketmq.client.apis.ClientConfigurationBuilder; +import org.apache.rocketmq.client.apis.ClientException; +import org.apache.rocketmq.client.apis.ClientServiceProvider; +import org.apache.rocketmq.client.apis.SessionCredentialsProvider; +import org.apache.rocketmq.client.apis.StaticSessionCredentialsProvider; +import org.apache.rocketmq.client.apis.consumer.ConsumeResult; +import org.apache.rocketmq.client.apis.consumer.FilterExpression; +import org.apache.rocketmq.client.apis.consumer.FilterExpressionType; +import org.apache.rocketmq.client.apis.consumer.PushConsumer; +import org.apache.rocketmq.client.apis.producer.Producer; +import org.apache.rocketmq.client.exception.MQBrokerException; +import org.apache.rocketmq.client.exception.MQClientException; +import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.common.attribute.TopicMessageType; +import org.apache.rocketmq.remoting.exception.RemotingConnectException; +import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; +import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; +import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig; +import org.apache.rocketmq.shaded.commons.lang3.StringUtils; +import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; +import org.apache.rocketmq.tools.admin.MQAdminExt; +import org.apache.rocketmq.tools.command.CommandUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RocketMQ5BenchmarkDriver implements BenchmarkDriver { + private RocketMQClient5Config rmqClientConfig; + private DefaultMQAdminExt rmqAdmin; + + @Override + public void initialize(final File configurationFile, final StatsLogger statsLogger) + throws IOException { + this.rmqClientConfig = readConfig(configurationFile); + if (isAdminAclEnabled()) { + AclClientRPCHook rpcHook = + new AclClientRPCHook( + new SessionCredentials( + this.rmqClientConfig.adminAccessKey, this.rmqClientConfig.adminSecretKey)); + this.rmqAdmin = new DefaultMQAdminExt(rpcHook); + } else { + this.rmqAdmin = new DefaultMQAdminExt(); + } + this.rmqAdmin.setNamesrvAddr(this.rmqClientConfig.namesrvAddr); + this.rmqAdmin.setInstanceName("AdminInstance-" + getRandomString()); + try { + this.rmqAdmin.start(); + } catch (MQClientException e) { + log.error("Start the RocketMQ admin tool failed."); + } + } + + Map> cachedBrokerAddr = new ConcurrentHashMap<>(); + + private synchronized Set fetchMasterAndSlaveAddrByClusterName( + final MQAdminExt adminExt, final String clusterName) + throws RemotingConnectException, RemotingSendRequestException, RemotingTimeoutException, + MQBrokerException, InterruptedException { + Set brokerList = cachedBrokerAddr.get(clusterName); + if (brokerList == null) { + brokerList = + CommandUtil.fetchMasterAndSlaveAddrByClusterName( + adminExt, this.rmqClientConfig.clusterName); + cachedBrokerAddr.put(clusterName, brokerList); + if (brokerList.isEmpty()) { + throw new RuntimeException("get brokerAddr return null, clusterName: " + clusterName); + } + } + return brokerList; + } + + @Override + public String getTopicNamePrefix() { + return "Benchmark"; + } + + @Override + public CompletableFuture createTopic(final String topic, final int partitions) { + return CompletableFuture.runAsync( + () -> { + TopicConfig topicConfig = new TopicConfig(); + topicConfig.setOrder(false); + topicConfig.setPerm(6); + topicConfig.setReadQueueNums(partitions); + topicConfig.setWriteQueueNums(partitions); + topicConfig.setTopicName(topic); + Map properties = new HashMap<>(); + String topicType = + rmqClientConfig.sendDelayMsg + ? TopicMessageType.DELAY.getValue() + : TopicMessageType.NORMAL.getValue(); + properties.put("+message.type", topicType); + topicConfig.setAttributes(properties); + + try { + Set brokerList = + fetchMasterAndSlaveAddrByClusterName( + this.rmqAdmin, this.rmqClientConfig.clusterName); + topicConfig.setReadQueueNums(Math.max(1, partitions / brokerList.size())); + topicConfig.setWriteQueueNums(Math.max(1, partitions / brokerList.size())); + + for (String brokerAddr : brokerList) { + this.rmqAdmin.createAndUpdateTopicConfig(brokerAddr, topicConfig); + } + } catch (Exception e) { + throw new RuntimeException( + String.format( + "Failed to create topic [%s] to cluster [%s]", + topic, this.rmqClientConfig.clusterName), + e); + } + }); + } + + @Override + public CompletableFuture createProducer(final String topic) { + + ClientServiceProvider provider = ClientServiceProvider.loadService(); + ClientConfigurationBuilder builder = + ClientConfiguration.newBuilder().setEndpoints(this.rmqClientConfig.grpcEndpoint); + SessionCredentialsProvider sessionCredentialsProvider = + new StaticSessionCredentialsProvider( + this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey); + ClientConfiguration configuration; + if (isAclEnabled()) { + builder.setCredentialProvider(sessionCredentialsProvider); + configuration = builder.build(); + } else { + configuration = builder.build(); + } + + Producer rmqProducer; + try { + rmqProducer = + provider + .newProducerBuilder() + .setTopics(topic) + .setClientConfiguration(configuration) + .build(); + } catch (ClientException e) { + throw new RuntimeException(e); + } + if (this.rmqClientConfig.sendDelayMsg) { + return CompletableFuture.completedFuture( + new RocketMQ5BenchmarkProducer( + rmqProducer, topic, true, this.rmqClientConfig.delayTimeInSec)); + } else { + return CompletableFuture.completedFuture(new RocketMQ5BenchmarkProducer(rmqProducer, topic)); + } + } + + public void createSubscriptionGroup(String fullSubName) { + try { + Set brokerList = + fetchMasterAndSlaveAddrByClusterName(this.rmqAdmin, this.rmqClientConfig.clusterName); + SubscriptionGroupConfig subscriptionGroupConfig = new SubscriptionGroupConfig(); + subscriptionGroupConfig.setGroupName(fullSubName); + + for (String brokerAddr : brokerList) { + this.rmqAdmin.createAndUpdateSubscriptionGroupConfig(brokerAddr, subscriptionGroupConfig); + } + } catch (Exception e) { + throw new RuntimeException( + String.format( + "Failed to create subscription [%s] to cluster [%s]", + fullSubName, this.rmqClientConfig.clusterName), + e); + } + } + + @Override + public CompletableFuture createConsumer( + final String topic, final String subscriptionName, final ConsumerCallback consumerCallback) { + PushConsumer rmqConsumer; + + // To avoid bench-tool encounter subscription relationship conflict when specifying multiple + // topics, let's add topic name as subscription name prefix. + String subPrefix; + if (topic.contains("%")) { + subPrefix = topic.split("%")[1]; + } else { + subPrefix = topic; + } + String fullSubName = String.format("%s_%s", subPrefix, subscriptionName); + createSubscriptionGroup(fullSubName); + + ClientServiceProvider provider = ClientServiceProvider.loadService(); + ClientConfigurationBuilder builder = + ClientConfiguration.newBuilder().setEndpoints(this.rmqClientConfig.grpcEndpoint); + SessionCredentialsProvider sessionCredentialsProvider = + new StaticSessionCredentialsProvider( + this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey); + ClientConfiguration configuration; + if (isAclEnabled()) { + builder.setCredentialProvider(sessionCredentialsProvider); + configuration = builder.build(); + } else { + configuration = builder.build(); + } + FilterExpression filterExpression = new FilterExpression("*", FilterExpressionType.TAG); + + try { + rmqConsumer = + provider + .newPushConsumerBuilder() + .setClientConfiguration(configuration) + // Set the consumer group name. + .setConsumerGroup(fullSubName) + // Set the subscription for the consumer. + .setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression)) + .setMessageListener( + messageView -> { + // Handle the received message and return consume result. + consumerCallback.messageReceived( + messageView.getBody(), messageView.getBornTimestamp()); + return ConsumeResult.SUCCESS; + }) + .build(); + } catch (ClientException e) { + throw new RuntimeException(e); + } + return CompletableFuture.completedFuture(new RocketMQ5BenchmarkConsumer(rmqConsumer)); + } + + public boolean isAclEnabled() { + return !(StringUtils.isAnyBlank(this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey) + || StringUtils.isAnyEmpty(this.rmqClientConfig.accessKey, this.rmqClientConfig.secretKey)); + } + + public boolean isAdminAclEnabled() { + return !(StringUtils.isAnyBlank( + this.rmqClientConfig.adminAccessKey, this.rmqClientConfig.adminSecretKey) + || StringUtils.isAnyEmpty( + this.rmqClientConfig.adminAccessKey, this.rmqClientConfig.adminSecretKey)); + } + + @Override + public void close() throws Exception {} + + private static final ObjectMapper mapper = + new ObjectMapper(new YAMLFactory()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + private static RocketMQClient5Config readConfig(File configurationFile) throws IOException { + return mapper.readValue(configurationFile, RocketMQClient5Config.class); + } + + private static final Random random = new Random(); + + private static String getRandomString() { + byte[] buffer = new byte[5]; + random.nextBytes(buffer); + return BaseEncoding.base64Url().omitPadding().encode(buffer); + } + + private static final Logger log = LoggerFactory.getLogger(RocketMQ5BenchmarkDriver.class); +} diff --git a/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkProducer.java b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkProducer.java new file mode 100644 index 000000000..34bbd8a78 --- /dev/null +++ b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/RocketMQ5BenchmarkProducer.java @@ -0,0 +1,83 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.rocketmq; + + +import io.openmessaging.benchmark.driver.BenchmarkProducer; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import org.apache.rocketmq.client.apis.message.MessageBuilder; +import org.apache.rocketmq.client.apis.producer.Producer; +import org.apache.rocketmq.client.java.message.MessageBuilderImpl; + +public class RocketMQ5BenchmarkProducer implements BenchmarkProducer { + private final Producer rmqProducer; + private final String rmqTopic; + private final Boolean sendDelayMsg; + private final Long delayTimeInSec; + + public RocketMQ5BenchmarkProducer(final Producer rmqProducer, final String rmqTopic) { + this.rmqProducer = rmqProducer; + this.rmqTopic = rmqTopic; + this.sendDelayMsg = false; + this.delayTimeInSec = 0L; + } + + public RocketMQ5BenchmarkProducer( + final Producer rmqProducer, + final String rmqTopic, + Boolean sendDelayMsg, + Long delayTimeInSec) { + this.rmqProducer = rmqProducer; + this.rmqTopic = rmqTopic; + this.sendDelayMsg = sendDelayMsg; + this.delayTimeInSec = delayTimeInSec; + } + + @Override + public CompletableFuture sendAsync(final Optional key, final byte[] payload) { + MessageBuilder messageBuilder = new MessageBuilderImpl(); + messageBuilder.setBody(payload); + messageBuilder.setTopic(this.rmqTopic); + + key.ifPresent(messageBuilder::setKeys); + + if (this.sendDelayMsg) { + // 延时消息,单位秒(s),在指定延迟时间(当前时间之后)进行投递,例如消息在10秒后投递。 + long delayTime = System.currentTimeMillis() + this.delayTimeInSec * 1000; + // 设置消息需要被投递的时间。 + messageBuilder.setDeliveryTimestamp(delayTime); + } + + CompletableFuture future = new CompletableFuture<>(); + this.rmqProducer + .sendAsync(messageBuilder.build()) + .whenComplete( + (sendReceipt, throwable) -> { + if (sendReceipt != null) { + future.complete(null); + } else { + future.completeExceptionally(throwable); + } + }); + return future; + } + + @Override + public void close() throws Exception { + if (rmqProducer != null) { + rmqProducer.close(); + } + } +} diff --git a/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClient5Config.java b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClient5Config.java new file mode 100644 index 000000000..11c9ae5a4 --- /dev/null +++ b/driver-rocketmq5/src/main/java/io/openmessaging/benchmark/driver/rocketmq/client/RocketMQClient5Config.java @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.driver.rocketmq.client; + +public class RocketMQClient5Config { + public String namesrvAddr; + public String grpcEndpoint; + public String clusterName; + public String adminAccessKey; + public String adminSecretKey; + public String accessKey; + public String secretKey; + public boolean sendDelayMsg; + public Long delayTimeInSec; +} diff --git a/etc/APACHE-2.txt b/etc/APACHE-2.txt new file mode 100644 index 000000000..86a8beecb --- /dev/null +++ b/etc/APACHE-2.txt @@ -0,0 +1,11 @@ +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/etc/checkstyle.xml b/etc/checkstyle.xml new file mode 100644 index 000000000..2d95c2bf3 --- /dev/null +++ b/etc/checkstyle.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/findbugsExclude.xml b/etc/findbugsExclude.xml new file mode 100644 index 000000000..a5af39dd8 --- /dev/null +++ b/etc/findbugsExclude.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/package/pom.xml b/package/pom.xml index dc6ab7fc9..199d8f145 100644 --- a/package/pom.xml +++ b/package/pom.xml @@ -1,71 +1,66 @@ + - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - .. - + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + - package - Packaging - pom + package + pom + Packaging - - - - maven-assembly-plugin - 3.1.0 - - - distro-assembly - package - - single - - - true - posix - openmessaging-benchmark-${project.version} - - src/assemble/bin.xml - src/assemble/src.xml - - - - - - - + + + ${project.groupId} + benchmark-framework + ${project.version} + + - - - ${project.groupId} - benchmark-framework - ${project.version} - - + + + + maven-assembly-plugin + 3.3.0 + + + distro-assembly + + single + + package + + true + posix + openmessaging-benchmark-${project.version} + + src/assemble/bin.xml + src/assemble/src.xml + + + + + + + diff --git a/package/src/assemble/bin.xml b/package/src/assemble/bin.xml index 1f9a8f894..1ae16f685 100644 --- a/package/src/assemble/bin.xml +++ b/package/src/assemble/bin.xml @@ -1,21 +1,16 @@ - 4.0.0 - - io.openmessaging.benchmark - messaging-benchmark - 0.0.1-SNAPSHOT - Messaging Benchmark - pom - - - benchmark-framework - driver-api - - driver-pravega - driver-pulsar - driver-kafka - driver-rabbitmq - driver-artemis - driver-bookkeeper - driver-rocketmq - driver-nats - driver-nats-streaming - driver-nsq - driver-jms - driver-redis - package - docker - - - - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - UTF-8 - UTF-8 - 4.14.0 - - - - - - com.mycila - license-maven-plugin - 3.0 - -
dev/license-header.txt
- - - LICENSE - NOTICE - payload/** - **/*.pyc - **/.pydevproject - .github/** - - - SCRIPT_STYLE - SCRIPT_STYLE - SCRIPT_STYLE - SCRIPT_STYLE - XML_STYLE - -
- - - - check - - - -
-
-
- - - - org.slf4j - slf4j-api - 1.7.25 - - - - com.fasterxml.jackson.core - jackson-databind - 2.9.10.8 - - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - 2.9.3 - - - io.netty - netty-all - 4.1.48.Final - - - - - - - - com.google.guava - guava - 29.0-jre - - - - - - - modern-java-compile - - [9,) - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 8 - 8 - 8 - UTF-8 - true - true - true - - - - - - - - jdk-8-compile - - [,8] - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 8 - 8 - UTF-8 - true - true - true - - - - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + pom + Messaging Benchmark + + 2017 + + + OpenMessaging Project + https://openmessaging.cloud + + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + benchmark-framework + driver-api + + driver-pravega + driver-pulsar + driver-kafka + driver-rabbitmq + driver-artemis + driver-bookkeeper + driver-rocketmq + driver-rocketmq5 + driver-nats + driver-nats-streaming + driver-nsq + driver-jms + driver-redis + package + docker + driver-kop + tool + driver-mqtt5 + + + + UTF-8 + UTF-8 + + 3.23.1 + 4.14.4 + 10.3.3 + 3.12.0 + 2.20.0 + 1.18.36 + 2.13.2 + 1.48 + 5.9.0 + 4.8.0 + 4.1.65.Final + 1.7.36 + + 3.2.0 + 0.8.8 + 4.1 + 3.13.0 + 3.1.0 + 3.0.0-M7 + 4.7.2.0 + 2.25.0 + + + + + + com.beust + jcommander + ${jcommander.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-base + ${jackson.version} + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + ${jackson.version} + + + com.google.guava + guava + 29.0-jre + + + io.netty + netty-all + ${netty.version} + + + org.apache.commons + commons-lang3 + ${commons.lang3.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.junit.jupiter.version} + test + + + + + + + + + com.diffplug.spotless + spotless-maven-plugin + ${spotless.plugin.version} + + + + false + true + 4 + scope,groupId,artifactId + groupId,artifactId + groupId,artifactId + + + + + + + + true + 2 + + + true + 4 + + + + + **/*.md + + + + + + + etc/**/*.xml + .github/workflows/**/*.yml + **/doc/**/*.puml + + + + + true + 4 + + + + + + + check + + check + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs.plugin.version} + + etc/findbugsExclude.xml + + + + + check + + + + + + + com.mycila + license-maven-plugin + ${license.plugin.version} + +
etc/APACHE-2.txt
+ + LICENSE + NOTICE + payload/** + **/*.pyc + **/.pydevproject + .github/** + + + SCRIPT_STYLE + SCRIPT_STYLE + SCRIPT_STYLE + SCRIPT_STYLE + XML_STYLE + SCRIPT_STYLE + APOSTROPHE_STYLE + +
+ + + com.mycila + license-maven-plugin-git + ${license.plugin.version} + + + + + + check + + process-sources + + +
+ + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + true + true + true + etc/checkstyle.xml + true + + + + com.puppycrawl.tools + checkstyle + ${checkstyle.version} + + + + + + check + + validate + + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven.enforcer.plugin.version} + + + enforce-maven-version + + enforce + + + + + [3.8.6,) + + + true + + + + + + maven-failsafe-plugin + ${maven.surefire.plugin.version} + + + + integration-test + verify + + + + + + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + + + --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED + -Dio.netty.tryReflectionSetAccessible=true + --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED + -Dorg.apache.pulsar.shade.io.netty.tryReflectionSetAccessible=true + --add-opens java.base/java.util.zip=ALL-UNNAMED + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.plugin.version} + + + + prepare-agent + + + + report + + report + + verify + + + check + + check + + verify + + + + BUNDLE + + + CLASS + COVEREDRATIO + 0.00 + + + METHOD + COVEREDRATIO + 0.00 + + + LINE + COVEREDRATIO + 0.00 + + + BRANCH + COVEREDRATIO + 0.00 + + + + + + + + +
+
+ + + + modern-java-compile + + [9,) + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 17 + ${project.build.sourceEncoding} + true + true + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + + + + jdk-8-compile + + [,8] + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 8 + 8 + ${project.build.sourceEncoding} + true + true + true + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + + +
diff --git a/style/copyright/Apache.xml b/style/copyright/Apache.xml new file mode 100644 index 000000000..1dc9ce264 --- /dev/null +++ b/style/copyright/Apache.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/tool/README.md b/tool/README.md new file mode 100644 index 000000000..231160428 --- /dev/null +++ b/tool/README.md @@ -0,0 +1,68 @@ +# Tool + +## `WorkloadGenerationTool` + +Generates a set of `Workload` definition files from a `WorkloadSetTemplate` file. + +### Example + +Template: + +```yaml +nameFormat: "${topics}-topics-${partitionsPerTopic}-partitions-${messageSize}b-${producersPerTopic}p-${consumerPerSubscription}c-${producerRate}" +topics: [1] +partitionsPerTopic: [1] +messageSize: [10000] +payloadFile: "payload/payload-100b.data" +subscriptionsPerTopic: [1] +consumerPerSubscription: [1, 2, 4, 8, 16, 32, 64] +producersPerTopic: [1, 2, 4, 8, 16, 32, 64] +producerRate: [50000] +consumerBacklogSizeGB: 0 +testDurationMinutes: 15 +``` + +Usage: + +``` +mkdir my-workloads + io.openmessaging.benchmark.tool.workload.WorkloadGenerationTool \ + --templateFile=template.yaml \ + --outputFolder=my-workloads +``` + +Output: + +``` +Starting benchmark with config: templateFile: "template.yaml" +outputFolder: "my-workloads" + +Generated: 1-topics-1-partitions-10kb-1p-1c-50k +Generated: 1-topics-1-partitions-10kb-1p-2c-50k +Generated: 1-topics-1-partitions-10kb-1p-4c-50k +... +Generated: 1-topics-1-partitions-10kb-64p-64c-50k +Generated 49 workloads. +``` + +Example generated workload: + +```yaml +name: "1-topics-1-partitions-10kb-64p-2c-50k" +topics: 1 +partitionsPerTopic: 1 +keyDistributor: "NO_KEY" +messageSize: 10000 +useRandomizedPayloads: false +randomBytesRatio: 0.0 +randomizedPayloadPoolSize: 0 +payloadFile: "payload/payload-100b.data" +subscriptionsPerTopic: 1 +producersPerTopic: 64 +consumerPerSubscription: 2 +producerRate: 50000 +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 +warmupDurationMinutes: 1 +``` + diff --git a/tool/pom.xml b/tool/pom.xml new file mode 100644 index 000000000..4c0391582 --- /dev/null +++ b/tool/pom.xml @@ -0,0 +1,74 @@ + + + + 4.0.0 + + io.openmessaging.benchmark + messaging-benchmark + 0.0.1-SNAPSHOT + + + tool + + + + com.beust + jcommander + + + io.openmessaging.benchmark + benchmark-framework + ${project.version} + + + org.apache.commons + commons-io + 1.3.2 + + + org.apache.commons + commons-text + 1.10.0 + + + org.apache.logging.log4j + log4j-slf4j-impl + + + org.assertj + assertj-core + + + org.projectlombok + lombok + + + org.junit.jupiter + junit-jupiter + 5.9.0 + test + + + org.mockito + mockito-junit-jupiter + 4.7.0 + test + + + + diff --git a/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadGenerationTool.java b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadGenerationTool.java new file mode 100644 index 000000000..91bfb7d5d --- /dev/null +++ b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadGenerationTool.java @@ -0,0 +1,97 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.tool.workload; + + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParameterException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import io.openmessaging.benchmark.Workload; +import java.io.File; +import java.io.IOException; +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +/** Generates a set of {@link Workload} definition files from a {@link WorkloadSetTemplate} file. */ +@Slf4j +public class WorkloadGenerationTool { + + private static final ObjectMapper mapper = + new ObjectMapper( + new YAMLFactory().configure(YAMLGenerator.Feature.WRITE_DOC_START_MARKER, false)) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + static { + mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); + } + + public static void main(String[] args) throws IOException { + final WorkloadGenerationTool.Arguments arguments = new WorkloadGenerationTool.Arguments(); + JCommander jc = new JCommander(arguments); + jc.setProgramName("workload-generator"); + + try { + jc.parse(args); + } catch (ParameterException e) { + System.err.println(e.getMessage()); + jc.usage(); + System.exit(-1); + } + + if (arguments.help) { + jc.usage(); + System.exit(-1); + } + + // Dump configuration variables + log.info("Starting benchmark with config: {}", mapper.writeValueAsString(arguments)); + + WorkloadSetTemplate template = + mapper.readValue(arguments.templateFile, WorkloadSetTemplate.class); + List workloads = new WorkloadGenerator(template).generate(); + for (Workload w : workloads) { + File outputFile = null; + try { + outputFile = new File(arguments.outputFolder, w.name + ".yaml"); + mapper.writeValue(outputFile, w); + } catch (IOException e) { + log.error("Could not write file: {}", outputFile, e); + } + } + } + + static class Arguments { + @Parameter( + names = {"-t", "--template-file"}, + description = "Path to a YAML file containing the workload template", + required = true) + public File templateFile; + + @Parameter( + names = {"-o", "--output-folder"}, + description = "Output", + required = true) + public File outputFolder; + + @Parameter( + names = {"-h", "--help"}, + description = "Help message", + help = true) + boolean help; + } +} diff --git a/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadGenerator.java b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadGenerator.java new file mode 100644 index 000000000..d2bfc7956 --- /dev/null +++ b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadGenerator.java @@ -0,0 +1,98 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.tool.workload; + +import static java.util.Collections.unmodifiableList; + +import io.openmessaging.benchmark.Workload; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +/** + * Expands a {@link io.openmessaging.benchmark.tool.workload.WorkloadSetTemplate} into a set of + * {@link io.openmessaging.benchmark.Workload Workloads}. + */ +@Slf4j +class WorkloadGenerator { + private final WorkloadSetTemplate template; + private final WorkloadNameFormat nameFormat; + + WorkloadGenerator(@NonNull WorkloadSetTemplate template) { + this.template = template; + nameFormat = new WorkloadNameFormat(template.nameFormat); + } + + List generate() throws IOException { + List workloads = new ArrayList<>(); + Workload workload = new Workload(); + workload.keyDistributor = template.keyDistributor; + workload.payloadFile = template.payloadFile; + workload.randomBytesRatio = template.randomBytesRatio; + workload.randomizedPayloadPoolSize = template.randomizedPayloadPoolSize; + workload.consumerBacklogSizeGB = template.consumerBacklogSizeGB; + workload.testDurationMinutes = template.testDurationMinutes; + workload.warmupDurationMinutes = template.warmupDurationMinutes; + workload.useRandomizedPayloads = template.useRandomizedPayloads; + for (int t : template.topics) { + for (int pa : template.partitionsPerTopic) { + for (int ms : template.messageSize) { + for (int pd : template.producersPerTopic) { + for (int st : template.subscriptionsPerTopic) { + for (int cn : template.consumerPerSubscription) { + for (int pr : template.producerRate) { + workload.topics = t; + workload.partitionsPerTopic = pa; + workload.messageSize = ms; + workload.producersPerTopic = pd; + workload.subscriptionsPerTopic = st; + workload.consumerPerSubscription = cn; + workload.producerRate = pr; + Workload copy = copyOf(workload); + workloads.add(copy); + log.info("Generated: {}", copy.name); + } + } + } + } + } + } + } + log.info("Generated {} workloads.", workloads.size()); + return unmodifiableList(workloads); + } + + private Workload copyOf(Workload workload) { + Workload copy = new Workload(); + copy.keyDistributor = workload.keyDistributor; + copy.payloadFile = workload.payloadFile; + copy.randomBytesRatio = workload.randomBytesRatio; + copy.randomizedPayloadPoolSize = workload.randomizedPayloadPoolSize; + copy.consumerBacklogSizeGB = workload.consumerBacklogSizeGB; + copy.testDurationMinutes = workload.testDurationMinutes; + copy.warmupDurationMinutes = workload.warmupDurationMinutes; + copy.topics = workload.topics; + copy.partitionsPerTopic = workload.partitionsPerTopic; + copy.messageSize = workload.messageSize; + copy.producersPerTopic = workload.producersPerTopic; + copy.subscriptionsPerTopic = workload.subscriptionsPerTopic; + copy.consumerPerSubscription = workload.consumerPerSubscription; + copy.producerRate = workload.producerRate; + copy.useRandomizedPayloads = workload.useRandomizedPayloads; + copy.name = nameFormat.from(copy); + return copy; + } +} diff --git a/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadNameFormat.java b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadNameFormat.java new file mode 100644 index 000000000..501d6fc00 --- /dev/null +++ b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadNameFormat.java @@ -0,0 +1,76 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.tool.workload; + + +import io.openmessaging.benchmark.Workload; +import java.util.HashMap; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang.text.StrSubstitutor; + +/** + * Generates {@link Workload} names based on a template. Substitutes template place-holders of the + * form {@code ${variableName}}, where {@code variableName} is the name of a public member in {@link + * Workload}. Note that the set of variables is statically assigned. Numeric values will typically + * be in a form that includes an SI suffix. + */ +@RequiredArgsConstructor +class WorkloadNameFormat { + + private static final long MAX_PRODUCER_RATE = 10_000_000; + + private final String format; + + String from(Workload workload) { + if (workload.name != null) { + return workload.name; + } + Map params = new HashMap<>(); + params.put("topics", countToDisplaySize(workload.topics)); + params.put("partitionsPerTopic", countToDisplaySize(workload.partitionsPerTopic)); + params.put("messageSize", countToDisplaySize(workload.messageSize)); + params.put("subscriptionsPerTopic", countToDisplaySize(workload.subscriptionsPerTopic)); + params.put("producersPerTopic", countToDisplaySize(workload.producersPerTopic)); + params.put("consumerPerSubscription", countToDisplaySize(workload.consumerPerSubscription)); + params.put( + "producerRate", + (workload.producerRate >= MAX_PRODUCER_RATE) + ? "max-rate" + : countToDisplaySize(workload.producerRate)); + params.put("keyDistributor", workload.keyDistributor); + params.put("payloadFile", workload.payloadFile); + params.put("useRandomizedPayloads", workload.useRandomizedPayloads); + params.put("randomBytesRatio", workload.randomBytesRatio); + params.put("randomizedPayloadPoolSize", countToDisplaySize(workload.randomizedPayloadPoolSize)); + params.put("consumerBacklogSizeGB", countToDisplaySize(workload.consumerBacklogSizeGB)); + params.put("testDurationMinutes", workload.testDurationMinutes); + params.put("warmupDurationMinutes", workload.warmupDurationMinutes); + return StrSubstitutor.replace(format, params, "${", "}"); + } + + private static String countToDisplaySize(long size) { + String displaySize; + if (size / 1_000_000_000L > 0L) { + displaySize = size / 1_000_000_000L + "g"; + } else if (size / 1_000_000L > 0L) { + displaySize = size / 1_000_000L + "m"; + } else if (size / 1_000L > 0L) { + displaySize = size / 1_000 + "k"; + } else { + displaySize = size + ""; + } + return displaySize; + } +} diff --git a/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadSetTemplate.java b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadSetTemplate.java new file mode 100644 index 000000000..538a28ef4 --- /dev/null +++ b/tool/src/main/java/io/openmessaging/benchmark/tool/workload/WorkloadSetTemplate.java @@ -0,0 +1,55 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.tool.workload; + + +import io.openmessaging.benchmark.utils.distributor.KeyDistributorType; +import java.util.Collections; +import java.util.List; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * A template that defines a set of workload definitions. This is much like the {@link + * io.openmessaging.benchmark.Workload} entity, except that for many values that typically change in + * a benchmark, one can specify a sequence of values. + */ +@Data +@NoArgsConstructor +public class WorkloadSetTemplate { + public static final String DEFAULT_NAME_TEMPLATE = + "${topics}-topics-${partitionsPerTopic}-partitions-${messageSize}b" + + "-${producersPerTopic}p-${consumerPerSubscription}c-${producerRate}"; + public String nameFormat = DEFAULT_NAME_TEMPLATE; + + /** Number of topics to create in the test. */ + public List topics = Collections.emptyList(); + /** Number of partitions each topic will contain. */ + public List partitionsPerTopic = Collections.emptyList(); + + public List messageSize = Collections.emptyList(); + public List subscriptionsPerTopic = Collections.emptyList(); + public List producersPerTopic = Collections.emptyList(); + public List consumerPerSubscription = Collections.emptyList(); + public List producerRate = Collections.emptyList(); + + public KeyDistributorType keyDistributor = KeyDistributorType.NO_KEY; + public String payloadFile = null; + public boolean useRandomizedPayloads = false; + public double randomBytesRatio = 0.0; + public int randomizedPayloadPoolSize = 0; + public long consumerBacklogSizeGB = 0; + public int testDurationMinutes = 5; + public int warmupDurationMinutes = 1; +} diff --git a/tool/src/main/resources/log4j2.yaml b/tool/src/main/resources/log4j2.yaml new file mode 100644 index 000000000..fa5945cb8 --- /dev/null +++ b/tool/src/main/resources/log4j2.yaml @@ -0,0 +1,30 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Configuration: + status: INFO + name: driver-kafka-test + + Appenders: + Console: + name: Console + target: SYSTEM_OUT + PatternLayout: + Pattern: "%d{HH:mm:ss.SSS} [%t] %-4level %c{1} - %msg%n" + Loggers: + Root: + level: info + additivity: false + AppenderRef: + - ref: Console diff --git a/tool/src/test/java/io/openmessaging/benchmark/tool/workload/WorkloadNameFormatTest.java b/tool/src/test/java/io/openmessaging/benchmark/tool/workload/WorkloadNameFormatTest.java new file mode 100644 index 000000000..63ff456fc --- /dev/null +++ b/tool/src/test/java/io/openmessaging/benchmark/tool/workload/WorkloadNameFormatTest.java @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.openmessaging.benchmark.tool.workload; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.openmessaging.benchmark.Workload; +import org.junit.jupiter.api.Test; + +class WorkloadNameFormatTest { + + public String nameFormat = + "${topics}-topics-${partitionsPerTopic}-partitions-${messageSize}b" + + "-${producersPerTopic}p-${consumerPerSubscription}c-${producerRate}"; + + @Test + void nameOverride() { + Workload workload = new Workload(); + workload.name = "x"; + String name = new WorkloadNameFormat(nameFormat).from(workload); + assertThat(name).isEqualTo("x"); + } + + @Test + void from() { + Workload workload = new Workload(); + workload.topics = 1456; + workload.partitionsPerTopic = 2123; + workload.messageSize = 617890; + workload.producersPerTopic = 45; + workload.consumerPerSubscription = 541; + workload.producerRate = 1000000; + String name = new WorkloadNameFormat(nameFormat).from(workload); + assertThat(name).isEqualTo("1k-topics-2k-partitions-617kb-45p-541c-1m"); + } +} diff --git a/tool/src/test/resources/template.yaml b/tool/src/test/resources/template.yaml new file mode 100644 index 000000000..e3895faec --- /dev/null +++ b/tool/src/test/resources/template.yaml @@ -0,0 +1,25 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +nameFormat: "${topics}-topics-${partitionsPerTopic}-partitions-${messageSize}b-${producersPerTopic}p-${consumerPerSubscription}c-${producerRate}" +topics: [1] +partitionsPerTopic: [1] +messageSize: [10000] +payloadFile: "payload/payload-100b.data" +subscriptionsPerTopic: [1] +consumerPerSubscription: [1, 2, 4, 8, 16, 32, 64] +producersPerTopic: [1, 2, 4, 8, 16, 32, 64] +producerRate: [50000] +consumerBacklogSizeGB: 0 +testDurationMinutes: 15 \ No newline at end of file diff --git a/workloads/1-topic-1-partition-100b.yaml b/workloads/1-topic-1-partition-100b.yaml index 4f4f55728..1a2b4b2f7 100644 --- a/workloads/1-topic-1-partition-100b.yaml +++ b/workloads/1-topic-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 topic / 1 partition / 100b diff --git a/workloads/1-topic-1-partition-1kb.yaml b/workloads/1-topic-1-partition-1kb.yaml index caa1f204a..7c074d9a0 100644 --- a/workloads/1-topic-1-partition-1kb.yaml +++ b/workloads/1-topic-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 topic / 1 partition / 1Kb diff --git a/workloads/1-topic-100-partitions-1kb-4p-4c-1000k.yaml b/workloads/1-topic-100-partitions-1kb-4p-4c-1000k.yaml index 0eafe5fd5..95201382d 100644 --- a/workloads/1-topic-100-partitions-1kb-4p-4c-1000k.yaml +++ b/workloads/1-topic-100-partitions-1kb-4p-4c-1000k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1000k rate 4 producers and 4 consumers on 1 topic / 100 partition diff --git a/workloads/1-topic-100-partitions-1kb-4p-4c-2000k.yaml b/workloads/1-topic-100-partitions-1kb-4p-4c-2000k.yaml index 761d172ca..2b44b5341 100644 --- a/workloads/1-topic-100-partitions-1kb-4p-4c-2000k.yaml +++ b/workloads/1-topic-100-partitions-1kb-4p-4c-2000k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 2000k rate 4 producers and 4 consumers on 1 topic / 100 partition diff --git a/workloads/1-topic-100-partitions-1kb-4p-4c-200k-backlog.yaml b/workloads/1-topic-100-partitions-1kb-4p-4c-200k-backlog.yaml index 6918f74b9..e61149a8f 100644 --- a/workloads/1-topic-100-partitions-1kb-4p-4c-200k-backlog.yaml +++ b/workloads/1-topic-100-partitions-1kb-4p-4c-200k-backlog.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Backlog for 200k rate 4 producers and 4 consumers on 1 topic / 100 partition diff --git a/workloads/1-topic-100-partitions-1kb-4p-4c-200k.yaml b/workloads/1-topic-100-partitions-1kb-4p-4c-200k.yaml index 6993ba4c7..cfb3b4c4f 100644 --- a/workloads/1-topic-100-partitions-1kb-4p-4c-200k.yaml +++ b/workloads/1-topic-100-partitions-1kb-4p-4c-200k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 200k rate 4 producers and 4 consumers on 1 topic / 100 partition diff --git a/workloads/1-topic-100-partitions-1kb-4p-4c-500k.yaml b/workloads/1-topic-100-partitions-1kb-4p-4c-500k.yaml index a224bed2b..a938e3652 100644 --- a/workloads/1-topic-100-partitions-1kb-4p-4c-500k.yaml +++ b/workloads/1-topic-100-partitions-1kb-4p-4c-500k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 500k rate 4 producers and 4 consumers on 1 topic / 100 partition diff --git a/workloads/1-topic-100-partitions-1kb.yaml b/workloads/1-topic-100-partitions-1kb.yaml index 51778f8fe..6c8cff632 100644 --- a/workloads/1-topic-100-partitions-1kb.yaml +++ b/workloads/1-topic-100-partitions-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 producer / 1 consumers on 1 topic diff --git a/workloads/1-topic-10000-partitions-1kb-4p-4c-1000k.yaml b/workloads/1-topic-10000-partitions-1kb-4p-4c-1000k.yaml index 9060381f1..be14a5f75 100644 --- a/workloads/1-topic-10000-partitions-1kb-4p-4c-1000k.yaml +++ b/workloads/1-topic-10000-partitions-1kb-4p-4c-1000k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1000k rate 4 producers and 4 consumers on 1 topic / 10000 partition diff --git a/workloads/1-topic-10000-partitions-1kb-4p-4c-2000k.yaml b/workloads/1-topic-10000-partitions-1kb-4p-4c-2000k.yaml index 93980b5ef..b5296245b 100644 --- a/workloads/1-topic-10000-partitions-1kb-4p-4c-2000k.yaml +++ b/workloads/1-topic-10000-partitions-1kb-4p-4c-2000k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 2000k rate 4 producers and 4 consumers on 1 topic / 10000 partition diff --git a/workloads/1-topic-10000-partitions-1kb-4p-4c-200k.yaml b/workloads/1-topic-10000-partitions-1kb-4p-4c-200k.yaml index 8a851fe6b..b0b709e3c 100644 --- a/workloads/1-topic-10000-partitions-1kb-4p-4c-200k.yaml +++ b/workloads/1-topic-10000-partitions-1kb-4p-4c-200k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 200k rate 4 producers and 4 consumers on 1 topic / 10000 partition diff --git a/workloads/1-topic-10000-partitions-1kb-4p-4c-500k.yaml b/workloads/1-topic-10000-partitions-1kb-4p-4c-500k.yaml index 0ed1cc493..cb5550f56 100644 --- a/workloads/1-topic-10000-partitions-1kb-4p-4c-500k.yaml +++ b/workloads/1-topic-10000-partitions-1kb-4p-4c-500k.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 500k rate 4 producers and 4 consumers on 1 topic / 10000 partition diff --git a/workloads/1-topic-16-partition-100b.yaml b/workloads/1-topic-16-partition-100b.yaml index 383a8a4ca..3f94b60e0 100644 --- a/workloads/1-topic-16-partition-100b.yaml +++ b/workloads/1-topic-16-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 topic / 16 partition / 100b diff --git a/workloads/1-topic-16-partitions-1kb.yaml b/workloads/1-topic-16-partitions-1kb.yaml index 56c9a3654..ed1856a79 100644 --- a/workloads/1-topic-16-partitions-1kb.yaml +++ b/workloads/1-topic-16-partitions-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 producer / 1 consumers on 1 topic diff --git a/workloads/1-topic-3-partition-100b-3producers.yaml b/workloads/1-topic-3-partition-100b-3producers.yaml index 96b160ed3..4bd561425 100644 --- a/workloads/1-topic-3-partition-100b-3producers.yaml +++ b/workloads/1-topic-3-partition-100b-3producers.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 topic / 3 partition / 100b / 3 producers diff --git a/workloads/1-topic-6-partition-100b.yaml b/workloads/1-topic-6-partition-100b.yaml index 8cc7c9b99..510d2af02 100644 --- a/workloads/1-topic-6-partition-100b.yaml +++ b/workloads/1-topic-6-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 topic / 6 partition / 100b diff --git a/workloads/100-topic-1kb-4p-4c-2000k.yaml b/workloads/100-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..f70d0da2b --- /dev/null +++ b/workloads/100-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 100 topic + +topics: 100 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/100-topic-1kb-4p-4c-500k.yaml b/workloads/100-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..4b577432b --- /dev/null +++ b/workloads/100-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 100 topic + +topics: 100 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/100-topics-1-partitions-1kb.yaml b/workloads/100-topics-1-partitions-1kb.yaml index 379bf553e..1fa0aecc8 100644 --- a/workloads/100-topics-1-partitions-1kb.yaml +++ b/workloads/100-topics-1-partitions-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 producer / 3 consumers on 100 topics diff --git a/workloads/100k-topic-1kb-4p-4c-100k.yaml b/workloads/100k-topic-1kb-4p-4c-100k.yaml new file mode 100644 index 000000000..20c6b04f2 --- /dev/null +++ b/workloads/100k-topic-1kb-4p-4c-100k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 100k rate 4 producers and 4 consumers on 100k topic + +topics: 100000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 100000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/100k-topic-1kb-4p-4c-2000k.yaml b/workloads/100k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..6b5134436 --- /dev/null +++ b/workloads/100k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 100k topic + +topics: 100000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/100k-topic-1kb-4p-4c-500k.yaml b/workloads/100k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..4a5db4461 --- /dev/null +++ b/workloads/100k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 100k topic + +topics: 100000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/10k-topic-1kb-4p-4c-100k.yaml b/workloads/10k-topic-1kb-4p-4c-100k.yaml new file mode 100644 index 000000000..365790b42 --- /dev/null +++ b/workloads/10k-topic-1kb-4p-4c-100k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 100k rate 4 producers and 4 consumers on 10k topic + +topics: 10000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 100000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/10k-topic-1kb-4p-4c-2000k.yaml b/workloads/10k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..c007225fa --- /dev/null +++ b/workloads/10k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 10k topic + +topics: 10000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/10k-topic-1kb-4p-4c-500k.yaml b/workloads/10k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..b48f9e7e6 --- /dev/null +++ b/workloads/10k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 10k topic + +topics: 10000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/1k-topic-1kb-4p-4c-100k.yaml b/workloads/1k-topic-1kb-4p-4c-100k.yaml new file mode 100644 index 000000000..ccf38b9f0 --- /dev/null +++ b/workloads/1k-topic-1kb-4p-4c-100k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 100k rate 4 producers and 4 consumers on 1k topic + +topics: 1000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 100000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/1k-topic-1kb-4p-4c-2000k.yaml b/workloads/1k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..b060d1295 --- /dev/null +++ b/workloads/1k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 1k topic + +topics: 1000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/1k-topic-1kb-4p-4c-500k.yaml b/workloads/1k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..1f389de50 --- /dev/null +++ b/workloads/1k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 1k topic + +topics: 1000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/1m-10-topics-1-partition-100b.yaml b/workloads/1m-10-topics-1-partition-100b.yaml index cca18bdba..0168734af 100644 --- a/workloads/1m-10-topics-1-partition-100b.yaml +++ b/workloads/1m-10-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-1-partition-100b diff --git a/workloads/1m-10-topics-16-partitions-100b.yaml b/workloads/1m-10-topics-16-partitions-100b.yaml index 2957f65d7..be3d6584d 100644 --- a/workloads/1m-10-topics-16-partitions-100b.yaml +++ b/workloads/1m-10-topics-16-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-16-partitions-100b diff --git a/workloads/1m-10-topics-2-partitions-100b.yaml b/workloads/1m-10-topics-2-partitions-100b.yaml index 01afc5c84..e6ef2eb81 100644 --- a/workloads/1m-10-topics-2-partitions-100b.yaml +++ b/workloads/1m-10-topics-2-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-2-partitions-100b diff --git a/workloads/1m-10-topics-3-partitions-100b.yaml b/workloads/1m-10-topics-3-partitions-100b.yaml index a3c2390a2..73dbb9207 100644 --- a/workloads/1m-10-topics-3-partitions-100b.yaml +++ b/workloads/1m-10-topics-3-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-3-partitions-100b diff --git a/workloads/1m-10-topics-4-partitions-100b.yaml b/workloads/1m-10-topics-4-partitions-100b.yaml index a0d300260..2382bf6eb 100644 --- a/workloads/1m-10-topics-4-partitions-100b.yaml +++ b/workloads/1m-10-topics-4-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-4-partitions-100b diff --git a/workloads/1m-10-topics-6-partitions-100b.yaml b/workloads/1m-10-topics-6-partitions-100b.yaml index 6ec47c434..b3dc0c3cb 100644 --- a/workloads/1m-10-topics-6-partitions-100b.yaml +++ b/workloads/1m-10-topics-6-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-6-partitions-100b diff --git a/workloads/1m-10-topics-9-partitions-100b.yaml b/workloads/1m-10-topics-9-partitions-100b.yaml index 1d4d5da28..645224efc 100644 --- a/workloads/1m-10-topics-9-partitions-100b.yaml +++ b/workloads/1m-10-topics-9-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1m-10-topics-9-partitions-100b diff --git a/workloads/1m-topic-1kb-4p-4c-2000k.yaml b/workloads/1m-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..051ae6e01 --- /dev/null +++ b/workloads/1m-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 1m topic + +topics: 1000000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/1m-topic-1kb-4p-4c-500k.yaml b/workloads/1m-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..f1a107564 --- /dev/null +++ b/workloads/1m-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 1m topic + +topics: 1000000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/200k-topic-1kb-4p-4c-100k.yaml b/workloads/200k-topic-1kb-4p-4c-100k.yaml new file mode 100644 index 000000000..7fd75dc8d --- /dev/null +++ b/workloads/200k-topic-1kb-4p-4c-100k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 100k rate 4 producers and 4 consumers on 200k topic + +topics: 200000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 100000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/200k-topic-1kb-4p-4c-2000k.yaml b/workloads/200k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..7d737bce2 --- /dev/null +++ b/workloads/200k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 200k topic + +topics: 200000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/200k-topic-1kb-4p-4c-500k.yaml b/workloads/200k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..83ca06336 --- /dev/null +++ b/workloads/200k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 200k topic + +topics: 200000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/300k-topic-1kb-4p-4c-2000k.yaml b/workloads/300k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..cfcfb12fc --- /dev/null +++ b/workloads/300k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 300k topic + +topics: 300000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/300k-topic-1kb-4p-4c-500k.yaml b/workloads/300k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..86482683f --- /dev/null +++ b/workloads/300k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 300k topic + +topics: 300000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/400k-topic-1kb-4p-4c-2000k.yaml b/workloads/400k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..c7286c416 --- /dev/null +++ b/workloads/400k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 400k topic + +topics: 400000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/400k-topic-1kb-4p-4c-500k.yaml b/workloads/400k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..acea013b2 --- /dev/null +++ b/workloads/400k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 400k topic + +topics: 400000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/500-topic-1kb-4p-4c-2000k.yaml b/workloads/500-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..c8bb3795f --- /dev/null +++ b/workloads/500-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 500 topic + +topics: 500 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/500-topic-1kb-4p-4c-500k.yaml b/workloads/500-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..0dc59c443 --- /dev/null +++ b/workloads/500-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 500 topic + +topics: 500 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/500k-topic-1kb-4p-4c-2000k.yaml b/workloads/500k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..42030106f --- /dev/null +++ b/workloads/500k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 500k topic + +topics: 500000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/500k-topic-1kb-4p-4c-500k.yaml b/workloads/500k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..addfcc98d --- /dev/null +++ b/workloads/500k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 500k topic + +topics: 500000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/50k-topic-1kb-4p-4c-100k.yaml b/workloads/50k-topic-1kb-4p-4c-100k.yaml new file mode 100644 index 000000000..e38e77acb --- /dev/null +++ b/workloads/50k-topic-1kb-4p-4c-100k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 100k rate 4 producers and 4 consumers on 50k topic + +topics: 50000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 100000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/50k-topic-1kb-4p-4c-2000k.yaml b/workloads/50k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..5c066e3a3 --- /dev/null +++ b/workloads/50k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 50k topic + +topics: 50000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/50k-topic-1kb-4p-4c-500k.yaml b/workloads/50k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..2345d64ee --- /dev/null +++ b/workloads/50k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 50k topic + +topics: 50000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/5k-topic-1kb-4p-4c-100k.yaml b/workloads/5k-topic-1kb-4p-4c-100k.yaml new file mode 100644 index 000000000..b092ccedc --- /dev/null +++ b/workloads/5k-topic-1kb-4p-4c-100k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 100k rate 4 producers and 4 consumers on 5k topic + +topics: 5000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 100000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/5k-topic-1kb-4p-4c-2000k.yaml b/workloads/5k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..7c1672926 --- /dev/null +++ b/workloads/5k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 5k topic + +topics: 5000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/5k-topic-1kb-4p-4c-500k.yaml b/workloads/5k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..30e1c80d3 --- /dev/null +++ b/workloads/5k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 5k topic + +topics: 5000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/600k-topic-1kb-4p-4c-2000k.yaml b/workloads/600k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..495d39936 --- /dev/null +++ b/workloads/600k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 600k topic + +topics: 600000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/600k-topic-1kb-4p-4c-600k.yaml b/workloads/600k-topic-1kb-4p-4c-600k.yaml new file mode 100644 index 000000000..9e7231d3a --- /dev/null +++ b/workloads/600k-topic-1kb-4p-4c-600k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 600k topic + +topics: 600000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/700k-topic-1kb-4p-4c-2000k.yaml b/workloads/700k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..e404145f4 --- /dev/null +++ b/workloads/700k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 700k topic + +topics: 700000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/700k-topic-1kb-4p-4c-500k.yaml b/workloads/700k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..d3a44cef9 --- /dev/null +++ b/workloads/700k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 700k topic + +topics: 700000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/800k-topic-1kb-4p-4c-2000k.yaml b/workloads/800k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..a98dcbec0 --- /dev/null +++ b/workloads/800k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 800k topic + +topics: 800000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/800k-topic-1kb-4p-4c-500k.yaml b/workloads/800k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..dfae1b720 --- /dev/null +++ b/workloads/800k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 800k topic + +topics: 800000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/900k-topic-1kb-4p-4c-2000k.yaml b/workloads/900k-topic-1kb-4p-4c-2000k.yaml new file mode 100644 index 000000000..c5674a385 --- /dev/null +++ b/workloads/900k-topic-1kb-4p-4c-2000k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 2000k rate 4 producers and 4 consumers on 900k topic + +topics: 900000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 2000000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/900k-topic-1kb-4p-4c-500k.yaml b/workloads/900k-topic-1kb-4p-4c-500k.yaml new file mode 100644 index 000000000..4c5ec487e --- /dev/null +++ b/workloads/900k-topic-1kb-4p-4c-500k.yaml @@ -0,0 +1,33 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: 500k rate 4 producers and 4 consumers on 900k topic + +topics: 900000 +partitionsPerTopic: 1 + +messageSize: 1024 +useRandomizedPayloads: true +randomBytesRatio: 0.5 +randomizedPayloadPoolSize: 1000 + +subscriptionsPerTopic: 1 +consumerPerSubscription: 4 +producersPerTopic: 4 + +# Discover max-sustainable rate +producerRate: 500000 + +consumerBacklogSizeGB: 0 +testDurationMinutes: 5 \ No newline at end of file diff --git a/workloads/backlog-1-topic-1-partition-1kb.yaml b/workloads/backlog-1-topic-1-partition-1kb.yaml index 925ccaf8f..be1638ed1 100644 --- a/workloads/backlog-1-topic-1-partition-1kb.yaml +++ b/workloads/backlog-1-topic-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 producer / 1 consumers on 1 topic diff --git a/workloads/backlog-1-topic-16-partitions-1kb.yaml b/workloads/backlog-1-topic-16-partitions-1kb.yaml index 11fce285d..d78180a07 100644 --- a/workloads/backlog-1-topic-16-partitions-1kb.yaml +++ b/workloads/backlog-1-topic-16-partitions-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: 1 producer / 1 consumers on 1 topic diff --git a/workloads/max-rate-1-topic-1-partition-1p-1c-100b.yaml b/workloads/max-rate-1-topic-1-partition-1p-1c-100b.yaml index 8ec41c45c..15ae9a5ea 100644 --- a/workloads/max-rate-1-topic-1-partition-1p-1c-100b.yaml +++ b/workloads/max-rate-1-topic-1-partition-1p-1c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-1-partition-1p-1c-100b diff --git a/workloads/max-rate-1-topic-1-partition-1p-1c-1kb.yaml b/workloads/max-rate-1-topic-1-partition-1p-1c-1kb.yaml index f135a5037..5f730b402 100644 --- a/workloads/max-rate-1-topic-1-partition-1p-1c-1kb.yaml +++ b/workloads/max-rate-1-topic-1-partition-1p-1c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-1-partition-1p-1c-1kb diff --git a/workloads/max-rate-1-topic-1-partition-1p-1c-64kb.yaml b/workloads/max-rate-1-topic-1-partition-1p-1c-64kb.yaml index 0438461fe..2b4f541ac 100644 --- a/workloads/max-rate-1-topic-1-partition-1p-1c-64kb.yaml +++ b/workloads/max-rate-1-topic-1-partition-1p-1c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-1-partition-1p-1c-64kb diff --git a/workloads/max-rate-1-topic-1-partition-4p-1c-1kb.yaml b/workloads/max-rate-1-topic-1-partition-4p-1c-1kb.yaml index 166ece735..2e0dbc1a1 100644 --- a/workloads/max-rate-1-topic-1-partition-4p-1c-1kb.yaml +++ b/workloads/max-rate-1-topic-1-partition-4p-1c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-1-partition-4p-1c-1kb diff --git a/workloads/max-rate-1-topic-10-partitions-10p-10c-100b.yaml b/workloads/max-rate-1-topic-10-partitions-10p-10c-100b.yaml index b1b80f084..b12af94a3 100644 --- a/workloads/max-rate-1-topic-10-partitions-10p-10c-100b.yaml +++ b/workloads/max-rate-1-topic-10-partitions-10p-10c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-10-partitions-10p-10c-100b diff --git a/workloads/max-rate-1-topic-10-partitions-10p-10c-1kb.yaml b/workloads/max-rate-1-topic-10-partitions-10p-10c-1kb.yaml index 78393cc6e..fac203b03 100644 --- a/workloads/max-rate-1-topic-10-partitions-10p-10c-1kb.yaml +++ b/workloads/max-rate-1-topic-10-partitions-10p-10c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-10-partitions-10p-10c-1kb diff --git a/workloads/max-rate-1-topic-10-partitions-10p-10c-64kb.yaml b/workloads/max-rate-1-topic-10-partitions-10p-10c-64kb.yaml index 3e383ab82..546756561 100644 --- a/workloads/max-rate-1-topic-10-partitions-10p-10c-64kb.yaml +++ b/workloads/max-rate-1-topic-10-partitions-10p-10c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-10-partitions-10p-10c-64kb diff --git a/workloads/max-rate-1-topic-10-partitions-1p-1c-100b.yaml b/workloads/max-rate-1-topic-10-partitions-1p-1c-100b.yaml index 8e3aa34e0..0130a8407 100644 --- a/workloads/max-rate-1-topic-10-partitions-1p-1c-100b.yaml +++ b/workloads/max-rate-1-topic-10-partitions-1p-1c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-1p-1c-100b diff --git a/workloads/max-rate-1-topic-10-partitions-1p-1c-1kb.yaml b/workloads/max-rate-1-topic-10-partitions-1p-1c-1kb.yaml index 59f59484a..f204d6874 100644 --- a/workloads/max-rate-1-topic-10-partitions-1p-1c-1kb.yaml +++ b/workloads/max-rate-1-topic-10-partitions-1p-1c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-1p-1c-1kb diff --git a/workloads/max-rate-1-topic-10-partitions-1p-1c-64kb.yaml b/workloads/max-rate-1-topic-10-partitions-1p-1c-64kb.yaml index e729b67ba..bc41c414b 100644 --- a/workloads/max-rate-1-topic-10-partitions-1p-1c-64kb.yaml +++ b/workloads/max-rate-1-topic-10-partitions-1p-1c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-1p-1c-64kb diff --git a/workloads/max-rate-1-topic-100-partitions-100b.yaml b/workloads/max-rate-1-topic-100-partitions-100b.yaml index 4920c4f09..79e29a4f1 100644 --- a/workloads/max-rate-1-topic-100-partitions-100b.yaml +++ b/workloads/max-rate-1-topic-100-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Max rate 1 producer on 1 topic / 100 partition / 100 bytes diff --git a/workloads/max-rate-1-topic-100-partitions-100p-100c-100b.yaml b/workloads/max-rate-1-topic-100-partitions-100p-100c-100b.yaml index a027e5644..d7a390bf3 100644 --- a/workloads/max-rate-1-topic-100-partitions-100p-100c-100b.yaml +++ b/workloads/max-rate-1-topic-100-partitions-100p-100c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-100p-100c-100b diff --git a/workloads/max-rate-1-topic-100-partitions-100p-100c-1kb.yaml b/workloads/max-rate-1-topic-100-partitions-100p-100c-1kb.yaml index 3c2861341..d9bc894cd 100644 --- a/workloads/max-rate-1-topic-100-partitions-100p-100c-1kb.yaml +++ b/workloads/max-rate-1-topic-100-partitions-100p-100c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-100p-100c-1kb diff --git a/workloads/max-rate-1-topic-100-partitions-100p-100c-64kb.yaml b/workloads/max-rate-1-topic-100-partitions-100p-100c-64kb.yaml index f4dde89bc..f70b1341a 100644 --- a/workloads/max-rate-1-topic-100-partitions-100p-100c-64kb.yaml +++ b/workloads/max-rate-1-topic-100-partitions-100p-100c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-100p-100c-64kb diff --git a/workloads/max-rate-1-topic-100-partitions-1kb.yaml b/workloads/max-rate-1-topic-100-partitions-1kb.yaml index 1e350d6d9..b176f6da0 100644 --- a/workloads/max-rate-1-topic-100-partitions-1kb.yaml +++ b/workloads/max-rate-1-topic-100-partitions-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Max rate 1 producer on 1 topic / 100 partition diff --git a/workloads/max-rate-1-topic-100-partitions-1p-1c-100b.yaml b/workloads/max-rate-1-topic-100-partitions-1p-1c-100b.yaml index b54129837..f4ee12735 100644 --- a/workloads/max-rate-1-topic-100-partitions-1p-1c-100b.yaml +++ b/workloads/max-rate-1-topic-100-partitions-1p-1c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-1p-1c-100b diff --git a/workloads/max-rate-1-topic-100-partitions-1p-1c-1kb.yaml b/workloads/max-rate-1-topic-100-partitions-1p-1c-1kb.yaml index 902fa91bb..9b3b19484 100644 --- a/workloads/max-rate-1-topic-100-partitions-1p-1c-1kb.yaml +++ b/workloads/max-rate-1-topic-100-partitions-1p-1c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-100-partitions-1p-1c-1kb diff --git a/workloads/max-rate-1-topic-16-partitions-100b.yaml b/workloads/max-rate-1-topic-16-partitions-100b.yaml index 31e36ac88..f5764c251 100644 --- a/workloads/max-rate-1-topic-16-partitions-100b.yaml +++ b/workloads/max-rate-1-topic-16-partitions-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Max rate 1 producer on 1 topic / 16 partitions diff --git a/workloads/max-rate-1-topic-16-partitions-1kb.yaml b/workloads/max-rate-1-topic-16-partitions-1kb.yaml index 83ece0c62..af5a78fbf 100644 --- a/workloads/max-rate-1-topic-16-partitions-1kb.yaml +++ b/workloads/max-rate-1-topic-16-partitions-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: Max rate 1 producer on 1 topic / 1 partition diff --git a/workloads/max-rate-1-topic-20-partitions-20p-20c-100b.yaml b/workloads/max-rate-1-topic-20-partitions-20p-20c-100b.yaml index 3fbb3053c..e5796028a 100644 --- a/workloads/max-rate-1-topic-20-partitions-20p-20c-100b.yaml +++ b/workloads/max-rate-1-topic-20-partitions-20p-20c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-20-partitions-20p-20c-100b diff --git a/workloads/max-rate-1-topic-20-partitions-20p-20c-1kb.yaml b/workloads/max-rate-1-topic-20-partitions-20p-20c-1kb.yaml index dc4b402fd..754422b74 100644 --- a/workloads/max-rate-1-topic-20-partitions-20p-20c-1kb.yaml +++ b/workloads/max-rate-1-topic-20-partitions-20p-20c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-20-partitions-20p-20c-1kb diff --git a/workloads/max-rate-1-topic-20-partitions-20p-20c-64kb.yaml b/workloads/max-rate-1-topic-20-partitions-20p-20c-64kb.yaml index 3592bb896..82792e2ab 100644 --- a/workloads/max-rate-1-topic-20-partitions-20p-20c-64kb.yaml +++ b/workloads/max-rate-1-topic-20-partitions-20p-20c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-20-partitions-20p-20c-64kb diff --git a/workloads/max-rate-1-topic-30-partitions-30p-30c-100b.yaml b/workloads/max-rate-1-topic-30-partitions-30p-30c-100b.yaml index 3ee40d0bf..81d7744b8 100644 --- a/workloads/max-rate-1-topic-30-partitions-30p-30c-100b.yaml +++ b/workloads/max-rate-1-topic-30-partitions-30p-30c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-30-partitions-30p-30c-100b diff --git a/workloads/max-rate-1-topic-30-partitions-30p-30c-1kb.yaml b/workloads/max-rate-1-topic-30-partitions-30p-30c-1kb.yaml index 79e036626..f4e46225a 100644 --- a/workloads/max-rate-1-topic-30-partitions-30p-30c-1kb.yaml +++ b/workloads/max-rate-1-topic-30-partitions-30p-30c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-30-partitions-30p-30c-1kb diff --git a/workloads/max-rate-1-topic-40-partitions-40p-40c-100b.yaml b/workloads/max-rate-1-topic-40-partitions-40p-40c-100b.yaml index cc647d349..ce99582af 100644 --- a/workloads/max-rate-1-topic-40-partitions-40p-40c-100b.yaml +++ b/workloads/max-rate-1-topic-40-partitions-40p-40c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-40-partitions-40p-40c-100b diff --git a/workloads/max-rate-1-topic-40-partitions-40p-40c-1kb.yaml b/workloads/max-rate-1-topic-40-partitions-40p-40c-1kb.yaml index 86a7cecb1..c31ab6882 100644 --- a/workloads/max-rate-1-topic-40-partitions-40p-40c-1kb.yaml +++ b/workloads/max-rate-1-topic-40-partitions-40p-40c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-40-partitions-40p-40c-1kb diff --git a/workloads/max-rate-1-topic-40-partitions-40p-40c-64kb.yaml b/workloads/max-rate-1-topic-40-partitions-40p-40c-64kb.yaml index 42fea3c31..215d7b9cd 100644 --- a/workloads/max-rate-1-topic-40-partitions-40p-40c-64kb.yaml +++ b/workloads/max-rate-1-topic-40-partitions-40p-40c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-40-partitions-40p-40c-64kb diff --git a/workloads/max-rate-1-topic-50-partitions-50p-50c-100b.yaml b/workloads/max-rate-1-topic-50-partitions-50p-50c-100b.yaml index 16fb69222..1a84a34b4 100644 --- a/workloads/max-rate-1-topic-50-partitions-50p-50c-100b.yaml +++ b/workloads/max-rate-1-topic-50-partitions-50p-50c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-50-partitions-50p-50c-100b diff --git a/workloads/max-rate-1-topic-50-partitions-50p-50c-1kb.yaml b/workloads/max-rate-1-topic-50-partitions-50p-50c-1kb.yaml index 332c3ca9d..76c63c7bb 100644 --- a/workloads/max-rate-1-topic-50-partitions-50p-50c-1kb.yaml +++ b/workloads/max-rate-1-topic-50-partitions-50p-50c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-50-partitions-50p-50c-1kb diff --git a/workloads/max-rate-1-topic-60-partitions-60p-60c-100b.yaml b/workloads/max-rate-1-topic-60-partitions-60p-60c-100b.yaml index 0b1530a67..40ed6a9db 100644 --- a/workloads/max-rate-1-topic-60-partitions-60p-60c-100b.yaml +++ b/workloads/max-rate-1-topic-60-partitions-60p-60c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-60-partitions-60p-60c-100b diff --git a/workloads/max-rate-1-topic-60-partitions-60p-60c-1kb.yaml b/workloads/max-rate-1-topic-60-partitions-60p-60c-1kb.yaml index f26063443..4cac48e95 100644 --- a/workloads/max-rate-1-topic-60-partitions-60p-60c-1kb.yaml +++ b/workloads/max-rate-1-topic-60-partitions-60p-60c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-60-partitions-60p-60c-1kb diff --git a/workloads/max-rate-1-topic-60-partitions-60p-60c-64kb.yaml b/workloads/max-rate-1-topic-60-partitions-60p-60c-64kb.yaml index ec37f7252..2a37f1324 100644 --- a/workloads/max-rate-1-topic-60-partitions-60p-60c-64kb.yaml +++ b/workloads/max-rate-1-topic-60-partitions-60p-60c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-60-partitions-60p-60c-64kb diff --git a/workloads/max-rate-1-topic-70-partitions-70p-70c-100b.yaml b/workloads/max-rate-1-topic-70-partitions-70p-70c-100b.yaml index d96f09fb2..296d48117 100644 --- a/workloads/max-rate-1-topic-70-partitions-70p-70c-100b.yaml +++ b/workloads/max-rate-1-topic-70-partitions-70p-70c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-70-partitions-70p-70c-100b diff --git a/workloads/max-rate-1-topic-70-partitions-70p-70c-1kb.yaml b/workloads/max-rate-1-topic-70-partitions-70p-70c-1kb.yaml index 4870820f8..220abae74 100644 --- a/workloads/max-rate-1-topic-70-partitions-70p-70c-1kb.yaml +++ b/workloads/max-rate-1-topic-70-partitions-70p-70c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-70-partitions-70p-70c-1kb diff --git a/workloads/max-rate-1-topic-80-partitions-80p-80c-100b.yaml b/workloads/max-rate-1-topic-80-partitions-80p-80c-100b.yaml index 585091a02..7a5288c41 100644 --- a/workloads/max-rate-1-topic-80-partitions-80p-80c-100b.yaml +++ b/workloads/max-rate-1-topic-80-partitions-80p-80c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-80-partitions-80p-80c-100b diff --git a/workloads/max-rate-1-topic-80-partitions-80p-80c-1kb.yaml b/workloads/max-rate-1-topic-80-partitions-80p-80c-1kb.yaml index 497245402..640bdc0d6 100644 --- a/workloads/max-rate-1-topic-80-partitions-80p-80c-1kb.yaml +++ b/workloads/max-rate-1-topic-80-partitions-80p-80c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-80-partitions-80p-80c-1kb diff --git a/workloads/max-rate-1-topic-80-partitions-80p-80c-64kb.yaml b/workloads/max-rate-1-topic-80-partitions-80p-80c-64kb.yaml index dba8495bd..bb176749c 100644 --- a/workloads/max-rate-1-topic-80-partitions-80p-80c-64kb.yaml +++ b/workloads/max-rate-1-topic-80-partitions-80p-80c-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-80-partitions-80p-80c-64kb diff --git a/workloads/max-rate-1-topic-90-partitions-90p-90c-100b.yaml b/workloads/max-rate-1-topic-90-partitions-90p-90c-100b.yaml index ef6f31ee4..c3b3a2dbd 100644 --- a/workloads/max-rate-1-topic-90-partitions-90p-90c-100b.yaml +++ b/workloads/max-rate-1-topic-90-partitions-90p-90c-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-90-partitions-90p-90c-100b diff --git a/workloads/max-rate-1-topic-90-partitions-90p-90c-1kb.yaml b/workloads/max-rate-1-topic-90-partitions-90p-90c-1kb.yaml index 424fa7f87..cd49480b2 100644 --- a/workloads/max-rate-1-topic-90-partitions-90p-90c-1kb.yaml +++ b/workloads/max-rate-1-topic-90-partitions-90p-90c-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-1-topic-90-partitions-90p-90c-1kb diff --git a/workloads/max-rate-10-topics-1-partition-100b.yaml b/workloads/max-rate-10-topics-1-partition-100b.yaml index dee18356c..c8891dcf1 100644 --- a/workloads/max-rate-10-topics-1-partition-100b.yaml +++ b/workloads/max-rate-10-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-10-topics-1-partition-100b diff --git a/workloads/max-rate-10-topics-1-partition-1kb.yaml b/workloads/max-rate-10-topics-1-partition-1kb.yaml index 4f3b905d6..6add8303a 100644 --- a/workloads/max-rate-10-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-10-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-10-topics-1-partition-1kb diff --git a/workloads/max-rate-10-topics-1-partition-64kb.yaml b/workloads/max-rate-10-topics-1-partition-64kb.yaml index 5dfbd0b90..092b92b50 100644 --- a/workloads/max-rate-10-topics-1-partition-64kb.yaml +++ b/workloads/max-rate-10-topics-1-partition-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-10-topics-1-partition-64kb diff --git a/workloads/max-rate-100-topics-1-partition-100b.yaml b/workloads/max-rate-100-topics-1-partition-100b.yaml index 2db091839..9c89d3f06 100644 --- a/workloads/max-rate-100-topics-1-partition-100b.yaml +++ b/workloads/max-rate-100-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-100-topics-1-partition-100b diff --git a/workloads/max-rate-100-topics-1-partition-1kb.yaml b/workloads/max-rate-100-topics-1-partition-1kb.yaml index f47884325..e236607c3 100644 --- a/workloads/max-rate-100-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-100-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-100-topics-1-partition-1kb diff --git a/workloads/max-rate-100-topics-1-partition-64kb.yaml b/workloads/max-rate-100-topics-1-partition-64kb.yaml index 63f868883..510c7dee5 100644 --- a/workloads/max-rate-100-topics-1-partition-64kb.yaml +++ b/workloads/max-rate-100-topics-1-partition-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-100-topics-1-partition-64kb diff --git a/workloads/max-rate-20-topics-1-partition-100b.yaml b/workloads/max-rate-20-topics-1-partition-100b.yaml index f77913e73..92d6912a0 100644 --- a/workloads/max-rate-20-topics-1-partition-100b.yaml +++ b/workloads/max-rate-20-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-20-topics-1-partition-100b diff --git a/workloads/max-rate-20-topics-1-partition-1kb.yaml b/workloads/max-rate-20-topics-1-partition-1kb.yaml index 18f9a9f11..4aa53b53b 100644 --- a/workloads/max-rate-20-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-20-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-20-topics-1-partition-1kb diff --git a/workloads/max-rate-20-topics-1-partition-64kb.yaml b/workloads/max-rate-20-topics-1-partition-64kb.yaml index c858dfeda..2e563175a 100644 --- a/workloads/max-rate-20-topics-1-partition-64kb.yaml +++ b/workloads/max-rate-20-topics-1-partition-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-20-topics-1-partition-64kb diff --git a/workloads/max-rate-30-topics-1-partition-100b.yaml b/workloads/max-rate-30-topics-1-partition-100b.yaml index b95a6dcef..f02fb7bed 100644 --- a/workloads/max-rate-30-topics-1-partition-100b.yaml +++ b/workloads/max-rate-30-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-30-topics-1-partition-100b diff --git a/workloads/max-rate-30-topics-1-partition-1kb.yaml b/workloads/max-rate-30-topics-1-partition-1kb.yaml index 87d84f57a..0aab511eb 100644 --- a/workloads/max-rate-30-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-30-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-30-topics-1-partition-1kb diff --git a/workloads/max-rate-40-topics-1-partition-100b.yaml b/workloads/max-rate-40-topics-1-partition-100b.yaml index 79e56614e..55c449ac3 100644 --- a/workloads/max-rate-40-topics-1-partition-100b.yaml +++ b/workloads/max-rate-40-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-40-topics-1-partition-100b diff --git a/workloads/max-rate-40-topics-1-partition-1kb.yaml b/workloads/max-rate-40-topics-1-partition-1kb.yaml index 44cbbbb48..a247d70a2 100644 --- a/workloads/max-rate-40-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-40-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-40-topics-1-partition-1kb diff --git a/workloads/max-rate-40-topics-1-partition-64kb.yaml b/workloads/max-rate-40-topics-1-partition-64kb.yaml index 9db67a0b1..dd8ec9724 100644 --- a/workloads/max-rate-40-topics-1-partition-64kb.yaml +++ b/workloads/max-rate-40-topics-1-partition-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-40-topics-1-partition-64kb diff --git a/workloads/max-rate-50-topics-1-partition-100b.yaml b/workloads/max-rate-50-topics-1-partition-100b.yaml index 9b9df80fb..0980d52f9 100644 --- a/workloads/max-rate-50-topics-1-partition-100b.yaml +++ b/workloads/max-rate-50-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-50-topics-1-partition-100b diff --git a/workloads/max-rate-50-topics-1-partition-1kb.yaml b/workloads/max-rate-50-topics-1-partition-1kb.yaml index de3d02d68..43de6a3f5 100644 --- a/workloads/max-rate-50-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-50-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-50-topics-1-partition-1kb diff --git a/workloads/max-rate-60-topics-1-partition-100b.yaml b/workloads/max-rate-60-topics-1-partition-100b.yaml index 0bd4ded1d..db87c08ad 100644 --- a/workloads/max-rate-60-topics-1-partition-100b.yaml +++ b/workloads/max-rate-60-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-60-topics-1-partition-100b diff --git a/workloads/max-rate-60-topics-1-partition-1kb.yaml b/workloads/max-rate-60-topics-1-partition-1kb.yaml index d22b2622d..7066fc38c 100644 --- a/workloads/max-rate-60-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-60-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-60-topics-1-partition-1kb diff --git a/workloads/max-rate-60-topics-1-partition-64kb.yaml b/workloads/max-rate-60-topics-1-partition-64kb.yaml index 8344e2909..02c6af28c 100644 --- a/workloads/max-rate-60-topics-1-partition-64kb.yaml +++ b/workloads/max-rate-60-topics-1-partition-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-60-topics-1-partition-64kb diff --git a/workloads/max-rate-70-topics-1-partition-100b.yaml b/workloads/max-rate-70-topics-1-partition-100b.yaml index 754523ac2..a1689162e 100644 --- a/workloads/max-rate-70-topics-1-partition-100b.yaml +++ b/workloads/max-rate-70-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-70-topics-1-partition-100b diff --git a/workloads/max-rate-70-topics-1-partition-1kb.yaml b/workloads/max-rate-70-topics-1-partition-1kb.yaml index 0deb78b30..d51208c6a 100644 --- a/workloads/max-rate-70-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-70-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-70-topics-1-partition-1kb diff --git a/workloads/max-rate-80-topics-1-partition-100b.yaml b/workloads/max-rate-80-topics-1-partition-100b.yaml index c59fe85a7..9de875843 100644 --- a/workloads/max-rate-80-topics-1-partition-100b.yaml +++ b/workloads/max-rate-80-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-80-topics-1-partition-100b diff --git a/workloads/max-rate-80-topics-1-partition-1kb.yaml b/workloads/max-rate-80-topics-1-partition-1kb.yaml index 77123de89..1ff47d2e7 100644 --- a/workloads/max-rate-80-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-80-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-80-topics-1-partition-1kb diff --git a/workloads/max-rate-80-topics-1-partition-64kb.yaml b/workloads/max-rate-80-topics-1-partition-64kb.yaml index 8a19750b7..a79d7ea6d 100644 --- a/workloads/max-rate-80-topics-1-partition-64kb.yaml +++ b/workloads/max-rate-80-topics-1-partition-64kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-80-topics-1-partition-64kb diff --git a/workloads/max-rate-90-topics-1-partition-100b.yaml b/workloads/max-rate-90-topics-1-partition-100b.yaml index 68b95cd7f..5cef920f0 100644 --- a/workloads/max-rate-90-topics-1-partition-100b.yaml +++ b/workloads/max-rate-90-topics-1-partition-100b.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-90-topics-1-partition-100b diff --git a/workloads/max-rate-90-topics-1-partition-1kb.yaml b/workloads/max-rate-90-topics-1-partition-1kb.yaml index 360f2cf0e..3d123fd18 100644 --- a/workloads/max-rate-90-topics-1-partition-1kb.yaml +++ b/workloads/max-rate-90-topics-1-partition-1kb.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # name: max-rate-90-topics-1-partition-1kb diff --git a/workloads/simple-workload.yaml b/workloads/simple-workload.yaml index f3f17fbec..bf3a5ea97 100644 --- a/workloads/simple-workload.yaml +++ b/workloads/simple-workload.yaml @@ -1,20 +1,15 @@ # -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. #