Why and how to use Jetty in mission-critical production

This article is a summary of a seminar I had on the topic. If it seems like it’s a continuation of an existing discussion that’s because, to some extent, it is. If you haven’t been discussing exchanging your app server, this article probably isn’t very interesting to you.

By putting the application server inside my application instead of the other way around, I was able to leap tall buildings in a single bound.

The embedded application server

This is how I build and deploy my sample application to a new test environment (or to production):

  1. mvn install
  2. scp someapp-server/target/someapp-1.0.onejar.jar appuser@appserver:/home/appuser/test-env1/
  3. ssh appuser@appserver "cd /home/appuser/test-env1/ && java -jar someapp-1.0.onejar.jar&"

This require no prior installed software on the appserver (with the exception of the JVM). It requires no prior configuration. Rolling back is a matter of replacing one jar-file with another. Clustering is a matter of deploying the same application several times.

In order to make this work in a real environment, there are a many details you as a developer need to take care of. As a matter of fact, you will have to take responsibility for your operational environment. The good news is that creating a good operational environment is not more time-consuming than trying to cope with the feed and care of a big-a Application Server.

In this scheme every application comes with its own application server in the form of jetty’s jar-files embedded in the deployed jar-file.

The advantages

Why would you want to do something like this?

  • Independent application: If you’ve ever been told that you can’t use Java 1.5 because that would require an upgrade of the application server. And if we upgrade the application server, that could affect someone else adversely. So we need to start a huge undertaking to find out who could possibly be affected.
  • Developer managed libraries: Similar problems can occur with libraries. Especially those that come with the application server. For example: Oracle OC4J helpfully places a preview version of JPA 1.0 first in your classpath. If you want to use Hibernate with JPA 1.0-FINAL, it will mostly work. Until you try to use a annotation that was changed after the preview version (@Discriminator, for example). The general rule is: If an API comes with your app server, you’re better served by staying away from it. A rather bizarre state of affairs.
  • Deployment, configuration and upgrades: Each version of the application, including all its dependencies is packaged into a single jar-file that can be deployed on several application server, or several times on the same application server (with different ports). The configuration is read from a properties-file in the current working directory. On the minus side, there’s no fancy web UI where you can step through a wizard to deploy the application or change the configuration. On the plus side, there is no fancy web UI …. If you’ve used one such web UI, you know what I mean.
  • Continuous deployment: As your maven-repository will contain stand alone applications, creating a continuous deployment scheme is very easy. In my previous environment, a cron job running wget periodically was all that was needed to connect the dots. Having each server environment PULL the latest version gives a bit more flexibility if you want many test environments. (However, if you’re doing automated PUSH deployment, it’s probably just as practical for you).
  • Same code in test and production: The fact that you can start Jetty inside a plain old JUnit test means that it is ideal for taking your automated tests one step further. However, if you test with Jetty and deploy on a different Application Server, the difference will occasionally trip you. It’s not a big deal. You have to test in the server environment anyway. But why not eliminate the extra source of pain if you can?
  • Licenses: Sure, you can afford to pay a few million $ for an application server. You probably don’t have any better use for that money, anyway, right? However, if you have to pay licenses for each test-server in addition, it will probably mean that you will test less. We don’t want that.
  • Operations: In my experience, operations people don’t like to mess around with the internals of an Application Server. An executable jar file plus a script that can be run with [start|status|stop] may be a much better match.

The missing bits

Taking control of the application server takes away a lot of complex technology. This simplifies and makes a lot of stuff cheaper. It also puts you back in control of the environment. However, it forces you to think about some things that might’ve been solved for you before:

  • Monitoring: The first step of monitoring is simple: Just make sure you write to a log file that is being monitored by your operations department. The second step requires some work: Create a servlet (or a Jetty Handler) that a monitoring tool can ping to check that everything is okay. Taking control of this means that you can improve it: Check if your data sources can connect, if your file share is visible, if that service answers. Maybe add application-calibrated load reporting. Beyond that, Jetty has good JMX support, but I’ve never needed it myself.
  • Load balancing: My setup supports no load balancing or failover out of the box. However, this is normally something that the web server or routers in front of the application server anyway. You might want to look into Jetty’s options for session affinity, if you need that.
  • Security: Jetty supports JAAS, of course. Also: In all the environments I’ve been working with (CA SiteMinder, Sun OpenSSO, Oracle SSO), the SSO server sends the user name of the currently logged in user as an HTTP header. You can get far by just using that.
  • Consistency: If you deploy more than one application as an embedded application server, the file structure used by an application (if any) should be standardized. As should the commands to start and stop the application. And the location of logs. Beyond that, reuse what you like, recreate what you don’t.

Taking control of your destiny

Using an embedded application server means using the application server as a library instead of a framework. It means taking control of your “main” method. There’s a surprisingly small number of things you need to work out yourself. In exchange, you get the control to do many things that are impossible with a big-A Application Server.

Thanks to Dicksen, Eivind, Terje, Kristian and Kristian for a fun discussion on Jetty as a production app server

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.

Print This Post Print This Post
  • Paul c
    I'm beginning to wonder is the whole idea of a "container" is really a good idea. Not just with respect to web servers but more generally. Its one of the reasons I like Camel - I can have an application with ESB functionality without needing a container. In fact I'm working on a system using embedded Camel and Jetty all in the one app.

    Even if you use a gazillion libraries including hefty ones like spring hibernate camel etc in terms of actual megabytes of space it doesn't really amount to much on a modern system so why not keep each application stand-alone and avoid all those container related dependency, unit testing, classloading etc etc problems.

    IMO we've been brainwashed over the years to equate production environments with containers in the java world.
  • tarjeihuse
    One jar, that is the way to do it. Here are some implementation pointers.

    Installing and configuring applicationservers is quite a drag and often hard to automate with tools like puppet or cfengine.

    I've switched to doing this for all my different services with good results. With maven you can do this using the winstone-maven plugin very easily.

    Another option is using the jetty-runner that was created for Jetty 7. The camel-web-standalone component in the Apache Camel project contains an example for creating a combined jar for jetty-runner and all dependencies.

    Hope this helps someone.
  • Hi, Terjei

    winstone-maven-plugin looks very nice. What I like about my approach is the fact that I regain control of the main-method. Perhaps a sign that I am a control freak. And I suspect you can do the same with winstone if you want to.

    Good tip. Thanks.
  • When you need to deploy a new version of the app how do you handle this? It seems like you would need to stop the original server and then start up a new one. The JVM can take some time to boot, not to mention allowing time to hotspot to optimize the new code.. So stopping the server and waiting for the new one to boot doesn't seem too graceful. Is there a way to reuse the previous JVM? (I'm new to the JVM.) I like this approach but I am struggling with how to deal with deployments and restarts.
  • Markus
    If you are trying to maximize availability of a service than you need to have a loadbalancer. The standard schema for web applications is a reverse proxy + multiply instances of a service (aka jetty webserver). As a reverse proxy many projects use Apache or Nginx.

    In case if you need to redeploy webapplication or restart server, load-balancer will take care of the traffic and send all requests to other available webservers. Using this way you could redeploy webapp instances one-by-one.

    BTW apache/nginx could also take care of other routine tasks such as DDoS prevention/Gzip response compression/SSL handling/caching immutable responses from the servlet engine/....

    If you are interested more in such architecture I recommend you to read this book http://www.amazon.com/Scalable-Internet-Archite...
  • Thanks for the quick reply. I am using nginx reverse proxy currently (with SSL) and am taking the approach you have recommended. It seems problematic though for apps which only need one jetty instance as requests will be backed up for several seconds as the other process boots up. I suppose I can add additional ports and stop one when a new one fires up assuming I have the additional ram required to do that.
  • Markus
    The main pro here with "one jar application" is that you cut dependency to your AppServer. Or to be precise you embed the appserver inside the jar and deploy them together. It is a good thing as in many companies you are not allowed to use new API/jdk because the prod version of AppServer does not support it yet. And admins do not want to upgrade the AppServer as it may break other installed applications. It is a chicken-egg problem. Cutting dependency to AppServer *you* decide what version to use as your deployment completely independent from other applications.

    Another thing with "one jar app" is unification. If you deploy all your applications the same way - it makes administration things easier. We use "one jar app" way you described. Not only for Web applications but also for RPC applications - we embed small RPC server based on Apache Thrift inside jar. So all our applications just *.jar and we start them using "java -jar app.jar"
  • Thank you for a good comment, Markus. Installing other server libraries inside of the executable Jar is a good idea.
  • Ben Johnson
    Interesting read. I'm new to web development, but you indicated that deployment simply required the JVM to be installed, but your first command is "mvn install", which looks like a Maven command (I don't know Maven yet). Is Maven a prerequisite on the app server?
  • Maven is a prerequisite when *building* the application. At least with the example code I provided (you could make a similar maven-free build).

    When the application is built (with the embedded application server), the JVM is the only prerequisite when you want to *run* it.

    Hope this makes sense.
  • Ben Johnson
    Oh, I see, I misunderstood. In your deployment instructions above, step 1 (mvn install) is actually building the application on your development box, not deploying it (I understand it makes good sense to ensure the application is built against the latest source code before deploying it). Step 2 does the deployment and step 3 starts it. Thanks, this has been helpful!
  • Thank you for you comments, Ben. I've updated the article to say "this is how I build and deploy" instead of just "this is how I deploy".

    Please let me know if you have any other questions or input regarding this topic.
  • pnyheim
    Great read, and I would love to see something like this at my customer, however as this is a very large corporation, they have corporate guidelines and operations teams and what not that needs to be followed and catered to. And this is a far bigger challenge to change as it involves people, processes and policies.

    Any thoughts on how to get such a ball rolling?
  • Thank you for a good comment.

    When I introduced an embedded application server in my previous job, I was faced with the same issues. However, when I started talking to the operations teams, I realized that in our location, they wanted things to look like Unix services. They didn't particularly care for the application server.

    The operations teams had issues that we were able to solve by simplifying and customizing the deployment. By talking with them and addressing their concerns, we gained a good ally in replacing the app server.

    Of course, this is likely to vary wildly from place to place.

    But here's where I would start: Make sure to sit next to someone from the operations team at the next company party.
blog comments powered by Disqus
Creative Commons Attribution 3.0 Unported
This work is licensed under a Creative Commons Attribution 3.0 Unported.