Skip to content

Commit 97ad1ef

Browse files
committed
performance: attempt to improve performance
- reset ioThreads to server defaults - bug fixing on netty buffered output - reduce call to netty headers set(String, String)
1 parent 6671558 commit 97ad1ef

File tree

11 files changed

+144
-39
lines changed

11 files changed

+144
-39
lines changed

jooby/src/main/java/io/jooby/ServerOptions.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ public class ServerOptions {
7272
private static final String LOCAL_HOST = "0.0.0.0";
7373

7474
/** Number of available threads, but never smaller than <code>2</code>. */
75-
public static final int IO_THREADS = Runtime.getRuntime().availableProcessors() * 2;
75+
public static final int IO_THREADS =
76+
Integer.parseInt(
77+
System.getProperty(
78+
"jooby.server.ioThreads",
79+
Integer.toString(Runtime.getRuntime().availableProcessors())));
7680

7781
/**
7882
* Number of worker (a.k.a application) threads. It is the number of processors multiply by <code>

jooby/src/main/java/io/jooby/internal/Chi.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,6 @@ private interface MethodMatcher {
515515
StaticRouterMatch get(String method);
516516

517517
void put(String method, StaticRouterMatch route);
518-
519-
boolean matches(String method);
520518
}
521519

522520
private static class SingleMethodMatcher implements MethodMatcher {
@@ -531,17 +529,9 @@ public void put(String method, StaticRouterMatch route) {
531529

532530
@Override
533531
public StaticRouterMatch get(String method) {
534-
if (this.method == method) {
535-
return route;
536-
}
537532
return this.method.equals(method) ? route : null;
538533
}
539534

540-
@Override
541-
public boolean matches(String method) {
542-
return this.method.equals(method);
543-
}
544-
545535
public void clear() {
546536
this.method = null;
547537
this.route = null;
@@ -565,11 +555,6 @@ public StaticRouterMatch get(String method) {
565555
public void put(String method, StaticRouterMatch route) {
566556
methods.put(method, route);
567557
}
568-
569-
@Override
570-
public boolean matches(String method) {
571-
return this.methods.containsKey(method);
572-
}
573558
}
574559

575560
static class StaticRoute {

jooby/src/test/java/io/jooby/internal/ChiTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public void staticMap6() {
4242
router.insert(route("GET", "/4", stringHandler("4")));
4343
router.insert(route("GET", "/5", stringHandler("5")));
4444
router.insert(route("GET", "/6", stringHandler("6")));
45+
46+
Router.Match result = router.find("GET", "/1");
47+
assertTrue(result.matches());
4548
}
4649

4750
@Test

modules/jooby-jetty/src/main/java/io/jooby/jetty/JettyServer.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.jetty.server.handler.ContextHandler;
2121
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
2222
import org.eclipse.jetty.util.DecoratedObjectFactory;
23+
import org.eclipse.jetty.util.ProcessorUtils;
2324
import org.eclipse.jetty.util.compression.CompressionPool;
2425
import org.eclipse.jetty.util.compression.DeflaterPool;
2526
import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -47,6 +48,13 @@
4748
public class JettyServer extends io.jooby.Server.Base {
4849

4950
private static final int THREADS = 200;
51+
52+
static {
53+
int cpus = ProcessorUtils.availableProcessors();
54+
var ioThreads = Math.max(1, Math.min(cpus / 2, THREADS / 16));
55+
System.setProperty("jooby.server.ioThreads", ioThreads + "");
56+
}
57+
5058
private BufferedOutputFactory outputFactory;
5159

5260
private Server server;

modules/jooby-netty/src/main/java/io/jooby/internal/netty/HeadersMultiMap.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import io.netty.handler.codec.DateFormatter;
1818
import io.netty.handler.codec.http.DefaultHttpHeadersFactory;
1919
import io.netty.handler.codec.http.HttpHeaders;
20-
import io.netty.handler.codec.http.HttpHeadersFactory;
2120
import io.netty.util.AsciiString;
2221
import io.netty.util.CharsetUtil;
2322

@@ -61,20 +60,6 @@ private static CharSequence toValidCharSequence(Object value) {
6160
}
6261
}
6362

64-
public static HttpHeadersFactory httpHeadersFactory() {
65-
return new HttpHeadersFactory() {
66-
@Override
67-
public HttpHeaders newHeaders() {
68-
return new HeadersMultiMap();
69-
}
70-
71-
@Override
72-
public HttpHeaders newEmptyHeaders() {
73-
return new HeadersMultiMap();
74-
}
75-
};
76-
}
77-
7863
@Override
7964
public int size() {
8065
return names().size();

modules/jooby-netty/src/main/java/io/jooby/internal/netty/NettyContext.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
package io.jooby.internal.netty;
77

8+
import static io.jooby.internal.netty.NettyHeadersFactory.HEADERS;
89
import static io.netty.buffer.Unpooled.wrappedBuffer;
910
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
1011
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
@@ -31,7 +32,6 @@
3132
import java.nio.charset.Charset;
3233
import java.security.cert.Certificate;
3334
import java.util.ArrayList;
34-
import java.util.Arrays;
3535
import java.util.Collection;
3636
import java.util.Collections;
3737
import java.util.HashMap;
@@ -75,12 +75,11 @@
7575
import io.netty.util.IllegalReferenceCountException;
7676

7777
public class NettyContext implements DefaultContext, ChannelFutureListener {
78-
public static HttpHeadersFactory HEADERS = HeadersMultiMap.httpHeadersFactory();
7978
private static final HttpHeaders NO_TRAILING = EmptyHttpHeaders.INSTANCE;
8079
private static final String STREAM_ID = "x-http2-stream-id";
8180

8281
private String streamId;
83-
HttpHeaders setHeaders = HEADERS.newHeaders();
82+
HeadersMultiMap setHeaders = HEADERS.newHeaders();
8483
private int bufferSize;
8584
InterfaceHttpPostRequestDecoder decoder;
8685
DefaultHttpDataFactory httpDataFactory;
@@ -286,7 +285,7 @@ public List<Certificate> getClientCertificates() {
286285
SslHandler sslHandler = (SslHandler) ctx.channel().pipeline().get("ssl");
287286
if (sslHandler != null) {
288287
try {
289-
return Arrays.asList(sslHandler.engine().getSession().getPeerCertificates());
288+
return List.of(sslHandler.engine().getSession().getPeerCertificates());
290289
} catch (SSLPeerUnverifiedException x) {
291290
throw SneakyThrows.propagate(x);
292291
}
@@ -420,13 +419,11 @@ public Context upgrade(@NonNull ServerSentEmitter.Handler handler) {
420419
responseStarted = true;
421420
ctx.writeAndFlush(new DefaultHttpResponse(HTTP_1_1, status, setHeaders));
422421

423-
// ctx.executor().execute(() -> {
424422
try {
425423
handler.handle(new NettyServerSentEmitter(this));
426424
} catch (Throwable x) {
427425
sendError(x);
428426
}
429-
// });
430427
return this;
431428
}
432429

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.internal.netty;
7+
8+
import io.netty.handler.codec.http.HttpHeadersFactory;
9+
10+
public class NettyHeadersFactory implements HttpHeadersFactory {
11+
12+
public static NettyHeadersFactory HEADERS = new NettyHeadersFactory();
13+
14+
@Override
15+
public HeadersMultiMap newHeaders() {
16+
return new HeadersMultiMap();
17+
}
18+
19+
@Override
20+
public HeadersMultiMap newEmptyHeaders() {
21+
return new HeadersMultiMap();
22+
}
23+
}

modules/jooby-netty/src/main/java/io/jooby/netty/NettyServer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.jooby.netty;
77

88
import static io.jooby.ServerOptions._4KB;
9+
import static io.jooby.internal.netty.NettyHeadersFactory.HEADERS;
910
import static java.util.concurrent.Executors.newFixedThreadPool;
1011

1112
import java.net.BindException;
@@ -199,8 +200,8 @@ private NettyPipeline newPipeline(
199200
.setMaxInitialLineLength(_4KB)
200201
.setMaxHeaderSize(options.getMaxHeaderSize())
201202
.setMaxChunkSize(options.getBuffer().getSize())
202-
.setHeadersFactory(NettyContext.HEADERS)
203-
.setTrailersFactory(NettyContext.HEADERS);
203+
.setHeadersFactory(HEADERS)
204+
.setTrailersFactory(HEADERS);
204205
return new NettyPipeline(
205206
sslContext,
206207
dateService,

modules/jooby-undertow/src/main/java/io/jooby/undertow/UndertowServer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@
4242
*/
4343
public class UndertowServer extends Server.Base {
4444

45+
static {
46+
System.setProperty(
47+
"jooby.server.ioThreads", (Runtime.getRuntime().availableProcessors() * 2) + "");
48+
}
49+
4550
private static final int BACKLOG = 8192;
4651

4752
private static final int _100 = 100;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package examples;
7+
8+
import static io.jooby.ExecutionMode.EVENT_LOOP;
9+
import static io.jooby.MediaType.JSON;
10+
11+
import java.nio.charset.StandardCharsets;
12+
13+
import io.jooby.Jooby;
14+
import io.jooby.StatusCode;
15+
import io.jooby.netty.NettyServer;
16+
17+
public class Performance extends Jooby {
18+
19+
private static final String MESSAGE = "Hello, World!";
20+
21+
private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.UTF_8);
22+
23+
{
24+
var message = getOutputFactory().wrap(MESSAGE_BYTES);
25+
get(
26+
"/plaintext",
27+
ctx -> {
28+
return ctx.send(message);
29+
});
30+
31+
get("/json", ctx -> ctx.setResponseType(JSON).render(new Message(MESSAGE)));
32+
33+
get("/db", ctx -> ctx.send(StatusCode.OK));
34+
35+
get("/queries", ctx -> ctx.send(StatusCode.OK));
36+
37+
get("/fortuxnes", ctx -> ctx.send(StatusCode.OK));
38+
39+
get("/updates", ctx -> ctx.send(StatusCode.OK));
40+
}
41+
42+
public static void main(final String[] args) {
43+
System.setProperty("io.netty.disableHttpHeadersValidation", "true");
44+
runApp(args, new NettyServer(), EVENT_LOOP, Performance::new);
45+
}
46+
}

0 commit comments

Comments
 (0)