Java application servers are dead!
There. We said it. Don’t believe us? Eberhard Wolff checks for a pulse and shows us why we need to blow some life into the application server.
For years Enterprise Java has been a synonym for Application Servers. Deployment and operations of the Application Servers has changed little over the years – while the APIs have adapted to new paradigms and competitive programming models were introduced. Time to rethink this part of the traditional enterprise stack, too.
First let’s define the term “Application Server”: It is either a complete Java EE implementation like Wildfly or WebSphere or a Servlet container like Jetty or Tomcat. Most of today’s applications run on either kind of platform.
Application Server: One home for all applications?
Originally Application Servers were supposed to be a container for multiple applications. You can deploy any number of applications as WAR, EAR or JAR files into a single instance of an Application Server. The applications are isolated against each other using individual ClassLoaders. This way classes loaded in one application are completely separate from the code in any other application. This concept can lead to complex problems. Everyone working with Application Servers has already battled issues around class loading.
But classes are not the only resource an application consumes. Much more important are CPU, memory or the file system. In this regard the applications are not isolated at all. If you run a web application on the same application servers as a JMS application problems might arise. If the JMS system causes a lot of load the users of the web application will suffer. If the web application fills up the file system with a log file it will crash the JMS system, too.
These problems are the domain of operating systems: Their purpose is to isolate process from each other and allocate resources to them. To solve these issues the JVM would need to become an operating system.
But is an application server really home to multiple applications? Nowadays the opposite is often the case: One application is installed on a cluster of servers. Then the application can scale by distributing the load on several servers – and also to make the application fault tolerant. If one server fails one of the others can take over.
Application Servers provide a foundation for the applications running on them. This includes some APIs and other features:
- Two Phase Commit (2PC) is a feature that Java EE servers offer. Servlet containers don’t support it. 2PC is used to coordinate multiple transaction resource that should take part in a single transaction. Whether this feature makes sense could be the subject of an article in its own right. So we will only cover it shortly here. If 2PC is used to coordinate two databases the architecture might be wrong. Why is data distributed across two databases if it has such a close relation that it should be changed as part of a single transaction? If JMS and access to a database are done in the same transaction synchronization might be an alternative. It offers almost the same guarantees but is a lot less complex and resource consuming. And remember: Also 2 PC can fail – like any IT system. In modern Systems that use technologies such as REST or NoSQL 2PC cannot be used anyway. These technologies do not support 2PC. So more often than not 2PC is not that useful.
- Network and Threading are another area where infrastructure is needed. Usually Application Servers provide support for protocols like HTTP with optimizations like connection pooling. Also thread pools are used so no new threads need to be created for each connection. While every web application needs this it can be provided without an application server, too. Embedded servers like Tomcat and Jetty can be shipped with the application. Also Frameworks like Play or Vert.x come with their own support for HTTP – so no application server is needed to run them.
- Finally Application Servers provide several APIs and libraries that are part of the Java EE standard. This includes EJB, CDI, JPA or JSF to name a few. The Application Server offers an implementation of these APIs to build applications on. While these provide a great foundation to build an application they can also be used as libraries. In that case they would be added to the application as a JAR file instead. If you rely on the APIs as provided by the Application Server there are some challenges: The version of the library depends on the version of the Application Server. So new versions of the APIs cannot be used until a new version of the Application Server is in production – which might take quite some time. If a new version of the Application Server should be used you face a lot of effort – effectively a migration project. Ironically bundling APIs with the application will increase portability. So using the APIs that are part of the Application Server has more drawback than advantages. Also the APIs do not cover every need of every application – virtually all Enterprise Java application come with their own additional libraries. So in fact application developers have no choice: They will need to bundle at least some libraries with the application. But then they might as well bundle all of them and not use the APIs of the Application Server at all.
Application Servers originally promised an application independent infrastructure. It was supposed to serve as a generic base that applications can use. But in practice each application has its own infrastructure. For example an application might need a database connection pool to its database or some specific configuration. Sometimes even specific libraries are added to the Application Server for some applications. Of course that ties the Application Server to a specific application and should be avoided if at all possible.
A look at the dependencies
So let’s sum up the dependencies between application and Application Server:
- Applications use libraries and infrastructure provided by the Application Server. So applications depend on the Application Server.
- The Application Server depends on the application: It has specific configurations and is tuned for the application. For example it will provide all the database connection pools that the application need.
Figure 1 (above) shows these dependencies. As you can see Application Server and application are in a cyclic dependency. As we know from software architecture this means that they are really one component. They cannot be changed independently. So in essence Application Server are just another part of the application. This might be a surprise but think about the following questions:
- Can you deploy your application on a different server? Or on a different version of the same server? If not: Your application is closely tied to a specific Application Server.
- Are modifications to the setup of the server needed to install your application? Then your Application Server depends on the application. It is tuned for the application.
- Do you deploy any other application on the same Application Server? Could you? If not: This again means the Application Server is specially tuned for the application.
- Is the Application Server or an installation script in your version control? Then they share a common version – another strong indication that they are really one component.
Also note that Application Server focus on web applications. Batches, integration or Map/Reduce are not supported and need a different kind of infrastructure. Application Servers are no universal infrastructure. They just provide support for a specific kind of applications.
Continue reading part II on deployment, monitoring and microservices over here.