Skip to content

Commit

Permalink
Use Virtual Threads (#519)
Browse files Browse the repository at this point in the history
* migrating thread pools to virtual threads

* using virtual thread executor when querying remote dns servers

* fixing test

* stress test related code

* configuring supervisor

* adjusting default dns

* created stress test

* created stress test

* creating docs of how to use stress tests

* more asserts

* creating collector structure

* skipping login page and set as admin

* configuring metrics

* fixing test conflict with running dps on machine

* configuring default dashboards

* changing filter time

* updating the docs

* adjusting the docs order

* linking doc

* clean code

* clean code

* release notes

* [Gradle Release Plugin] - new version commit:  '3.25.0-snapshot'.
  • Loading branch information
mageddo authored Jul 30, 2024
1 parent a8b99f2 commit ae30d13
Show file tree
Hide file tree
Showing 27 changed files with 712 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,5 @@ issues
/files
tmp/
Poc.java

src/stress-test/docker/dps-stress-test-instance/files
5 changes: 4 additions & 1 deletion RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## 3.24.2
## 3.25.0
* Optimize resource utilization by using Java Virtual Threads #436.

## 3.24.2
* Mitigate arm release failure due inexistence of required debian package #517

## 3.24.1
Expand Down
32 changes: 32 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ repositories {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21

sourceSets {
stressTest {
java {
srcDir 'src/stress-test/java'
}
resources {
srcDir 'src/stress-test/resources'
}
compileClasspath += sourceSets.test.runtimeClasspath
runtimeClasspath += sourceSets.test.runtimeClasspath
}
}



dependencies {

compileOnly('org.projectlombok:lombok:1.18.+')
Expand Down Expand Up @@ -56,9 +71,13 @@ dependencies {
implementation('com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1')

testAnnotationProcessor("com.google.dagger:dagger-compiler:2.45")

testCompileOnly('org.projectlombok:lombok:1.18.+')
testAnnotationProcessor('org.projectlombok:lombok:1.18.+')

stressTestCompileOnly('org.projectlombok:lombok:1.18.+')
stressTestAnnotationProcessor('org.projectlombok:lombok:1.18.+')

testImplementation("org.junit.jupiter:junit-jupiter:5.10.+")
testImplementation('org.mockito:mockito-junit-jupiter:5.12.+')
testImplementation('io.rest-assured:rest-assured:5.3.0')
Expand All @@ -83,6 +102,19 @@ task compTest(type: Test) {
}
}

task stressTest(type: Test) {

testClassesDirs = sourceSets.stressTest.output.classesDirs
classpath += sourceSets.stressTest.runtimeClasspath

useJUnitPlatform()
include "**/*Test.class"
failFast = true
testLogging {
events "passed", "skipped", "failed"
}
}

compileJava {
options.encoding = 'UTF-8'
options.compilerArgs << '-parameters'
Expand Down
2 changes: 1 addition & 1 deletion docs/content/4-developing/compiling.en.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Compiling from source
weight: 4
pre: "<b>4. </b>"
pre: "<b>1. </b>"
---

## Requirements
Expand Down
2 changes: 1 addition & 1 deletion docs/content/4-developing/generating-docs.en.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Generating the docs
weight: 6
pre: "<b>6. </b>"
pre: "<b>2. </b>"
---

## Introduction
Expand Down
2 changes: 1 addition & 1 deletion docs/content/4-developing/releasing.en.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Release Process
weight: 7
pre: "<b>7. </b>"
pre: "<b>3. </b>"
---

## Feature Request - Phase 1
Expand Down
28 changes: 28 additions & 0 deletions docs/content/4-developing/stress-tests.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: Stress Tests
pre: "<b>4. </b>"
---

Start DPS Instance to be tested

```bash
./gradlew clean build compTest shadowJar nativeImageJar nativeCompile -i
cp build/native/nativeCompile/dns-proxy-server ./src/stress-test/docker/dps-stress-test-instance/files/
docker-compose -f src/stress-test/docker/dps-stress-test-instance/docker-compose.yml up --build
```

Start Grafana Stack to Collect Performance Metrics

```bash
docker-compose -f src/stress-test/docker/grafana/docker-compose.yml up --build
```

Run the Stress Test Suite

```bash
./gradlew build stressTest
```

Access http://localhost:3000 to see the metrics

[1]: {{%relref "1-getting-started/requirements/_index.en.md" %}}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=3.24.2-snapshot
version=3.25.0-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,39 @@
import com.mageddo.net.IpAddr;

import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;

public class RemoteResolvers {
public class RemoteResolvers implements AutoCloseable {

private final List<Resolver> resolvers;
private final ExecutorService executor;

private RemoteResolvers(List<Resolver> resolvers) {
private RemoteResolvers(List<Resolver> resolvers, ExecutorService executor) {
this.resolvers = resolvers;
this.executor = executor;
}

public static RemoteResolvers of(List<IpAddr> servers, final Function<IpAddr, Resolver> resolverProvider) {
final var resolvers = servers
.stream()
.map(resolverProvider)
.toList();
return new RemoteResolvers(resolvers);
return new RemoteResolvers(resolvers, Executors.newVirtualThreadPerTaskExecutor());
}

public List<Resolver> resolvers() {
return this.resolvers;
}

@Override
public void close() throws Exception {
this.executor.close();
}

public Executor getExecutor() {
return this.executor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ Result safeQueryResult(Request req) {
}

Result queryResultWhilePingingResolver(Request req) {
final var resFuture = req.sendQueryAsyncToResolver();
final var resFuture = req.sendQueryAsyncToResolver(this.delegate.getExecutor());
this.netWatchdog.watch(req.getResolverAddr(), resFuture, PING_TIMEOUT_IN_MS);
return this.transformToResult(resFuture, req);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.net.InetSocketAddress;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

@Value
@Builder
Expand Down Expand Up @@ -40,8 +41,8 @@ public void splitStopWatch() {
this.stopWatch.split();
}

public CompletableFuture<Message> sendQueryAsyncToResolver() {
return this.resolver.sendAsync(this.query).toCompletableFuture();
public CompletableFuture<Message> sendQueryAsyncToResolver(Executor executor) {
return this.resolver.sendAsync(this.query, executor).toCompletableFuture();
}

public long getElapsedTimeInMs() {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/mageddo/dnsserver/TCPServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

Expand All @@ -35,7 +36,7 @@ public class TCPServer implements AutoCloseable {

@Inject
public TCPServer() {
this.serverThreadPool = ThreadPool.newFixed(50);
this.serverThreadPool = Executors.newVirtualThreadPerTaskExecutor();
this.clients = new LinkedHashSet<>();
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/mageddo/dnsserver/UDPServer.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.mageddo.dnsserver;

import com.mageddo.commons.concurrent.ThreadPool;
import com.mageddo.commons.io.IoUtils;
import com.mageddo.dns.utils.Messages;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -10,6 +9,7 @@
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class UDPServer {
Expand All @@ -24,7 +24,7 @@ public class UDPServer {
public UDPServer(SocketAddress address, RequestHandler requestHandler) {
this.address = address;
this.requestHandler = requestHandler;
this.pool = ThreadPool.newFixed(50);
this.pool = Executors.newVirtualThreadPerTaskExecutor();
}

public void start() {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/mageddo/net/NetExecutorWatchdog.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.mageddo.net;

import com.mageddo.commons.circuitbreaker.CircuitCheckException;
import com.mageddo.commons.concurrent.ThreadPool;
import com.mageddo.commons.concurrent.Threads;
import com.mageddo.dnsproxyserver.utils.InetAddresses;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -10,14 +9,15 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

@Slf4j
public class NetExecutorWatchdog implements AutoCloseable {

public static final int FPS_120 = 1000 / 120;

private final ExecutorService threadPool = ThreadPool.newFixed(50);
private final ExecutorService threadPool = Executors.newVirtualThreadPerTaskExecutor();

/**
* Will ping the #pingAddr while waiting the future to be done, which occurs first will return,
Expand Down
25 changes: 25 additions & 0 deletions src/stress-test/docker/dps-stress-test-instance/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM debian:12

ARG PROCESS_EXPORTER_URL=https://github.com/ncabatoff/process-exporter/releases/download/v0.8.2/process-exporter-0.8.2.linux-amd64.tar.gz

RUN mkdir /process-exporter && mkdir -p /var/log/supervisord &&\
apt-get update && apt-get install -y curl supervisor &&\
curl -sL ${PROCESS_EXPORTER_URL} > /tmp/process-exporter.tgz &&\
tar --strip 1 -zxvf /tmp/process-exporter.tgz -C /process-exporter

# from website
ARG APP_URL=https://github.com/mageddo/dns-proxy-server/releases/download/3.24.0-snapshot/dns-proxy-server-linux-amd64-3.24.0-snapshot.tgz
RUN mkdir /app &&\
curl -sL ${APP_URL} > /tmp/app.tgz &&\
tar --strip 1 -zxvf /tmp/app.tgz -C /app

# from local build
#RUN mkdir /app
#COPY files/dns-proxy-server /app/dns-proxy-server

WORKDIR /process-exporter

COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY conf.yaml /process-exporter/conf.yaml

ENTRYPOINT ["/usr/bin/supervisord"]
4 changes: 4 additions & 0 deletions src/stress-test/docker/dps-stress-test-instance/conf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
process_names:
- name: "{{.Comm}}"
cmdline:
- '.+'
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
dps-stress-test-instance:
build:
dockerfile: Dockerfile
environment:
- MG_LOG_LEVEL=TRACE
ports:
- 9256:9256
- 5753:53/udp
38 changes: 38 additions & 0 deletions src/stress-test/docker/dps-stress-test-instance/supervisord.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[supervisord]
file=/tmp/supervisor.sock ; path to your socket file
[supervisord]
logfile=/var/log/supervisord/supervisord.log ; supervisord log file
logfile_maxbytes=50MB ; maximum size of logfile before rotation
logfile_backups=10 ; number of backed up logfiles
loglevel=info ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
nodaemon=true ; run supervisord as a daemon
minfds=1024 ; number of startup file descriptors
minprocs=200 ; number of process descriptors
user=root ; default user
childlogdir=/var/log/supervisord/ ; where child log files will live

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

;[supervisorctl]
;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket


[program:app]
user=root
command=bash -c '/app/dns-proxy-server --default-dns=false'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/1
stderr_logfile_maxbytes=0
autorestart=false

[program:processexporter]
user=root
command=bash -c '/process-exporter/process-exporter -config.path conf.yaml'
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/1
stderr_logfile_maxbytes=0
autorestart=false
1 change: 1 addition & 0 deletions src/stress-test/docker/grafana/README.md
20 changes: 20 additions & 0 deletions src/stress-test/docker/grafana/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
services:
prometheus:
image: prom/prometheus:v2.46.0
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml

grafana:
image: grafana/grafana:10.0.3-ubuntu
ports:
- "3000:3000"
environment:
- GF_SERVER_DOMAIN=grafana.docker
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
- GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH=/var/lib/grafana/dashboards/process-exporter-metrics.json
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning:ro
- ./grafana/dashboards:/var/lib/grafana/dashboards
Loading

0 comments on commit ae30d13

Please sign in to comment.