-
Notifications
You must be signed in to change notification settings - Fork 355
Optimize tomcat-embed-core footprint #1426
Comments
@sdeleuze I've spent some time on this, and I agree with the general direction. I think it's important to capture what has taken place. Here is a review (all using the same tomcat binaries built with Java 8 sha 338d05d Graal 19.2 / Java 8
Graal 19.3 / Java 8
Graal 19.3 / Java 11
Graal 20.2 / Java 11
Graal 21.3 / Java 11
Graal 22.0 / Java 17
|
The path forward that I believe can start on is
|
How can we move forward on it, could you work on a Tomcat fork with the JSON refinements I proposed in the issue description? Are JSON refinements ok to be pushed on Tomcat 9 (this will likely break some native users) or should that be 10.1 only (so Spring Boot 3 only)? About the figures, Java 8 to Java 11 RSS memory increase is well know, but I am surprised by the RSS increase on latest versions. Maybe something we want to analyze more closely. |
@fhanik After more thoughts, we should be able to generate the substitution on Spring side at AOT level based on Spring Boot configuration, so on Tomcat side you can let it as it is (especially given the fact Tomcat 10 removed some old protocols I think). So I think you can focus on:
|
For protocols, we may be able to use conditional configuration and just rely on the framework level subtitution to trigger or not the config. Something like:
Not sure, but something to test (I don't remember why those reflection entries are needed if |
Ok so after a meeting with @fhanik and GraalVM team, we agreed on the following path:
public abstract class TomcatFeatureDetector {
private static final boolean HTTP_11_NIO_PROTOCOL = (System.getProperty("tomcat.http11.nio.protocol") != null);
private static final boolean HTTP_11_APR_PROTOCOL = (System.getProperty("tomcat.http11.apr.protocol") != null);
public static boolean isHttp11NioProtocolEnabled() {
return HTTP_11_NIO_PROTOCOL;
}
public static boolean isHttp11AprProtocolEnabled() {
return HTTP_11_APR_PROTOCOL;
}
}
(works for build time evaluation thanks to the inlining now enabled by default). public static ProtocolHandler create(String protocol, boolean apr)
throws ClassNotFoundException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
if (protocol == null || "HTTP/1.1".equals(protocol)
|| (!apr && org.apache.coyote.http11.Http11NioProtocol.class.getName().equals(protocol))
|| (apr && org.apache.coyote.http11.Http11AprProtocol.class.getName().equals(protocol))) {
if (apr && TomcatFeatureDetector.isHttp11AprProtocolEnabled()) {
return new org.apache.coyote.http11.Http11AprProtocol();
} else if (TomcatFeatureDetector.isHttp11NioProtocolEnabled()) {
return new org.apache.coyote.http11.Http11NioProtocol();
}
...
} else {
// Instantiate protocol handler
Class<?> clazz = Class.forName(protocol);
return (ProtocolHandler) clazz.getConstructor().newInstance();
}
}
|
@fhanik Any update? |
tomcat-embed-programmatic
tomcat-embed-core
There is a diminishing rate of return here. I'm currently working on the reflection files, but I won't go into separation and optimization if it truly doesn't yield more than 2.1MB in a Spring MVC application. Strangely, the difference between the two JAR files is 6MB in a Hello World style Apache Tomcat application. |
How far is this in context for spring boot and spring-boot-starter-web when using profile native? Will i get out of the box a smart decision? |
When you use Spring Boot 3 and |
Notice Tomcat |
tomcat-embed-programmatic
is an experimental Tomcat dependency designed to lower the memory footprint, but it seems possible to reach similar or even lower footprint with the defaulttomcat-embed-core
with a refined native configuration and an additional substitution.My analysis tends to show that unused protocols are the main source of inefficiency, and more generally optional features should probably be removed from default Tomcat native configuration. As a consequence, I propose to modify
tomcat-reflection.json
as following:DefaultServlet
entry to a newtomcat-reflection-default-servlet.json
fileHttp11Nio2Protocol
entry to a newtomcat-reflection-nio2.json
fileHttp11AprProtocol
&AprEndpoint
entries to a newtomcat-reflection-apr.json
fileOpenSSLImplementation
,SSLHostConfig
,SSLHostConfigCertificate
,OpenSSLConf
,AbstractJsseEndpoint
entries to a newtomcat-reflection-ssl.json
file{ "name":"org.apache.coyote.AbstractProtocol", "methods" : [{"name": "setPort","parameterTypes":["int"] }] }
entry (mandatory and previously covered as a side effect byHttp11AprProtocol
entry)Those optional feature could then be enabled by users on demand with
Args = -H:ReflectionConfigurationResources=/META-INF/native-image/org.apache.tomcat.embed/tomcat-embed-core/tomcat-reflection-nio2.json
for example in a/META-INF/native-image/native-image.properties
file. This principle is already use fortomcat-jni.json
which is not included by default.This will require on Spring side the following substitution because Tomcat
ProtocolHandler
completly defeats GraalVM static analysis:Notice that we can't move forward without a Tomcat update because
--exclude-config
innative-image.properties
is likely broken, see also this NBT issue.Unrelated, but likely worth to fix,
org.apache.tomcat.util.threads.res.LocalStrings
should probably be removed fromtomcat-resource.json
since there is an error message saying it does not exists.@fhanik Could you please provide your feedback on the proposed changes, and if it is possible to perform them on Tomcat 9 branch or if we will have to wait Tomcat 10.1?
The text was updated successfully, but these errors were encountered: