I have several webapps deployed to production. I have used Tomcat as my servlet engine for ~10 years now. I'm considering moving to embedding Jetty model from the deploy-a-war-into-Tomcat model.
These webapps are deployed over several servers and some of the are horizontally scaled (using nginx IP hash based partitioning).
I see some advantages:
I can configure my servlet engine for a particular webapp (instead of having a generic configuration for Tomcat which is running several different webapps)
It's easier to horizontally scale my webapp by running multiple Jetty instances (configured to listen on different ports) on the same host. I could also do this with Tomcat (and I have run multiple tomcat instance on the same host in the past), but I've moved to using Debian packages (.deb archives) for deployment and it's not as easy to run multiple Tomcats using this method.
My deployment package (.deb) is more "complete" at build time i.e. I don't have to be sure the Tomcat instance is configured correctly.
And disadvantages:
More instances of a servlet engine running on a server means more resources being used
I've never used Jetty. I don't think I have any Tomcat-specific stuff going on in my webapps, but I'm not sure.
My main concern is the amount of resources that Jetty will use. If I had one Tomcat instance running 4 webapps, what will the difference in resources (memory/processor) be with four Jetty instances running?
This question is probably too open-ended, but I'm curious to know if I'm overlooking something or if anybody has any experience moving from Tomcat to (embedded) Jetty.
The web container I've found easiest to embed in a jar file (and it is still a valid WAR too) is Winstone (http://winstone.sourceforge.net/).
Jenkins - http://jenkins-ci.org/ - use this container so it has been pretty stress-tested. Note that it is Servlet 2.4 only.
Well I think there is no direct answer;
I might not fully understand the ".deb" part as I'm not a debian freak :)
I prefer having an instance of tomcat with a number of configurations aka CATALINA_HOME folders where you may specify apps and ports running, so you can always have all your configs separately and change the tomcat instance if needed.
Also, see related post:
Jetty: To embed or not to embed?
I also was used to Tomcat, so in my new project I tried using Jetty to learn about it.
In an enterprise environment (where you have production / testing / development servers) I would stick to Tomcat, mainly because it helps you in getting to separate code from configuration files (now I am working in setting the conf files in a separate jar, because that way when I move changes from testing to production they do not have to manually update the jars that I'll pass to sysadmin).
Other issue is that it looks like that Jetty has changed ownership not so long ago, and looking for info often got me to the old version.
Apart from that, using Jetty is not that different from Tomcat; had to run a little through docs for finding where everything is, but structure is (as last what I have seen, I have not tried anything too complicated) more or less like Tomcat.
Related
I'm working on a set of independent applications that share some common endpoints. The way I have it setup is to have each application be an independent war, and to have an embedded jetty server which provides those common endpoints. The embedded jetty server sets up the endpoints and loads the wars upon start. Each of our customers will have different applications installed, but will always have the common part, hence the need to have independently installable application wars.
This basic architecture is working ok, but in the development cycle I need to build each of the applications war to then run the whole thing with the embedded jetty server. I would like for the whole thing just to auto deploy when changes are made to any of the application files.
Any thoughts on how to do this?
Use a DeploymentManager with a WebAppProvider to find the webapps and deploy them (it will auto-redeploy on change).
Then setup your deployment to use exploded webapp directories, not war files.
You can even opt to setup deployment XML's in a single place, pointing to the contents of each webapp project's target/${project.build.finalName} directory (if using maven).
This works for many things, but not ALL things.
If you change classes or libs then there's a category of issues around memory leaks, and pinned classloaders, that can result in your reloaded webapp not behaving as you expect.
See
https://www.eclipse.org/jetty/documentation/current/preventing-memory-leaks.html
I'm trying to understand the model that Apache Tomcat adheres to, and the documentation apparently doesn't make sense to me.
As I understand it, Tomcat is a server for hosting a wide variety of services - so it's pretty generic. I've got this application that I'm trying to understand how to host, and its main method of deployment appears to be as a Tomcat-hosted web service - the application is called Camunda (its on github). After going through the docs for Camunda, my Tomcat directory becomes absolutely filled with Camunda-related jars, and config files, etc. The docs say to just plop everything right into the Tomcat lib folder, conf folders, etc.
Most of my experience with other "platform" / "service" style host applications has been that the application itself, in this case Tomcat, stays pretty untouched in its own directory. Through config files, etc, it knows how to host whatever it needs to host.
In the case of Tomcat, it seems that it's customary to basically "pollute" the Tomcat dir with a bunch of libs for the hosted content?
This is why I made the title "is Tomcat meant to be one install per application", because for all intents and purposes once you host something in Tomcat the directory becomes so coupled with that something that the Tomcat directory IS that something.
Is this normal? Just looking for some clarification in perhaps other terms that the docs put it, because the docs don't seem to be very clear to me.
Here is a link to the install process that I am following and referring to: https://docs.camunda.org/manual/latest/installation/full/tomcat/manual/
It's been a while since I've used Tomcat, but not only is it not one-install-per-application, it's not even one-install-per-virtual-host.
Tomcat is (amongst other things) a servlet container. The directory layout and such for servlets was standardized in the Java Servlet Specification v2.2. You can download the latest servlet spec here.
The docs say to just plop everything right into the Tomcat lib folder, conf folders, etc.
Hopefully they're talking about the ones in a .war file or similar, or shared libs in the shared locations. You can put shared libraries in a location where they can be reused across applications (or even virtual hosts), which was probably useful back when disk space was more expensive, but these days I assume most people put the libs for an app in the /WEB-INF/lib directory in the application's .war file.
This page talks about the "directory" layout of a .war file (which is basically a .jar with a particular structure).
It's true that typically .war files are expanded into subdirectories of the Tomcat installation directory, but as indicated in the answer that Dan_Maff linked to in a comment, you can modify the server.xml file to have it look elsewhere instead.
You can install a webapp called Manager that helps with installing, activating, deactivating, and managing web apps via .war files. (There's also a Host Manager for managing virtual hosts.)
All that said, you certainly could do one application per Tomcat install if you wanted. You'd need a reverse proxy in front of it (Apache, Nginx, etc.) so the same port (e.g., 80) could be used for the external URL of the various applications, and you'd need to assign each Tomcat install its own internal port for the reverse proxy to talk to.
We just discovered that every time we restart JBoss, all of our Java Web Start clients redownload all of their jars, instead of reusing the cached jars, even if our application has not changed.
From what I've seen on the web, Java Web Start does an HTTP HEAD to decide whether or not to download a jar. So I ran HTTP HEAD on all jars in our application, and discovered that after restarting JBoss, the modified time of all the jars has changed!
Why is this, and how can I fix it? The jars inside of my application archives have not changed at all. As near as I can tell, JBoss uses the time of startup or time of deploy as the modified time. This is going to completely short-circuit Java Web Start's ability to use cached jars from previous runs, if I understand correctly.
We use JBoss 6, if that's an issue. Previously we used JBoss 4. I want to check to see if we had the problem under JBoss 4, but we now have so many dependencies on the newer JBoss that it is going to take some work to make that test happen.
Try deploying your application as an exploded web application instead of a WAR file.
That would prevent JBoss having to decompress the application and potentially mess up the modification dates.
You'll have to handle updates to your app in a way that preserves modification dates, e.g., rsync, but that might be easier than downgrading or patching JBoss.
It looks like VFSUtils isn't maintaining the lastModifiedDate of the file when it mounts the filesystem to the tmp directory on server startup. You could patch the copy methods in that class to try to set the timestamp of the new file based on the values from the physical file.
As a response to the comment by chubbard: the problem does not occur with Tomcat (tomcat 7.0.21 to be precise).
There is an issue (https://issues.jboss.org/browse/JBVFS-177) created about the VFSUtils.unzip() which does not preserve timestamps while deploying (still applicable to JBoss 6.1).
As the issue is related to the unzip method the solution of blahdiblah may indeed works.
Another way would be to use Java Web Start with a version based (Modification of the jnlp with versionEnabled and creation of a version.xml).
Currently, we support many clients using the same web app, but each client has a different configuration for accessing their database, setting files etc. As the client list grows, updating the web apps is becoming increasingly arduous, and the duplication of resources is a waste of memory, file space, etc..
What we'd like to do is have a parent web app which is shared by all children web apps. Then have each child web app carry only files specific to them. When the child web app starts up, Tomcat loads the web app from the parent web app and then overrides any files defined in the child web app following an identical package structure.
We've been googling around and haven't found a ready or complete solution. Solutions we've looked at:
Tomcat common/share - could handle class and JAR files, but we don't see a way to handle static and JSP resources residing above the WEB-INF dir.
CATALINA_BASE appears to be more suited for running multiple instances of Tomcat which we'd rather avoid
A Maven possible solution, but we are not big fans of Maven, so would rather avoid it also.
Anybody have suggestions or ideas on how to solve this? If Tomcat configuration is not possible, what about a different application server (such as Glassfish) or a tool for doing dynamic file updated (such as OSGi, rsync). Would like to remove the resource duplication if possible.
Thank you.
There is no such thing as "parent" or "child" webapps. It's not part of J2EE spec and AFAIK it's not supported by any application server.
That said, your problem is twofold:
1) Having shared resources. This part is pretty easy assuming "resources" means static resources (images / CSS / javascript / etc...).
If they are truly shared (e.g. you don't need to have a separate version in some of your webapps), host them elsewhere (separate "common" webapp or put Apache in front of your Tomcat and host them there.
If you do need to have "local" versions of some of those resources you may be able to do some clever conditional URL rewriting or simply write a servlet that would check whether particular resource exists locally and, if not, take it from "common" location.
Precompile your JSPs so you only have to deal with JARs.
If your Tomcat instance only hosts your apps, you can indeed put your JARs in shared (or lib in the latest version); otherwise you can deploy them with each application .
2) Simplifying deployment. I'm not really sure what the big problem is here... It's rather trivial to write an Ant (batch, shell, what have you) script that would assemble and deploy WARs based on "common" and "per-app" directory structures.
Alternatively, you may want to take a look at using JNDI to severely reduce the number of files that have to be deployed (in theory, to a single context.xml for each application).
You can build parent-child hierarchy if you use Spring at your web-apps - Using a shared parent application context in a multi-war Spring application.
I.e. you can define all shared stuff at the 'parent' context and have 'child' contexts just to use it.
If all you had was setting file and configuration changes you could manage these through the context.xml and then you can point the docBase of each application context at a common directory for all the applications to share the same source.
the drawback to this is changes to the application will require a tomcat restart.
This does not however solve your problem if you want to override logic.
A option that I am exploring for a similar scenario is to move the client custom portion into ajax widgets / gadgets. Then have it be part of the configuration files to tell the application which version of the gadget to pull for which client.
you can review documentation for having applications share a docbase here http://tomcat.apache.org/tomcat-5.5-doc/config/context.html
I'm currently working on a j2ee project that's been in beta for a while now. Right now we're just hammering out some of the issues with the deployment process. Specifically, there are a number of files embedded in the war (some xml-files and .properties) that need different versions deploying depending on whether you are in a dev, testing or production environment. Stuff like loglevels, connection pools, etc.
So I was wondering how developers here structure their process for deploying webapps. Do you offload as much configuration as you can to the application server? Do you replace the settings files programmatically before deploying? Pick a version during build process? Manually edit the wars?
Also how far do you go in providing dependencies through the application servers' static libraries and how much do you put in the war themselves? All this just to get some ideas of what the common (or perhaps best) practice is at the moment.
I think that if the properties are machine/deployment specific, then they belong on the machine. If I'm going to wrap things up in a war, it should be drop-innable, which means nothing that's specific to the machine it's running on. This idea will break if the war has machine dependent properties in it.
What I like to do is build a project with a properties.example file, each machine has a .properties that lives somewhere the war can access it.
An alternative way would be to have ant tasks, e.g. for dev-war, stage-war, prod-war and have the sets of properties part of the project, baked in in the war-build. I don't like this as much because you're going to end up having things like file locations on an individual server as part of your project build.
I work in an environment where a separate server team performs the configuration of the QA and Production servers for our applications. Each application is generally deployed on two servers in QA and three servers in Production. My dev team has discovered that it is best to minimize the amount of configuration required on the server by putting as much configuration as possible in the war (or ear). This makes server configuration easier and also minimizes the chance that the server team will incorrectly configure the server.
We don't have machine-specific configuration, but we do have environment-specific configuration (Dev, QA, and Production). We have configuration files stored in the war file that are named by environment (ex. dev.properties, qa.properties, prod.properties). We put a -D property on the server VM's java command line to specify the environment (ex. java -Dapp.env=prod ...). The application can look for the app.env system property and use it to determine the name of the properties file to use.
I suppose if you have a small number of machine-specific properties then you could specify them as -D properties as well. Commons Configuration provides an easy way to combine properties files with system properties.
We configure connection pools on the server. We name the connection pool the same for every environment and simply point the servers that are assigned to each environment to the appropriate database. The application only has to know the one connection pool name.
wrt configuration files, I think Steve's answer is the best one so far. I would add the suggestion of making the external files relative to the installation path of the war file - that way you can have multiple installations of the war in the one server with different configurations.
e.g. If my dev.war gets unpacked into /opt/tomcat/webapps/dev, then I would use ServletContext.getRealPath to find the base folder and war folder name, so then the configuration files would live in ../../config/dev relative to the war, or /opt/tomcat/config/dev for absolute.
I also agree with Bill about putting as little as possible in these external configuration files. Using the database or JMX depending on your environment to store as much as it makes sense to. Apache Commons Configuration has a nice object for handling configurations backed by a database table.
Regarding libraries, I agree with unknown to have all the libs in the WEB-INF/lib folder in the war file (self-packaged). The advantage is that each installation of the application is autonomous, and you may have different builds of the war using different versions of the libraries concurrently.
The disadvantage is that it will use more memory as each web application will have its own copy of the classes, loaded by its own class loader.
If this poses a real concern, then you could put the jars in the common library folder for your servlet container ($CATALINA_HOME/lib for tomcat). All installations of your web application running on the same server have to use the same versions of the libraries though. (Actually, that's not strictly true as you could put overriding versions in the individual WEB-INF/lib folder if necessary, but that's getting pretty messy to maintain.)
I would build an automated installer for the common libraries in this case, using InstallShield or NSIS or equivalent for your operating system. Something that can make it easy to tell if you have the most up to date set of libraries, and upgrade, downgrade, etc.
I usually make two properties files:
one for app specifics (messages, internal "magic" words) embedded in the app,
the other for environment specifics (db access, log levels & paths...) exposed on each server's classpath and "sticked" (not delivered with my app). Usually I "mavenise" or "anttise" these one to put specific values, depending on the target env.
Cool guys use JMX to maintain their app conf (conf can be modified in realtime, without redeploying), but it's too complex for my needs.
Server's (static ?) libraries: I strongly discourage server library use in my apps as it adds dependency to the server:
IMO, my app must be "self-packaged": dropping my war, and that's all. I have seen wars with 20 Mbs of jars in it, and that's not disturbing for me.
A common best-practice is to limit your external dependencies to what is offered by the J2EE dogma: the J2EE API (use of Servlets, Ejbs, Jndi, JMX, JMS...). Your app has to be "server agnostic".
Putting dependencies in your app (war, ear, wathever) is self-documenting: you know what libraries your app depends on. With server libs, you have to clearly document these dependencies as they are less obvious (and soon your developers will forget this little magic).
If you upgrade your appserver, chances that the server lib you depends on will also change. AppServer editors are not supposed to maintain compatibility on their internal libs from version to version (and most of the time, they don't).
If you use a widely-used lib embedded in your appServer (jakarta commons logging, aka jcl, comes to mind) and want to ugrade it's version to get the latest features, you take the huge risk that your appServer will not support it.
If you relies on a static server object (in a static field of a server class, e.g. a Map or a log), you'll have to reboot your appserver to clean this object. You loose the ability to hot-redeploy your app (old server object will still exists between redeployments). Using appServer-wide objects (other than those defined by J2EE) can lead to subtle bugs, especially if this object is shared between multiple apps. That's why I strongly discourage the use of objects which resides in a static field of an appServer lib.
If you absolutely need "this object in this appserver's jar", try to copy the jar in your app, hoping there's no dependency on other server's jar, and checking your app's classloading policy (I take the habit to put a "parent last" classloading policy on all my apps: I'm sure I won't be "polluted" by server's jars - but I don't know if it is a "best practice").
I put all configuration in the database. The container (Tomcat, WebSphere, etc) gives me access to the initial database connection and from then on, everything comes out of the database. This allows for multiple environments, clustering, and dynamic changes without downtime (or at least without a redeploy). Especially nice is being able to change the log level on the fly (although you'll need either an admin screen or a background refresher to pick up the changes). Obviously this only works for things that aren't required to get the app started, but generally, you can get to the database pretty quickly after startup.