You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by zh...@apache.org on 2019/07/09 13:59:07 UTC
[servicecomb-pack] 01/02: SCB-1321 Add alpha benchmark tools
This is an automated email from the ASF dual-hosted git repository.
zhanglei pushed a commit to branch SCB-1321
in repository https://gitbox.apache.org/repos/asf/servicecomb-pack.git
commit 7392ae3fac841e3f6af9f0fa554e3ba24fe0129d
Author: Lei Zhang <zh...@apache.org>
AuthorDate: Tue Jul 9 21:46:29 2019 +0800
SCB-1321 Add alpha benchmark tools
---
alpha/alpha-benchmark/pom.xml | 88 +++++++++++
.../pack/alpha/benchmark/Application.java | 97 ++++++++++++
.../pack/alpha/benchmark/BenchmarkMetrics.java | 102 +++++++++++++
.../pack/alpha/benchmark/SagaEventBenchmark.java | 170 +++++++++++++++++++++
.../src/main/resources/application.yaml | 28 ++++
alpha/pom.xml | 1 +
6 files changed, 486 insertions(+)
diff --git a/alpha/alpha-benchmark/pom.xml b/alpha/alpha-benchmark/pom.xml
new file mode 100644
index 0000000..fcc3277
--- /dev/null
+++ b/alpha/alpha-benchmark/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>alpha</artifactId>
+ <groupId>org.apache.servicecomb.pack</groupId>
+ <version>0.5.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>alpha-benchmark</artifactId>
+ <name>Pack::Alpha::Benchmark</name>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>${spring.boot.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb.pack</groupId>
+ <artifactId>alpha-fsm</artifactId>
+ <exclusions>
+ <exclusion>
+ <artifactId>log4j-slf4j-impl</artifactId>
+ <groupId>org.apache.logging.log4j</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb.pack</groupId>
+ <artifactId>omega-spring-starter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb.pack</groupId>
+ <artifactId>omega-connector-grpc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.github.seanyinx</groupId>
+ <artifactId>unit-scaffolding</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- mixin plugin configurations declared in another pom,
+ just like importing dependencies managed in another pom -->
+ <plugin>
+ <groupId>com.github.odavid.maven.plugins</groupId>
+ <artifactId>mixin-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/Application.java b/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/Application.java
new file mode 100644
index 0000000..0a74910
--- /dev/null
+++ b/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/Application.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this 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 org.apache.servicecomb.pack.alpha.benchmark;
+
+import org.apache.servicecomb.pack.omega.transaction.SagaMessageSender;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application implements CommandLineRunner {
+
+ @Autowired
+ SagaEventBenchmark sagaEventBenchmark;
+
+ @Autowired(required = false)
+ SagaMessageSender sender;
+
+ @Value("${alpha.cluster.address}")
+ String address;
+
+ @Value("${n:0}")
+ int requests;
+
+ @Value("${c:1}")
+ int concurrency;
+
+ public static void main(String[] args) {
+ boolean hasAlphaAddress = false;
+ for(String arg : args){
+ if(arg.startsWith("--alpha.cluster.address")){
+ hasAlphaAddress = true;
+ }
+ }
+ if(!hasAlphaAddress){
+ printHelp();
+ System.exit(0);
+ }
+ SpringApplication.run(Application.class, args);
+ }
+
+ @Override
+ public void run(String... args) {
+
+ try {
+ if (checkParamter()) {
+ sagaEventBenchmark.send(requests, concurrency);
+ } else {
+ printHelp();
+ }
+ } finally {
+ sender.onDisconnected();
+ System.exit(0);
+ }
+
+ }
+
+ private boolean checkParamter() {
+ if (address == null) {
+ return false;
+ } else {
+ if (requests == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private static void printHelp() {
+ System.out.println("\nalpha-benchmark: wrong number of arguments");
+ System.out.println(
+ "Usage: java -jar alpha-benchmark-0.5.0-SNAPSHOT-exec.jar --alpha.cluster.address=0.0.0.0:8080 --n=1000 --c=1");
+ System.out.println("Options are:");
+ System.out.println(
+ String.format("%-5s %-15s %-25s", " --n", "requests", "Number of requests to perform"));
+ System.out.println(String.format("%-5s %-15s %-25s", " --c", "concurrency",
+ "Number of multiple requests to make at a time"));
+ }
+}
diff --git a/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/BenchmarkMetrics.java b/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/BenchmarkMetrics.java
new file mode 100644
index 0000000..e15a50d
--- /dev/null
+++ b/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/BenchmarkMetrics.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this 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 org.apache.servicecomb.pack.alpha.benchmark;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class BenchmarkMetrics {
+
+ private int requests;
+ private AtomicInteger completeRequests = new AtomicInteger();
+ private AtomicInteger failedRequests = new AtomicInteger();
+ private int concurrency;
+ private long timeTaken;
+ private List<Long> transactionTime = Collections.synchronizedList(new ArrayList());
+
+ private int beforeProgress;
+
+ public void setRequests(int requests) {
+ this.requests = requests;
+ }
+
+ //并发用户数
+ public int getConcurrency() {
+ return concurrency;
+ }
+
+ public void setConcurrency(int concurrency) {
+ this.concurrency = concurrency;
+ }
+
+ public void addTransactionTime(long time) {
+ transactionTime.add(time);
+ }
+
+ public long getTimeTaken() {
+ return timeTaken / 1000;
+ }
+
+ public void setTimeTaken(long timeTaken) {
+ this.timeTaken = timeTaken;
+ }
+
+ public int getCompleteRequests() {
+ return completeRequests.get();
+ }
+
+ public int getFailedRequests() {
+ return failedRequests.get();
+ }
+
+ //总请求数量
+ public void completeRequestsIncrement() {
+ completeRequests.incrementAndGet();
+ printProgress();
+ }
+
+ //失败的请求数量
+ public void failedRequestsIncrement() {
+ failedRequests.incrementAndGet();
+ printProgress();
+ }
+
+ //吞吐率
+ public long getRequestsPerSecond() {
+ return this.completeRequests.get() / (timeTaken / 1000);
+ }
+
+ //用户平均请求等待时间
+ public long getTimePerRequest() {
+ return this.timeTaken / (completeRequests.get() / concurrency);
+ }
+
+ public List<Long> getTransactionTime() {
+ return transactionTime;
+ }
+
+ private void printProgress() {
+ int progress = (int) ((float) completeRequests.get() / (float) requests * 100);
+ if (beforeProgress != progress) {
+ System.out.print("░");
+ beforeProgress = progress;
+ }
+ }
+}
diff --git a/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/SagaEventBenchmark.java b/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/SagaEventBenchmark.java
new file mode 100644
index 0000000..47e62aa
--- /dev/null
+++ b/alpha/alpha-benchmark/src/main/java/org/apache/servicecomb/pack/alpha/benchmark/SagaEventBenchmark.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this 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 org.apache.servicecomb.pack.alpha.benchmark;
+
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.OptionalDouble;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.servicecomb.pack.common.EventType;
+import org.apache.servicecomb.pack.omega.transaction.SagaMessageSender;
+import org.apache.servicecomb.pack.omega.transaction.TxEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SagaEventBenchmark {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ @Autowired(required = false)
+ SagaMessageSender sender;
+
+ BenchmarkMetrics metrics = new BenchmarkMetrics();
+
+ public void send(int requests, int concurrency) {
+ System.out.print("Benchmarking ");
+ metrics.setRequests(requests);
+ metrics.setConcurrency(concurrency);
+ long s = System.currentTimeMillis();
+ CountDownLatch begin = new CountDownLatch(1);
+ CountDownLatch end = new CountDownLatch(concurrency);
+ begin.countDown();
+ for (int i = 0; i < concurrency; i++) {
+ Execute execute = new Execute(sender, requests / concurrency, begin, end, metrics);
+ new Thread(execute).start();
+ }
+ try {
+ end.await();
+ long e = System.currentTimeMillis();
+ metrics.setTimeTaken(e - s);
+ System.out.println("\n");
+ System.out.println(String.format("%-25s %s", "Concurrency Level", metrics.getConcurrency()));
+ System.out.println(
+ String.format("%-25s %s", "Time taken for tests", metrics.getTimeTaken() + " seconds"));
+ System.out
+ .println(String.format("%-25s %s", "Complete requests", metrics.getCompleteRequests()));
+ System.out.println(String.format("%-25s %s", "Failed requests", metrics.getFailedRequests()));
+ System.out.println(String
+ .format("%-25s %s", "Requests per second", metrics.getRequestsPerSecond() + " [#/sec]"));
+ System.out.println(
+ String.format("%-25s %s", "Time per request", metrics.getTimePerRequest() + " [ms]"));
+ System.out.println();
+ System.out.println("Percentage of the requests served within a certain time (ms)");
+
+ int size = metrics.getTransactionTime().size();
+ int percentage = 50;
+ for (int i = 0; i <= 5; i++) {
+ float peek = size * ((float) percentage / 100);
+ System.out.println(String.format("%-5s %.2f", percentage + "%", getAverage(
+ metrics.getTransactionTime().subList(0, (int) peek)).getAsDouble()));
+ percentage = percentage + 10;
+ }
+
+ } catch (InterruptedException e) {
+ LOG.error(e.getMessage(), e);
+ }
+ LOG.info("OK");
+ }
+
+ private OptionalDouble getAverage(List<Long> times) {
+ try{
+ return times.stream().mapToLong(Long::longValue).average();
+ }catch (Exception e){
+
+ throw e;
+ }
+ }
+
+ private class Execute implements Runnable {
+
+ SagaMessageSender sender;
+ CountDownLatch begin;
+ CountDownLatch end;
+ int requests;
+
+ public Execute(SagaMessageSender sender, int requests, CountDownLatch begin,
+ CountDownLatch end, BenchmarkMetrics metrics) {
+ this.sender = sender;
+ this.requests = requests;
+ this.begin = begin;
+ this.end = end;
+ }
+
+ @Override
+ public void run() {
+ try {
+ begin.await();
+ for (int i = 0; i < requests; i++) {
+ metrics.completeRequestsIncrement();
+ long s = System.currentTimeMillis();
+ final String globalTxId = UUID.randomUUID().toString();
+ final String localTxId_1 = UUID.randomUUID().toString();
+ final String localTxId_2 = UUID.randomUUID().toString();
+ final String localTxId_3 = UUID.randomUUID().toString();
+ try {
+ sagaSuccessfulEvents(globalTxId, localTxId_1, localTxId_2, localTxId_3).stream()
+ .forEach(event -> sender.send(event));
+ } catch (Throwable e) {
+ metrics.failedRequestsIncrement();
+ }finally {
+ long e = System.currentTimeMillis();
+ metrics.addTransactionTime(e - s);
+ }
+ }
+ end.countDown();
+ } catch (InterruptedException e) {
+ LOG.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ public List<TxEvent> sagaSuccessfulEvents(String globalTxId, String localTxId_1,
+ String localTxId_2, String localTxId_3) {
+ List<TxEvent> sagaEvents = new ArrayList<>();
+ sagaEvents.add(
+ new TxEvent(EventType.SagaStartedEvent, globalTxId, globalTxId, globalTxId, "", 0, null,
+ 0));
+ sagaEvents.add(
+ new TxEvent(EventType.TxStartedEvent, globalTxId, localTxId_1, globalTxId, "service a", 0,
+ null, 0));
+ sagaEvents.add(
+ new TxEvent(EventType.TxEndedEvent, globalTxId, localTxId_1, globalTxId, "service a", 0,
+ null, 0));
+ sagaEvents.add(
+ new TxEvent(EventType.TxStartedEvent, globalTxId, localTxId_2, globalTxId, "service b", 0,
+ null, 0));
+ sagaEvents.add(
+ new TxEvent(EventType.TxEndedEvent, globalTxId, localTxId_2, globalTxId, "service b", 0,
+ null, 0));
+ sagaEvents.add(
+ new TxEvent(EventType.TxStartedEvent, globalTxId, localTxId_3, globalTxId, "service c", 0,
+ null, 0));
+ sagaEvents.add(
+ new TxEvent(EventType.TxEndedEvent, globalTxId, localTxId_3, globalTxId, "service c", 0,
+ null, 0));
+ sagaEvents.add(
+ new TxEvent(EventType.SagaEndedEvent, globalTxId, globalTxId, globalTxId, "", 0, null, 0));
+ return sagaEvents;
+ }
+}
diff --git a/alpha/alpha-benchmark/src/main/resources/application.yaml b/alpha/alpha-benchmark/src/main/resources/application.yaml
new file mode 100644
index 0000000..2124ca9
--- /dev/null
+++ b/alpha/alpha-benchmark/src/main/resources/application.yaml
@@ -0,0 +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
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+spring:
+ main:
+ banner-mode: "off"
+ application:
+ name: alpha-benchmark
+
+alpha:
+ cluster:
+ address: localhost:8080
+
+omega:
+ enabled: true
\ No newline at end of file
diff --git a/alpha/pom.xml b/alpha/pom.xml
index 3dfaf13..18ab23e 100644
--- a/alpha/pom.xml
+++ b/alpha/pom.xml
@@ -33,6 +33,7 @@
<modules>
<module>alpha-core</module>
<module>alpha-fsm</module>
+ <module>alpha-benchmark</module>
<module>alpha-spring-boot-compatibility</module>
<module>alpha-spring-cloud-starter-eureka</module>
<module>alpha-spring-cloud-starter-consul</module>