Skip to content

Commit 8a77bed

Browse files
committed
Refactor LoadTestAction for usability
Calculates the delay seconds automatically. This value helps ensure that all EPP requests are enqueued before the scheduled test start time. Since queue insertion is much slower than dispatch, this is essential to maintain a stable QPS rate. Also parallelizes queue insertion using a thread pool. This reduces the delay for enqueuing the requests. BUG=http://b/533414332
1 parent b5ae51a commit 8a77bed

2 files changed

Lines changed: 43 additions & 21 deletions

File tree

core/src/main/java/google/registry/loadtest/LoadTestAction.java

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static com.google.common.collect.ImmutableList.toImmutableList;
1919
import static com.google.common.collect.Lists.partition;
2020
import static google.registry.util.ResourceUtils.readResourceUtf8;
21+
import static java.util.concurrent.Executors.newFixedThreadPool;
2122

2223
import com.google.cloud.tasks.v2.Task;
2324
import com.google.common.collect.ImmutableList;
@@ -39,11 +40,15 @@
3940
import java.util.Iterator;
4041
import java.util.List;
4142
import java.util.Random;
43+
import java.util.concurrent.ExecutorService;
4244
import java.util.function.Function;
4345

4446
/**
4547
* Simple load test action that can generate configurable QPSes of various EPP actions.
4648
*
49+
* <p>This is not an end-to-end test. It exercises the Nomulus EPP service and the database, but
50+
* does not cover the proxy.
51+
*
4752
* <p>All aspects of the load test are configured via URL parameters that are specified when the
4853
* loadtest URL is being POSTed to. The {@code clientId} and {@code tld} parameters are required.
4954
* All of the other parameters are optional, but if none are specified then no actual load testing
@@ -60,7 +65,7 @@ public class LoadTestAction implements Runnable {
6065

6166
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
6267

63-
private static final int NUM_QUEUES = 10;
68+
private static final int NUM_QUEUES = 20;
6469
private static final int MAX_TASKS_PER_LOAD = 100;
6570
private static final int ARBITRARY_VALID_HOST_LENGTH = 40;
6671
private static final int MAX_DOMAIN_LABEL_LENGTH = 63;
@@ -72,20 +77,17 @@ public class LoadTestAction implements Runnable {
7277

7378
public static final String PATH = "/_dr/loadtest";
7479

80+
// Average task insertion rate with a dedicated thread enqueuing to one queue. This is used to
81+
// calculate the EPP request dispatch time. This value is based on observation and needs not to
82+
// be accurate. However, it should be low enough so that all EPP tasks are enqueued before the
83+
// first task is dispatched.
84+
private static final int TASK_INSERTIONS_PER_QUEUE_PER_MINUTE = 1000;
85+
7586
/** The ID of the registrar to use for load testing. */
7687
@Inject
7788
@Parameter("loadtestClientId")
7889
String registrarId;
7990

80-
/**
81-
* The number of seconds to delay the execution of the first load testing tasks by. Preparatory
82-
* work of creating independent hosts that will be used for later domain creation testing occurs
83-
* during this period, so make sure that it is long enough.
84-
*/
85-
@Inject
86-
@Parameter("delaySeconds")
87-
int delaySeconds;
88-
8991
/**
9092
* The number of seconds that tasks will be enqueued for. Note that if system QPS cannot handle
9193
* the given load then it will take longer than this number of seconds for the test to complete.
@@ -157,9 +159,24 @@ public class LoadTestAction implements Runnable {
157159
xmlHostInfo = loadXml("host_info").replace("%host%", EXISTING_HOST);
158160
}
159161

162+
private int eppTaskCount() {
163+
return successfulDomainCreatesPerSecond
164+
+ runSeconds
165+
* (successfulHostCreatesPerSecond
166+
+ failedHostCreatesPerSecond
167+
+ domainInfosPerSecond
168+
+ domainChecksPerSecond
169+
+ hostInfosPerSecond
170+
+ successfulDomainCreatesPerSecond
171+
+ failedDomainCreatesPerSecond);
172+
}
173+
160174
@Override
161175
public void run() {
162-
validateAndLogRequest();
176+
// Delay the EPP request dispatch time to account for queue-insertion time.
177+
int delaySeconds =
178+
Math.ceilDiv(eppTaskCount(), TASK_INSERTIONS_PER_QUEUE_PER_MINUTE * NUM_QUEUES) * 60;
179+
validateAndLogRequest(delaySeconds);
163180
Instant initialStartSecond = clock.now().plus(Duration.ofSeconds(delaySeconds));
164181
ImmutableList.Builder<String> preTaskXmls = new ImmutableList.Builder<>();
165182
ImmutableList.Builder<String> hostPrefixesBuilder = new ImmutableList.Builder<>();
@@ -209,7 +226,7 @@ public void run() {
209226
logger.atInfo().log("Added %d total load test tasks.", taskOptions.size());
210227
}
211228

212-
private void validateAndLogRequest() {
229+
private void validateAndLogRequest(int delaySeconds) {
213230
checkArgument(
214231
RegistryEnvironment.get() != RegistryEnvironment.PRODUCTION,
215232
"DO NOT RUN LOADTESTS IN PROD!");
@@ -297,9 +314,20 @@ private ImmutableList<Task> createTasks(ImmutableList<String> xmls, Instant star
297314

298315
private void enqueue(ImmutableList<Task> tasks) {
299316
List<List<Task>> chunks = partition(tasks, MAX_TASKS_PER_LOAD);
300-
// Farm out tasks to multiple queues to work around queue qps quotas.
301-
for (int i = 0; i < chunks.size(); i++) {
302-
cloudTasksUtils.enqueue("load" + (i % NUM_QUEUES), chunks.get(i));
317+
// Farm out tasks to multiple queues to work around queue qps quotas. Use multiple threads to
318+
// speed up the enqueuing.
319+
try (ExecutorService executorService = newFixedThreadPool(NUM_QUEUES)) {
320+
for (int i = 0; i < chunks.size(); i++) {
321+
final int index = i;
322+
// lgtm[java/local-variable-is-never-read] Suppress Github CodeQL's outdated warning
323+
var _ =
324+
executorService.submit(
325+
() -> cloudTasksUtils.enqueue(getQueueName(index % NUM_QUEUES), chunks.get(index)));
326+
}
303327
}
304328
}
329+
330+
private static String getQueueName(int queueId) {
331+
return String.format("load%d", queueId);
332+
}
305333
}

core/src/main/java/google/registry/loadtest/LoadTestModule.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ static String provideClientId(HttpServletRequest req) {
3838
return extractRequiredParameter(req, "clientId");
3939
}
4040

41-
@Provides
42-
@Parameter("delaySeconds")
43-
static int provideDelaySeconds(HttpServletRequest req) {
44-
return extractOptionalIntParameter(req, "delaySeconds").orElse(60);
45-
}
46-
4741
@Provides
4842
@Parameter("runSeconds")
4943
static int provideRunSeconds(HttpServletRequest req) {

0 commit comments

Comments
 (0)