11

I have one WAR ( app.war ) and one container ( Tomcat, Jetty, Glassfish, whatever ). My goal is to deploy, on demand, hundreds of instances of this same web application on the container.

http://foo/app1 --> app.war
http://foo/app2 --> app.war
http://foo/app3 --> app.war 
...
http://foo/appN --> app.war

Some obvious ways of achieving this:

  • In Tomcat, create one context.xml file for each app ( named appN.xml ), all pointing to the same WAR. Other containers have similar methods
    • Problem with this approach: It will explode the WAR N times, taking up a lot of disk space
  • Use symbolic links to create webapp/{app1,app2,appN} folders pointing to an exploded version of app.war. This prevents the disk space explosion, but the JVM is still loading many duplicate JARs to memory
  • Use some shared lib folder to contain most jars ( and a combination of the previous two options ).

I wonder if there is a better method to do this. Ideally, creating a new instance should not take up ANY more disk space ( other than marginal configuration files ) and only take up memory related to thread execution stacks and other runtime allocations.

Any ideas?

Aldo Bucchi
  • 425
  • 5
  • 10
  • Would you consider a rewrite of the application as a multitenanted app? If there are 100s of instances of exactly the same WAR and code, I'd consider designing just 1 WAR that would be deployed to the root context? – beny23 Apr 17 '12 at 00:03
  • @beny23 An elaborate explanation could help me also with some things I'm working on. Any chance you can provide one? – Andrew T Finnell Apr 17 '12 at 00:28
  • I posted an answer below, but if you tell us why you want to do this, I might be able to post a better one. – ccleve Apr 17 '12 at 01:59
  • Thanks for the tips ;) This is sort of a multi-tenant setup. I need to provision one "identical" app for each user that should run in its own context. The reason the app is built this way is beyond the scope of this post, but there is a strong business case driving this. – Aldo Bucchi Apr 17 '12 at 03:06
  • If you give us the business case, I may have more suggestions. Is it security-related? Different contexts won't help. Is it that each user needs their own URL path? You can do that with URL rewriting. Or giving each user a subdomain (which is easy to do with a servlet filter). – ccleve Apr 17 '12 at 15:46

5 Answers5

5

Jetty added support for what you looking for a while back with what are called overlays.

http://wiki.eclipse.org/Jetty/Tutorial/Configuring_the_Jetty_Overlay_Deployer

Copying a bit from the wiki page:

  • You can keep the WAR file immutable, even signed, so that it is clear which version you have deployed.
  • All modifications you make to customise/configure the web application are separate WARs, and thus are easily identifiable for review and migration to new versions.
  • You can create a parameterised template overlay that contains common customisations and configuration that apply to many instances of the web application (for example, for multi-tenant deployment).
  • Because the layered deployment clearly identifies the common and instance specific components, Jetty is able to share classloaders and static resource caches for the template, greatly reducing the memory footprint of multiple instances.
jesse mcconnell
  • 7,102
  • 1
  • 22
  • 33
2

Apologies for being a little bit off-topic, but in my view, your scenario shouts "multi-tenancy" application, so that you've got a single application which will service multiple "tenants" (customers).

With regard to multi-tenancy setups, the following considerations would have to be considered:

Benefits of multitenancy:

  • Shared code means that a bug fixed for one customer is fixed for all (this can be a disadvantage as well if different customers have different views on what constitutes a bug and what constitutes a feature).
  • Clustered deployment can share the load between customers (however, need to ensure that peak capacity is available for all customerS).

Downsides:

  • Code is going to be a bit more complex as queries need to ensure that the "discrimination" between customers works without accidentially exposing customers to each others data.
Community
  • 1
  • 1
beny23
  • 34,390
  • 5
  • 82
  • 85
1

You could configure Apache on the front end (mod_proxy/mod_proxy_ajp) to point named virtual hosts to a single WAR deployed on Tomcat. Your application should be designed/written in a way to service all request -- per website name specific configuration could be stored in a database or as a configuration file within your application -- your app would just need to probe the user's requesting domain name to ensure the correct settings are applied (once per session). Generally speaking, you should be able to solve this with one application. Great developers are LAZY.

Jason Grant Taylor
  • 1,239
  • 1
  • 8
  • 2
0

Well if this is for an experiment then any of the methods you listed can work.

If this is for production then I would recommend against this. While I have not tested ALL containers, the containers i have used lead me to be believe it is much more resilient to simply provision headless VMs with containers. Linux VMs can be very small and with VM technology you can add or subtract as many instances as needed.

If you truly want to have a dynamically growing solution then you should look to eliminate single points of failure rather then try to lump your entire world into one.

If you truly need "up to the second" load expansion/contraction then you should look at AWS or CloundFoundry.

TheCodeArtist
  • 21,479
  • 4
  • 69
  • 130
stimpy
  • 492
  • 1
  • 6
  • 18
  • Yes, we were provisioning one machine per user/app-instance. The main problem is costs. Some users don't use their apps for a while and I would like to move them to a "shared" machine. Spawning one VM process per instance is also possible, but I am trying to figure out which method has less overhead: multiple VMs/Containers or multiple instances per container. – Aldo Bucchi Apr 17 '12 at 03:11
0

If you're using Jetty, you can add contexts programmatically.

WebAppContext webapp = new WebAppContext();
webapp.setBaseResource(myBaseDirectory);
webapp.setContextPath(myContextPath);

Just do this in a loop for all your contexts. It should have close to zero diskspace overhead.

There's probably a similar way to do it in Tomcat.

ccleve
  • 15,239
  • 27
  • 91
  • 157