Skip to content

Instantly share code, notes, and snippets.

@mpfau
Created February 18, 2019 11:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpfau/9fbcbee56a5911e0f1ff5e83971d5c6c to your computer and use it in GitHub Desktop.
Save mpfau/9fbcbee56a5911e0f1ff5e83971d5c6c to your computer and use it in GitHub Desktop.
package perftest;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.client.api.Destination;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.io.ssl.SslHandshakeListener;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLSession;
import java.net.URI;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class PerfTestClient {
Logger log = LoggerFactory.getLogger(PerfTestClient.class);
int finishedRequestsThisSecond = 0;
int failedRequestsThisSecond = 0;
int failedConnectionsThisSecond = 0;
long time = 0;
int handshakes = 0;
int requestsPerSecond = 0;
int second = 0;
public static void main(String[] args) throws Exception {
String cipherSuite = null;
if (args.length == 6) {
cipherSuite = args[5];
}
new PerfTestClient().start(args[0], Integer.parseInt(args[1]), Boolean.parseBoolean(args[2]), Boolean.parseBoolean(args[3]), args[4], cipherSuite);
}
private void start(String endpoint, int targetRequestsPerSecond, boolean persistentSessions, boolean h2, String tls, String cipherSuite) throws Exception {
SslContextFactory cf = new SslContextFactory();
cf.setIncludeProtocols(tls); // "TLSv1.3", "TLSv1.2", "TLSv1"
if (cipherSuite != null) {
cf.setIncludeCipherSuites(cipherSuite);
}
cf.setEndpointIdentificationAlgorithm("HTTPS");
// java.security.Security.addProvider(new org.conscrypt.OpenSSLProvider());
// cf.setProvider("Conscrypt");
HttpClient httpClient = new HttpClient(cf);
if (h2) {
HTTP2Client h2Client = new HTTP2Client();
h2Client.setSelectors(1);
HttpClientTransportOverHTTP2 transport = new HttpClientTransportOverHTTP2(h2Client);
httpClient = new HttpClient(transport, cf);
}
HttpClient finalHttpClient = httpClient;
httpClient.addBean(new SslHandshakeListener() {
@Override
public void handshakeSucceeded(Event event) {
if (!persistentSessions) {
SSLSession session = event.getSSLEngine().getSession();
log.debug("id {}, {}", Base64.getEncoder().encodeToString(session.getId()), event.getSSLEngine().getSession().getCreationTime());
}
handshakes++;
}
});
httpClient.setMaxConnectionsPerDestination(256);
httpClient.setMaxRequestsQueuedPerDestination(4096);
httpClient.setConnectTimeout(15000);
httpClient.start();
URI uri = URI.create(endpoint);
Destination destination = finalHttpClient.getDestination(uri.getScheme(), uri.getHost(), uri.getPort());
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
// we distribute all requests to batches that are executed every 10 ms
for (int i = 0; i < 100; i++) {
int requestBatchSize = targetRequestsPerSecond / 100;
executorService.scheduleAtFixedRate(() -> {
for (int j = 0; j < requestBatchSize; j++) {
if (!persistentSessions) {
destination.newConnection(new Promise<Connection>() {
@Override
public void succeeded(Connection conn) {
sendRequest(endpoint, finalHttpClient, conn);
}
@Override
public void failed(Throwable x) {
failedConnectionsThisSecond++;
if (failedConnectionsThisSecond % 1000 == 1) {
log.debug("could not create conn", x);
}
}
});
} else {
sendRequest(endpoint, finalHttpClient, null);
}
}
}, i * 10, 1000, TimeUnit.MILLISECONDS);
}
System.out.println(formatLine(Arrays.asList("second", "threads", "timePerReq", "failedConnections", "failed", "finishedRequests", "handshakes")));
executorService.scheduleAtFixedRate(() -> {
long timePerRequest = time == 0 ? 0 : (time / (failedRequestsThisSecond + finishedRequestsThisSecond));
List<Number> data = Arrays.asList(second++, ((QueuedThreadPool) finalHttpClient.getExecutor()).getBusyThreads(), timePerRequest,
failedConnectionsThisSecond, failedRequestsThisSecond, finishedRequestsThisSecond, handshakes);
System.out.println(formatLine(data));
PerfTestClient.this.requestsPerSecond = 0;
finishedRequestsThisSecond = 0;
failedRequestsThisSecond = 0;
time = 0;
handshakes = 0;
failedConnectionsThisSecond = 0;
}, 1, 1, TimeUnit.SECONDS);
}
private String formatLine(List<?> data) {
return String.join(", ", data.stream().map((n) -> String.format("%1$20s", n)).collect(Collectors.toList()));
}
private void sendRequest(String endpoint, HttpClient httpClient, Connection conn) {
long start = System.currentTimeMillis();
Request get = httpClient.newRequest(endpoint)
.method(HttpMethod.GET);
BufferingResponseListener responseListener = new BufferingResponseListener() {
@Override
public void onComplete(Result result) {
time += System.currentTimeMillis() - start;
if (result.getResponse() != null && result.getResponse().getStatus() == 200) {
finishedRequestsThisSecond++;
} else {
if (failedRequestsThisSecond % 1000 == 1) {
if (result.getFailure() != null) {
result.getFailure().printStackTrace();
}
log.info("error {}, {}", result.getFailure(), result.getResponse().getStatus());
}
failedRequestsThisSecond++;
}
if (conn != null) { // persistentSessions
conn.close();
}
}
};
if (conn == null) { // persistentSessions
get.send(responseListener);
} else {
conn.send(get, responseListener);
}
}
}
@joakime
Copy link

joakime commented Feb 18, 2019

                 if (cipherSuite != null) {
			cf.setIncludeCipherSuites(cipherSuite);
		}

Exclude always wins over include.
Since you didn't replace the exclude list, your include list is hampered by the exclude patterns with the above code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment