[
https://issues.apache.org/jira/browse/TOMEE-4293?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17799368#comment-17799368
]
Jonathan Gallimore commented on TOMEE-4293:
-------------------------------------------
Thank you for the very thorough ticket, complete with the attachments. I'll
take a look. To set expectations, in a .war application with the EJBs embedded,
this is what I'd expect, and is a requirement for Java EE 6 Web Profile (as I
have run into this, and this specific block of code before), and the
expectation is that this behaviour is different to an ear file deployment.
> WAR-wide EJB local refs linked to each EJB at startup
> -----------------------------------------------------
>
> Key: TOMEE-4293
> URL: https://issues.apache.org/jira/browse/TOMEE-4293
> Project: TomEE
> Issue Type: Bug
> Components: TomEE Core Server
> Affects Versions: 8.0.16
> Reporter: Nicolas Ternisien
> Priority: Major
> Attachments: collapsedear-bug-ear.catalina.out,
> collapsedear-bug-ear.ear, collapsedear-bug-project.tar.gz,
> collapsedear-bug.war, collapsedear-bug.war.catalina.out
>
>
> h3. High Memory Consumption / Load Time when using WAR file (as "Collapsed
> EAR") vs EAR file
> We're currently experimenting the migration of an EAR project from Oracle
> Weblogic application server to TomEE.
> While conducting this experiment, we also tried to see if we could rely on
> "Collapsed EAR" approach, ie, simplifying the application by providing a
> single WAR file with EJBs embedded into it, instead of multiple ejb and web
> modules inside the EAR file.
> The project is quite big with:
> * 1992 EJBs in EJB Module (+ CDI beans)
> * 1193 EJBs in Web Module (+ CDI beans for JAX RS resources)
> * (and a total of 8569 injection points via @EJB annotation - you can keep
> this info for later)
> Still, with the EAR approach, total loading time is about 1min, with 3.1 GB
> JVM memory usage, so this is quite good (way faster than Oracle Weblogic).
> When trying the alternative approach via a WAR file (including the EJB module
> as JAR), the startup takes huge time (30 to 40 minutes) and JVM memory
> consumption goes up to 8.7 GB.
>
> h3. How to Reproduce
> We tried to investigate this difference and we have identified the bottleneck
> (via TomEE startup debugging) at JndiEncInfoBuilder, more especially at
> JndiEncInfoBuilder.buildEjbRefs() where each EJB has the *whole* list of
> ejbLocalRef of all the EJBs of the entire application. We are not very sure
> if this is an expected behavior, but each EJB referenced is linked to the
> 8569 injection points discovered.
> Wed've setup a dedicated project (in attachment), with 2 different deployable
> binaries:
> * collapsedear-bug.war
> * collapsedear-bug-ear.ear
> So that we could compare the two processes at loading time.
> Note the deployment is performed via the "tomee/apps" folder. Please note we
> only deployed on archive at a time, to be able to properly compare the two
> startups.
> Both WAR and EAR contains an EJB module, named "collapsedear-bug-ejb", which
> itself contains the following basic EJB NumberService.java:
> {code:java}
> package org.lastnico.collapsedear.bug.ejb;
> import java.util.Random;
> import javax.annotation.PostConstruct;
> import javax.ejb.EJB;
> import javax.ejb.Singleton;
> import javax.ejb.Startup;
> import org.slf4j.Logger;
> import org.slf4j.LoggerFactory;
> @Singleton
> @Startup
> public class NumberService {
> private static Logger log = LoggerFactory.getLogger(NumberFinder.class);
> @PostConstruct
> public void start() {
> log.info("Starting {}", this.getClass());
> }
> @EJB
> private NumberFinder userFinder;
> public long save() {
> return new Random().nextLong();
> }
> }
> {code}
>
> Of course, this project is much more simple (less than 5 EJBs in total), so
> we cannot notice it from memory consumption or loading time, but here are the
> debugging output:
>
> h4. collapsedear-bug.war
> At startup, with a debugging breakpoint, watching for "NumberService" EJB
> registration
> at
> {code}
> org.apache.openejb.config.JndiEncInfoBuilder.build(final JndiConsumer
> jndiConsumer, final String ejbName, final String moduleId, final URI
> moduleUri, final JndiEncInfo moduleJndiEnc, final JndiEncInfo compJndiEnc)
> throws OpenEJBException {
> {code}
> {code:java}
> moduleId = collapsedear-bug-ejb
> JndiConsumer.ejbClass = "org.lastnico.collapsedear.bug.ejb.NumberService"
> JndiConsumer.ejbLocalRef =
> {java:comp/env/org.lastnico.collapsedear.bug.ejb.NumberService/userFinder=EjbLocalRef{name='java:comp/env/org.lastnico.collapsedear.bug.ejb.NumberService/userFinder',
> local=org.lastnico.collapsedear.bug.ejb.NumberFinder, link='null',
> mappedName='null', lookupName='null'},
> java:comp/env/org.lastnico.collapsedear.bug.war.GreetingResource/numberFinder=EjbLocalRef{name='java:comp/env/org.lastnico.collapsedear.bug.war.GreetingResource/numberFinder',
> local=org.lastnico.collapsedear.bug.ejb.NumberFinder, link='null',
> mappedName='null', lookupName='null'},
> java:comp/env/org.lastnico.collapsedear.bug.war.GreetingResource/calculatorFront=EjbLocalRef{name='java:comp/env/org.lastnico.collapsedear.bug.war.GreetingResource/calculatorFront',
> local=org.lastnico.collapsedear.bug.war.CalculatorFront, link='null',
> mappedName='null', lookupName='null'},
> java:comp/env/org.lastnico.collapsedear.bug.war.CalculatorFront/numberFinder=EjbLocalRef{name='java:comp/env/org.lastnico.collapsedear.bug.war.CalculatorFront/numberFinder',
> local=org.lastnico.collapsedear.bug.ejb.NumberFinder, link='null',
> mappedName='null', lookupName='null'}}{code}
>
> You can see that ejbLocalRef contains 8 different injection points, while
> NumberService has only a single injection point (NumberFinder). Most of them
> actually relates to *other* EJBs in the application. If we skip and go to the
> next EJB JNDI registration, the exact same complete list of ejbLocalRef is
> provided.
> h4. collapsedear-bug-ear.ear
> At the opposite, when debugging the startup of the equivalent EAR file
> Here are the debugging info extracted:
> {code}
> moduleId = collapsedear-bug-ejb
> JndiConsumer.ejbClass = "org.lastnico.collapsedear.bug.ejb.NumberService"
> JndiConsumer.ejbLocalRef =
> {java:comp/env/org.lastnico.collapsedear.bug.ejb.NumberService/userFinder=EjbLocalRef{name='java:comp/env/org.lastnico.collapsedear.bug.ejb.NumberService/userFinder',
> local=org.lastnico.collapsedear.bug.ejb.NumberFinder, link='null',
> mappedName='null', lookupName='null'}}
> {code}
> This time, as expected, the NumberService EJB only has 1 single EJB local
> ref, matching its single injection point.
> h4. Suspicion
> I suspect the reason for this is that MergeWebappJndiContext indistinctely
> copies all possible EJB local refs, and hence each EJB receives the whole
> list of injection points (from all registered EJBs in the application).
> In the scenario of our application described earlier, we end up with (1992 +
> 1193) * 8569 declared EJB local refs, which slows down the whole startup and
> wastes huge quantity of memory.
> You can find in attachments both the WAR and EAR file, as well as the log
> output of both deployable artifacts, and the source code of the respective
> Maven project. Please note this was tested against TomEE 8.0.16 because this
> is our current target, but I assume this issue could also be reproduced on
> TomEE 9.1.2.
> Thanks!
--
This message was sent by Atlassian Jira
(v8.20.10#820010)