New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve exploded structure experience for efficient deployments #38276
Comments
About performance - In my project a data exchange between agents conducted via zip files. In one case I had 1k+ zips inside other zip and preparing data for agent by unziping all archives had taken minutes. pom dependency <dependency>
<groupId>com.google.jimfs</groupId>
<artifactId>jimfs</artifactId>
<version>1.2</version>
</dependency> repo is here - https://github.com/google/jimfs |
@bclozel and I had a bit of brainstorming on this one and he raised a use case that could become problematic. The solution above ignores the Spring Boot launcher on purpose to make the startup as straightforward as possible. However, it currently does not allow to augment the classpath, which is something that can be problematic. I don't know if this is something we need to take into consideration, but the POC could be adapted accordingly. |
The PoC has been updated to provide the ability to include additional libraries. This is typically used by buildpacks, for instance:
This copies One decision could help move the POC into something that can be reviewed. If the above is working for buildpacks, perhaps this could become the default mode of operation for layer tools as well. In other words, merging The structure above reuse the concept of "layers" to nicely separate concerns, except it does not expand the structure of the far jar (i.e. Merging the two means we need to bring back the launcher, perhaps as an opt-in? Keeping things separate would be less disturbing. However, the argument that buildpacks would work with the new mechanism, and has to for optimal CDS performance, means two mode of operations that might not be desirable. There are also a lot of infrastructure in I am happy to improve the proposal based on what the team decides. |
I spent some time looking at this last week and we discussed it a bit yesterday. The high-level conclusion was that we need to combine support for layers and CDS in a single command. This is necessary as the former needs to know about the latter so that the runner jar can go in the most frequently changing layer. At the moment, I'm imagining a single command with two options – one for CDS and one for layers – that can each be used individually and that can also be used together. There's quite a lot to figure out in terms of how we get from where we are now to where we want to be in a non-breaking manner. We hope that we might be able to look at this in March but there are other, higher priority items that require our attention in the 3.3.0-M2 timeframe. |
Yes. I guess I should have dumped my thoughts somewhere as I reached the same conclusion. Considering the buildpacks use case, I see it as a continuation of what we've started when we introduce layertools back then. Buildpacks still need all the features that we've built so far, but with a mode of operation that allows to further tune the application before final packaging. Given the classpath cannot be extended further, a mode of operation could be that Then, we need to review With buildpacks being updated upfront to support the new infrastructure, we could imagine a mode of operation where the build plugins introduce a flag that defaults to this There are a ton of things that I overlooked, but I am happy to dig further based on the team's guidance when it gets to this. Thanks! |
We'd like to maintain the current model where the archive produced by the build plugins is the single source of truth. It can then be run as-is using |
I've integrated Stephane's work into a new When building your application, the resulting uber jar contains the new jarmode This provides four ways of extracting:
|
@mhalbritter is only the first extraction option ( |
Hello @mhalbritter !
Using that option, simple
While I have been able to CDS'ize my app
I was wondering if there was any reason you did not pick @sdeleuze unpacking layout, which is:
The difference being Sebastien created 2 jars: one with a manifest only ( At first, I thought it was kind of the same, but when I tried adding a jar to the classpath (such as spring-cloud-bindings), I found out that with @sdeleuze layout, I could add it to the classpath with:
skipping the But with your layout, I can't skip
Using this, I could obtain such a layout:
First, not sure why there's an empty folder named
I don't think this is usable as such, please let me know if I missed something
the layout I got was:
No surprises here, it just worked.
and then
it worked but... apparently very few classes got cached (I don't know the command you used to create a CDS caching report) from the training run output; and anyway, with the caching dsa file, I just went from 1.2 secs to 1.0 secs; I think the JarLauncher somehow hid the classes to CDS... Seems like the JarLauncher way is not usable efficiently with CDS....
I obtained this layout:
This one, same as layers no launcher, I could not use it:
Not sure how to proceed with this one. Those are the results of my experimentation.
Sorry for the long post post merge; I wish I had provided the feedback before you merged, but that was so much easier for me to test using published SNAPSHOTs ! Thank you |
I don't understand why you seem surprised. The whole point of this issue is to provide a CDS friendly unpack structure as the extract method we had before this issue wasn't and we can't get rid of it. This is the "expected" behavior. |
|
Thanks for giving it a try!
This isn't CDS friendly, is it? Because you're adding the whole If you want to add additional JARs to the classpath, I think you need to edit the manifest. But I also think @sdeleuze wanted to investigate how that's possible without editing the JAR, maybe with some clever |
The |
Yeah, that's expected. As soon as you include
See #38276 (comment). |
Soo, i played around with it. If you want to add additional libraries, this works with:
where Java then takes the This is CDS friendly, too:
|
Hello all! So there remains the simple
It works fine (CDS'ifying worked too); not sure why I could not make it work during my testing 🤷 |
After a bit of discussion we want to change the names of the produced artifacts a bit. The plan is: If you don't specify So given this:
you'll get If you specify a directory with So given this:
you'll get |
It now extracts the contents of the JAR in a folder named after the JAR without the extension. It now also checks if the folder is empty. There's a new --force option to skip those checks. The "runner.jar" is now named like the uber JAR from which the extraction has been started. See gh-38276
You meant:
Right? |
Yeah, you're right, that's a typo. I've edited the original post. |
ZipInputStream can't cope with some non-deflated entries, see https://bugs.openjdk.org/browse/JDK-8143613. JarFile works better, but it doesn't support creation time / access time. See gh-38276
The reference guide has a section on unpacking the executable jar to get extra boost. It also has an additional hint for bypassing the bootlader with the impact on losing classpath ordering.
Our work on AppCDS (see spring-projects/spring-framework#31497) has shown that a predicable classpath has an impact on how effective the cache is going to be. Investigating a bit more, it looks doable to provide the above as a first class concept.
Here is a proposal that is hacking
layertools
with an additionalextract2
(sic) command: https://github.com/snicoll/spring-boot/tree/gh-38276Ignoring the fact that this does use layertools for convenience, you can execute the following on any repackaged archive:
This creates a directory with the following structure:
You can then run the app as follows (assuming you're in the same directory as the previous command):
The
run-app.jar
has the following characteristics:classpath.idx
, withapplication/my-app-1.0.0-SNAPSHOT.jar
being in frontmy-app-1.0.0-SNAPSHOT.jar
has some manifest entries of the original jar so thatpackage.getImplementationVersion()
continues to work.The work on this prototype has led to a number of questions:
Command
infrastructure and several utilities related to extracting/copying that are not specific to layers. If we want to go the same route with a different jar mode, a significant number of classes should be copied/reimplemented. Perhaps a single jar with a public API and sub-packages for layertools and this new mode could be an option?dependencies/BOOT-INF/lib
and a layer for the bootloader, we could use the same exact structure. Or perhaps the structure above could become a layer configuration (where all libs go todependencies
).run-app.jar
to have sensible File attributes. The command tries to respect the file attributes of files it extracts from the repackaged archive, butrun-jar.jar
is created on the spot.We have confirmed that with the prototype, AppCDS is effective (close to 95% classes loaded from the cache).
The text was updated successfully, but these errors were encountered: