Created
February 18, 2019 11:29
-
-
Save mpfau/9fbcbee56a5911e0f1ff5e83971d5c6c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.