Skip to content

Commit 5c3e7d1

Browse files
committed
Configure Buffer pools for Jetty server
This circumvents jetty/jetty.project#12670
1 parent 9727083 commit 5c3e7d1

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

http-server/src/main/java/io/airlift/http/server/HttpServer.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.airlift.http.server.jetty.MonitoredQueuedThreadPoolMBean;
2323
import io.airlift.log.Logger;
2424
import io.airlift.node.NodeInfo;
25+
import io.airlift.units.DataSize;
2526
import jakarta.annotation.PostConstruct;
2627
import jakarta.annotation.PreDestroy;
2728
import jakarta.servlet.Filter;
@@ -34,6 +35,8 @@
3435
import org.eclipse.jetty.http2.server.AuthorityCustomizer;
3536
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
3637
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
38+
import org.eclipse.jetty.io.ArrayByteBufferPool;
39+
import org.eclipse.jetty.io.ByteBufferPool;
3740
import org.eclipse.jetty.io.ConnectionStatistics;
3841
import org.eclipse.jetty.jmx.MBeanContainer;
3942
import org.eclipse.jetty.server.ConnectionFactory;
@@ -65,6 +68,7 @@
6568
import java.util.EnumSet;
6669
import java.util.List;
6770
import java.util.Optional;
71+
import java.util.OptionalLong;
6872
import java.util.Set;
6973
import java.util.concurrent.Executor;
7074
import java.util.concurrent.ScheduledExecutorService;
@@ -75,6 +79,7 @@
7579
import static com.google.common.base.Verify.verify;
7680
import static com.google.common.collect.ImmutableList.toImmutableList;
7781
import static io.airlift.concurrent.Threads.daemonThreadsNamed;
82+
import static java.lang.Math.max;
7883
import static java.lang.Math.toIntExact;
7984
import static java.time.temporal.ChronoUnit.DAYS;
8085
import static java.util.Collections.list;
@@ -139,7 +144,19 @@ public HttpServer(
139144
log.info("Virtual threads support is enabled");
140145
threadPool.setVirtualThreadsExecutor(executor);
141146
}
142-
server = new Server(threadPool);
147+
148+
int maxBufferSize = toIntExact(max(
149+
toSafeBytes(config.getMaxRequestHeaderSize()).orElse(65536),
150+
toSafeBytes(config.getMaxResponseHeaderSize()).orElse(65536)));
151+
152+
ByteBufferPool byteBufferPool = new ArrayByteBufferPool.Quadratic(
153+
0,
154+
maxBufferSize,
155+
Integer.MAX_VALUE,
156+
config.getMaxHeapMemory().toBytes(),
157+
config.getMaxDirectMemory().toBytes());
158+
159+
server = new Server(threadPool, null, byteBufferPool);
143160
this.monitoredQueuedThreadPoolMBean = new MonitoredQueuedThreadPoolMBean(threadPool);
144161

145162
boolean showStackTrace = config.isShowStackTrace();
@@ -273,7 +290,6 @@ public HttpServer(
273290
}
274291

275292
server.setHandler(statsHandler);
276-
277293
ErrorHandler errorHandler = new ErrorHandler();
278294
errorHandler.setShowMessageInTitle(showStackTrace);
279295
errorHandler.setShowStacks(showStackTrace);
@@ -471,4 +487,13 @@ private static ServerConnector createServerConnector(
471487
connector.open(channel);
472488
return connector;
473489
}
490+
491+
private static OptionalLong toSafeBytes(DataSize dataSize)
492+
{
493+
if (dataSize == null) {
494+
return OptionalLong.empty();
495+
}
496+
497+
return OptionalLong.of(dataSize.toBytes());
498+
}
474499
}

http-server/src/main/java/io/airlift/http/server/HttpServerConfig.java

+54
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
package io.airlift.http.server;
1717

18+
import com.google.common.annotations.VisibleForTesting;
1819
import io.airlift.configuration.Config;
1920
import io.airlift.configuration.ConfigDescription;
21+
import io.airlift.configuration.ConfigHidden;
2022
import io.airlift.configuration.DefunctConfig;
2123
import io.airlift.units.DataSize;
2224
import io.airlift.units.Duration;
@@ -94,6 +96,16 @@ public class HttpServerConfig
9496

9597
private boolean compressionEnabled = true;
9698

99+
private DataSize maxHeapMemory = clamp(
100+
DataSize.ofBytes(Runtime.getRuntime().maxMemory() / 8),
101+
DataSize.of(128, MEGABYTE),
102+
DataSize.of(512, MEGABYTE));
103+
104+
private DataSize maxDirectMemory = clamp(
105+
DataSize.ofBytes(Runtime.getRuntime().maxMemory() / 8),
106+
DataSize.of(128, MEGABYTE),
107+
DataSize.of(512, MEGABYTE));
108+
97109
public boolean isHttpEnabled()
98110
{
99111
return httpEnabled;
@@ -473,6 +485,36 @@ public HttpServerConfig setCompressionEnabled(boolean compressionEnabled)
473485
return this;
474486
}
475487

488+
@MinDataSize("128MB")
489+
@MaxDataSize("32GB")
490+
public DataSize getMaxHeapMemory()
491+
{
492+
return maxHeapMemory;
493+
}
494+
495+
@Config("http-server.max-heap-memory")
496+
@ConfigHidden
497+
public HttpServerConfig setMaxHeapMemory(DataSize maxHeapMemory)
498+
{
499+
this.maxHeapMemory = maxHeapMemory;
500+
return this;
501+
}
502+
503+
@MinDataSize("128MB")
504+
@MaxDataSize("32GB")
505+
public DataSize getMaxDirectMemory()
506+
{
507+
return maxDirectMemory;
508+
}
509+
510+
@Config("http-server.max-direct-memory")
511+
@ConfigHidden
512+
public HttpServerConfig setMaxDirectMemory(DataSize maxDirectMemory)
513+
{
514+
this.maxDirectMemory = maxDirectMemory;
515+
return this;
516+
}
517+
476518
public enum ProcessForwardedMode
477519
{
478520
ACCEPT,
@@ -488,4 +530,16 @@ public static ProcessForwardedMode fromString(String value)
488530
};
489531
}
490532
}
533+
534+
@VisibleForTesting
535+
static DataSize clamp(DataSize value, DataSize min, DataSize max)
536+
{
537+
if (value.compareTo(min) < 0) {
538+
return min;
539+
}
540+
if (value.compareTo(max) > 0) {
541+
return max;
542+
}
543+
return value;
544+
}
491545
}

http-server/src/test/java/io/airlift/http/server/TestHttpServerConfig.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults;
2828
import static io.airlift.http.server.HttpServerConfig.ProcessForwardedMode.IGNORE;
2929
import static io.airlift.http.server.HttpServerConfig.ProcessForwardedMode.REJECT;
30+
import static io.airlift.http.server.HttpServerConfig.clamp;
3031
import static io.airlift.units.DataSize.Unit.GIGABYTE;
3132
import static io.airlift.units.DataSize.Unit.KILOBYTE;
3233
import static io.airlift.units.DataSize.Unit.MEGABYTE;
@@ -67,7 +68,9 @@ public void testDefaults()
6768
.setHttp2InputBufferSize(DataSize.of(8, KILOBYTE))
6869
.setHttp2InitialStreamReceiveWindowSize(DataSize.of(16, MEGABYTE))
6970
.setHttp2StreamIdleTimeout(new Duration(15, SECONDS))
70-
.setCompressionEnabled(true));
71+
.setCompressionEnabled(true)
72+
.setMaxHeapMemory(clamp(DataSize.ofBytes(Runtime.getRuntime().maxMemory() / 8), DataSize.of(128, MEGABYTE), DataSize.of(512, MEGABYTE)))
73+
.setMaxDirectMemory(clamp(DataSize.ofBytes(Runtime.getRuntime().maxMemory() / 8), DataSize.of(128, MEGABYTE), DataSize.of(512, MEGABYTE))));
7174
}
7275

7376
@Test
@@ -103,6 +106,8 @@ public void testExplicitPropertyMappings()
103106
.put("http-server.http2.input-buffer-size", "4MB")
104107
.put("http-server.http2.stream-idle-timeout", "23s")
105108
.put("http-server.compression.enabled", "false")
109+
.put("http-server.max-heap-memory", "2GB")
110+
.put("http-server.max-direct-memory", "2GB")
106111
.build();
107112

108113
HttpServerConfig expected = new HttpServerConfig()
@@ -134,7 +139,9 @@ public void testExplicitPropertyMappings()
134139
.setHttp2InitialStreamReceiveWindowSize(DataSize.of(4, MEGABYTE))
135140
.setHttp2InputBufferSize(DataSize.of(4, MEGABYTE))
136141
.setHttp2StreamIdleTimeout(new Duration(23, SECONDS))
137-
.setCompressionEnabled(false);
142+
.setCompressionEnabled(false)
143+
.setMaxHeapMemory(DataSize.of(2, GIGABYTE))
144+
.setMaxDirectMemory(DataSize.of(2, GIGABYTE));
138145

139146
assertFullMapping(properties, expected);
140147
}

0 commit comments

Comments
 (0)