This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 36f75c7168 IGNITE-19151 Add client connections benchmark (#1860)
36f75c7168 is described below
commit 36f75c7168038de2d478f01d4bab1e091267126a
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Wed Mar 29 11:48:46 2023 +0300
IGNITE-19151 Add client connections benchmark (#1860)
---
.../ManyConnectionsBenchmark.cs | 100 +++++++++++++++++++++
.../dotnet/Apache.Ignite.Benchmarks/Program.cs | 7 +-
modules/runner/build.gradle | 9 ++
.../runner/app/PlatformBenchmarkNodeRunner.java | 73 +++++++++++++++
.../runner/app/PlatformTestNodeRunner.java | 60 ++++++++-----
5 files changed, 223 insertions(+), 26 deletions(-)
diff --git
a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/ManyConnectionsBenchmark.cs
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/ManyConnectionsBenchmark.cs
new file mode 100644
index 0000000000..117d034426
--- /dev/null
+++
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/ManyConnectionsBenchmark.cs
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this 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.
+ */
+
+namespace Apache.Ignite.Benchmarks;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using Log;
+
+/// <summary>
+/// Establishes many connections to the server node to see how it affects
server-side performance.
+/// <para />
+/// Requires a running Ignite node started with PlatformBenchmarkNodeRunner:
+/// <code>gradlew :ignite-runner:runnerPlatformBenchmark</code>.
+/// <para />
+/// Results on i9-12900H, .NET SDK 6.0.405, Ubuntu 22.04:
+///
+/// HeartbeatInterval 5 minutes:
+/// 250000 connections established in 00:00:41.0241231.
+/// 250000 GetTable calls in 00:00:16.2082830.
+///
+/// | Connections | JVM Used Heap (MB) |
+/// | ----------- | ------------------ |
+/// | 0 | 155 |
+/// | 10000 | 185 |
+/// | 20000 | 212 |
+/// | 40000 | 265 |
+/// | 80000 | 372 |
+/// | 160000 | 586 |.
+///
+/// HeartbeatInterval 1 second:
+/// 250000 connections established in 00:01:09.8284032.
+/// 250000 GetTable calls in 00:00:51.2001008.
+/// </summary>
+public static class ManyConnectionsBenchmark
+{
+ private const int Connections = 250_000;
+
+ public static async Task RunAsync()
+ {
+ var cfg = new IgniteClientConfiguration
+ {
+ RetryPolicy = new RetryNonePolicy(),
+ Logger = new ConsoleLogger { MinLevel = LogLevel.Warn },
+ HeartbeatInterval = TimeSpan.FromMinutes(5)
+ };
+
+ var clients = new List<IIgniteClient>();
+
+ Console.WriteLine("Establishing connections...");
+ var sw = Stopwatch.StartNew();
+ TimeSpan lastElapsed = default;
+
+ for (int i = 0; i < Connections; i++)
+ {
+ // Use different loopback addresses to avoid running out of ports.
+ var addr = $"127.0.0.{i % 255}:10420";
+
+ cfg.Endpoints.Clear();
+ cfg.Endpoints.Add(addr);
+
+ clients.Add(await IgniteClient.StartAsync(cfg));
+
+ if (sw.Elapsed - lastElapsed > TimeSpan.FromSeconds(2))
+ {
+ lastElapsed = sw.Elapsed;
+ Console.WriteLine($"{i} connections established in
{sw.Elapsed}.");
+ }
+ }
+
+ Console.WriteLine($"{Connections} connections established in
{sw.Elapsed}.");
+ Console.WriteLine("Invoking GetTable...");
+ sw = Stopwatch.StartNew();
+
+ foreach (var client in clients)
+ {
+ await client.Tables.GetTableAsync("t");
+ }
+
+ Console.WriteLine($"{Connections} GetTable calls in {sw.Elapsed}.");
+ Console.WriteLine("Press any key to close connections...");
+ Console.ReadKey();
+ }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Program.cs
b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Program.cs
index 99e1290a76..50b2e2bfb0 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Program.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Benchmarks/Program.cs
@@ -17,13 +17,12 @@
namespace Apache.Ignite.Benchmarks;
-using BenchmarkDotNet.Running;
-using Table;
+using System.Threading.Tasks;
internal static class Program
{
- private static void Main()
+ private static async Task Main()
{
- BenchmarkRunner.Run<TupleGetBenchmarks>();
+ await ManyConnectionsBenchmark.RunAsync();
}
}
diff --git a/modules/runner/build.gradle b/modules/runner/build.gradle
index a5552a8972..33ff65ebbd 100644
--- a/modules/runner/build.gradle
+++ b/modules/runner/build.gradle
@@ -116,6 +116,7 @@ dependencies {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
}
integrationTestImplementation project(':ignite-metastorage')
+ integrationTestImplementation project(':ignite-metrics')
integrationTestImplementation project(':ignite-table')
integrationTestImplementation project(':ignite-transactions')
integrationTestImplementation project(':ignite-code-deployment')
@@ -155,6 +156,14 @@ tasks.register("runnerPlatformTest", JavaExec) {
enableAssertions = true
}
+tasks.register("runnerPlatformBenchmark", JavaExec) {
+ mainClass =
"org.apache.ignite.internal.runner.app.PlatformBenchmarkNodeRunner"
+
+ classpath = sourceSets.integrationTest.runtimeClasspath
+
+ enableAssertions = true
+}
+
integrationTest {
useJUnitPlatform {
if (System.getProperty("sqlTest") != null) {
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformBenchmarkNodeRunner.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformBenchmarkNodeRunner.java
new file mode 100644
index 0000000000..8aa6b2fcfc
--- /dev/null
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformBenchmarkNodeRunner.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this 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.ignite.internal.runner.app;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.client.handler.ClientHandlerMetricSource;
+import org.apache.ignite.internal.testframework.IgniteTestUtils;
+
+/**
+ * Helper class for non-Java platform benchmarks (.NET, C++, Python, ...).
+ */
+public class PlatformBenchmarkNodeRunner {
+ /** Test node name. */
+ private static final String NODE_NAME =
PlatformBenchmarkNodeRunner.class.getCanonicalName();
+
+ /** Nodes bootstrap configuration. */
+ private static final Map<String, String> nodesBootstrapCfg = Map.of(
+ NODE_NAME, "{\n"
+ + " \"clientConnector\":{\"port\":
10420,\"portRange\":1,\"idleTimeout\":999000},"
+ + " \"network\": {\n"
+ + " \"port\":3344,\n"
+ + " \"nodeFinder\": {\n"
+ + " \"netClusterNodes\":[ \"localhost:3344\" ]\n"
+ + " }\n"
+ + " }\n"
+ + "}"
+ );
+
+ /** Base path for all temporary folders. */
+ private static final Path BASE_PATH = Path.of("target", "work",
"PlatformBenchmarkNodeRunner");
+
+ /**
+ * Entry point.
+ *
+ * @param args Args.
+ */
+ public static void main(String[] args) throws Exception {
+ System.out.println("Starting benchmark node runner...");
+
+ List<Ignite> startedNodes =
PlatformTestNodeRunner.startNodes(BASE_PATH, nodesBootstrapCfg);
+
+ Object clientHandlerModule =
IgniteTestUtils.getFieldValue(startedNodes.get(0), "clientHandlerModule");
+ ClientHandlerMetricSource metrics =
IgniteTestUtils.getFieldValue(clientHandlerModule, "metrics");
+ metrics.enable();
+
+ while (true) {
+ Thread.sleep(3000);
+ System.out.println();
+ System.out.println("sessionsActive: " + metrics.sessionsActive());
+ System.out.println("sessionsAccepted: " +
metrics.sessionsAccepted());
+ System.out.println("requestsActive: " + metrics.requestsActive());
+ System.out.println("requestsProcessed: " +
metrics.requestsProcessed());
+ }
+ }
+}
diff --git
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
index ae91f6f957..a3ee9a833c 100644
---
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
+++
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/runner/app/PlatformTestNodeRunner.java
@@ -22,6 +22,7 @@ import static
org.apache.ignite.internal.testframework.IgniteTestUtils.await;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.escapeWindowsPath;
import static
org.apache.ignite.internal.testframework.IgniteTestUtils.getResourcePath;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
@@ -53,6 +54,7 @@ import
org.apache.ignite.internal.table.impl.DummySchemaManagerImpl;
import org.apache.ignite.internal.util.IgniteUtils;
import org.apache.ignite.sql.Session;
import org.apache.ignite.table.Tuple;
+import org.jetbrains.annotations.NotNull;
/**
* Helper class for non-Java platform tests (.NET, C++, Python, ...). Starts
nodes, populates tables and data for tests.
@@ -179,14 +181,44 @@ public class PlatformTestNodeRunner {
return;
}
- IgniteUtils.deleteIfExists(BASE_PATH);
- Files.createDirectories(BASE_PATH);
+ List<Ignite> startedNodes = startNodes(BASE_PATH, nodesBootstrapCfg);
+
+ createTables(startedNodes.get(0));
+
+ String ports = startedNodes.stream()
+ .map(n -> String.valueOf(getPort((IgniteImpl) n)))
+ .collect(Collectors.joining(","));
+
+ System.out.println("THIN_CLIENT_PORTS=" + ports);
+
+ long runTimeMinutes = getRunTimeMinutes();
+ System.out.println("Nodes will be active for " + runTimeMinutes + "
minutes.");
+
+ Thread.sleep(runTimeMinutes * 60_000);
+ System.out.println("Exiting after " + runTimeMinutes + " minutes.");
+
+ for (Ignite node : startedNodes) {
+ IgnitionManager.stop(node.name());
+ }
+ }
+
+ /**
+ * Start nodes.
+ *
+ * @param basePath Base path.
+ * @param nodeCfg Node configuration.
+ * @return Started nodes.
+ */
+ @NotNull
+ static List<Ignite> startNodes(Path basePath, Map<String, String> nodeCfg)
throws IOException {
+ IgniteUtils.deleteIfExists(basePath);
+ Files.createDirectories(basePath);
var sslPassword = "123456";
var trustStorePath =
escapeWindowsPath(getResourcePath(PlatformTestNodeRunner.class,
"ssl/trust.jks"));
var keyStorePath =
escapeWindowsPath(getResourcePath(PlatformTestNodeRunner.class,
"ssl/server.jks"));
- List<CompletableFuture<Ignite>> igniteFutures =
nodesBootstrapCfg.entrySet().stream()
+ List<CompletableFuture<Ignite>> igniteFutures =
nodeCfg.entrySet().stream()
.map(e -> {
String nodeName = e.getKey();
String config = e.getValue()
@@ -194,11 +226,11 @@ public class PlatformTestNodeRunner {
.replace("TRUSTSTORE_PATH", trustStorePath)
.replace("SSL_STORE_PASS", sslPassword);
- return IgnitionManager.start(nodeName, config,
BASE_PATH.resolve(nodeName));
+ return IgnitionManager.start(nodeName, config,
basePath.resolve(nodeName));
})
.collect(toList());
- String metaStorageNodeName =
nodesBootstrapCfg.keySet().iterator().next();
+ String metaStorageNodeName = nodeCfg.keySet().iterator().next();
InitParameters initParameters = InitParameters.builder()
.destinationNodeName(metaStorageNodeName)
@@ -213,23 +245,7 @@ public class PlatformTestNodeRunner {
System.out.println("Ignite nodes started");
- createTables(startedNodes.get(0));
-
- String ports = startedNodes.stream()
- .map(n -> String.valueOf(getPort((IgniteImpl) n)))
- .collect(Collectors.joining(","));
-
- System.out.println("THIN_CLIENT_PORTS=" + ports);
-
- long runTimeMinutes = getRunTimeMinutes();
- System.out.println("Nodes will be active for " + runTimeMinutes + "
minutes.");
-
- Thread.sleep(runTimeMinutes * 60_000);
- System.out.println("Exiting after " + runTimeMinutes + " minutes.");
-
- for (Ignite node : startedNodes) {
- IgnitionManager.stop(node.name());
- }
+ return startedNodes;
}
private static void createTables(Ignite node) {