Nowadays, the concept of microservices is more than a simple novelty. With the advent of DevOps and the boom of container technologies and deployment automation tools, microservices are changing the way developers structure their applications. See how microservices can be a valid option for Java EE developers and how Payara Micro can help them by providing a perfect platform.
Microservices in general
The main purpose of a microservice architecture is to break down an application into smaller standalone components that are easier to handle, deploy, scale and maintain in the long term. Sounds familiar? Yes, this is something that many developers have been doing since a long time ago! Encapsulation, cohesion and a good understanding of service-oriented architectures have helped them apply this “divide and conquer” strategy to software architecture for many years and will do so in the future as well.
So, what’s the advantage of microservices then? Microservices are better understood when compared with their traditional counterparts: monolithic applications.
Monolithic applications, or monoliths, are usually big enterprise applications structured into a single deployable package. If you want to introduce a new component or update an existing one, the entire monolith must be updated at once. This is the way enterprise applications were usually developed, focusing on the concept of tiers (UI, middleware-services, persistence, data) and the segregation of concerns across these tiers.
So, while a monolith is just a normal application developed with traditional means, the microservices approach would be to break down such an application into separate components (or services), so that each component would fulfill the following criteria:
- Have a small
- Be cohesive, e.g. focus on a single feature or functionality
- Expose an interface to be used by other services of the same application or other external services.
- Allow independent management, so that it can be coded, tested, deployed and scaled faster.
- Be responsible for handling its own data.
- Be completely isolated from other services, such as no direct dependencies are needed.
Monoliths vs. Microservices
So does that mean that microservices should be used instead of traditional monolithic applications in all cases? Not necessarily. Microservices not only define a new architectural style, but also demand that development teams build applications in a different manner.
There are also some advantages and disadvantages regarding when to use a monolith and when to use microservices:
Cost of changes across all tiers is high. A change of a single feature means a redeployment of the whole unit.
Changes are easy to implement and not costly as they are targeted to specific services only.
All components belong to a single unit, there’s no communication overhead.
Remote calls are needed for communication between services, so this overhead factors in the performance of the application.
The entire development team must be familiarized with the design and composition of the entire application.
Each service can be handled by a separate team, so this favors separation of concerns and responsibilities.
Developed with a technological stack in mind, using one or two languages of choice. A main language/framework is chosen to govern the software architecture.
Each service can be developed using a different framework based on its requirements and needs. Standards are discarded in favor of improving each service with the right tools.
Easier to deploy and cluster.
The complexity of deployment and clustering increases with the number of services and the communication rules between them.
Failure of a component can cause the entire application to fail and hinder the user experience.
Failure of a service can only bring that specific service down, since services are decoupled from each other.
There’s a focus on tiers and integration across tiers.
There’s a focus on business needs and communication between teams.
Considered advantages are green, disadvantages are red, orange is for variable benefits depending on the software requirements or the organization’s environment.
Microservices can help an organization develop their applications in such structured way. But sometimes, when applications are not critical to their business, or their quality attributes (performance, availability, scalability, security, etc.) are not demanding, the traditional monolithic approach is more than enough.
Microservices and Java EE
The Java EE set of specifications allows for the creation of monolithic applications with ease. The main benefit being a Java EE developer is that you don’t need to worry about handling technical concerns like network handling, transaction management or a resource’s lifecycle when the specific container service does that for you. This simplifies the developers' work allowing them to focus on business concerns instead.
In the case of Java EE, a monolithic application’s example could be an e-commerce application with the following characteristics:
- Is structured as an EAR file with multiple modules (linked to the tiers of the monolith):
- An EJB-module that handles integration aspects (SOAP web services, Message handling, etc.)
- An EJB-module with a common persistence layer to access data stores with traditional means: JPA, JDBC, JCA, etc.
- Multiple WAR modules that correspond to the web applications that will handle the user interfaces. Let’s say this application has 3 WAR modules: One for an administrative interface, another to be used by providers or sellers and another for the use of buyers.
- Since the application’s built with Java EE, most of the code is written in Java.
Sounds complex? Yes. The previous scenario was a common occurrence in earlier Java EE days, but nowadays, with tools like Maven or OSGi, modularizing Java EE application has simplified the development of monoliths on Java EE, meaning that your entire application can be deployed in a single WAR file. However, if you want to develop this e-commerce application as a set of microservices, a simple WAR is not enough.
There are no technology restrictions that prevent you to create microservices using the APIs contained within the specifications of a Java EE application server like GlassFish (and Payara Server by extension). However, there are some considerations to have in mind:
- Since each microservice must be a complete standalone deployable unit, this means that each service should be composed of an application deployed within its own Java EE container. So if, for example, an application is composed of 10 micro services, then you would need 10 separate installations of an application server to host each service.
- Most application servers aren’t exactly lightweight, considering their complexity and the features they offer; e.g. Payara Server’s Full Profile currently weights around 117Mb.
- Although most application servers have greatly reduced their startup times, there’s some overhead since the application server needs to prepare and handle many components that won’t be needed for a specific service. For example, when booting a GlassFish domain, the server needs to initialize its messaging subsystem and this is something most services won’t need unless it’s strictly necessary.
Payara Micro was created with these concerns in mind: it’s relatively smaller in size, packaged as a JAR, and allows developers to easily run a microservice with a simple command:
java -jar payara-126.96.36.199.jar --deploy user-service.war
Run this command for each service and you don’t have to worry about a long startup time for your service or having to repeat the installation of a server multiple times! Since Payara Micro is based on the Java EE Web Profile, this means that complex or legacy APIs won’t be available to use (like JMS, JCA, JAX-WS, etc.) However, considering the usual technical requirements for a micro service this isn’t a problem! You still have Servlets, JSP, JSF, CDI, JAX-RS, JPA, JSON-P, etc.
Having this in mind, using Payara Micro only won't be good enough to build a microservices application. You still need to go the extra mile and guarantee that your services fulfill the criteria described above and allow your developers to maintain them with ease. The following is a list of my personal recommendations that you should follow when building micro services with Java EE:
- Package your applications as WAR projects. There’s no need to use the EAR packaging, since that would imply a composition of modules, and a microservice should be structured using the minimum unit of deployment.
- Define all the boundaries of your services using HTTP and REST whenever possible. This will guarantee that you will be able to communicate with other services that compose your application (even if they’re not developed with Java, Java EE or Payara Micro on mind). Each microservice should have REST endpoints defined with JAX-RS. Document these endpoints thoroughly so that the communication rules are clear from the start. I recommend using the Swagger specification since it’s powerful and is also compatible with JAX-RS.
- Is possible to use the CDI event bus provided by Payara Micro to propagate events from one service to another. Asynchronous communication like this tends to be more decoupled and helps services follow a reactive model. However, keep in mind that this feature is proprietary to Payara Micro, so only micro services deployed on it can use it. Consider it only for communicating the services that belong to the same application in the case you choose to use Java EE and Payara for its development.
- Depend on stateless components all time! Stateful components are not only more complex to scale, but they will also make it harder to transfer user data between a set of micro services:
- When using CDI beans, use only the @RequestScoped and @ApplicationScoped
- Use @Stateless session beans only.
- Don’t store data in the HTTP session objects. By default, the HTTP session object is managed by a web application, so define short-lived sessions (around 5 minutes) even if you don’t use it at all.
- Consider using HTML5 powered user interfaces for your web applications. Frameworks like AngularJS and ReactJS are good tools to build rich web interfaces nowadays.
- If you are considering using JSF pages for the user interface, consider using stateless views (<f:view transient=”true”>).
- Use JCache to code special cache components for your services when necessary. With Payara Micro, you have Hazelcast at your disposal, so setting a cache into your cluster is simple enough.
- For services that need data stores, consider using small-sized relational databases like H2, SQLite or JavaDB (since it comes with the JDK no additional dependencies are required), so you can leverage JPA with its object relational capabilities. If you’re in need of a faster or easier to scale database, switch to a NoSQL offer that suits your needs (like MongoDB or Couchbase). Don’t worry about integration, most NoSQL databases provide a Java API and plenty of documentation about handling specific integration challenges.
- Take advantage of the auto-clustering capabilities of Payara Server with Hazelcast. Using Payara Micro, simply define the cluster name for each service:
java -jar payara-188.8.131.52.jar --deploy login-service.war --clusterName loginService
- Docker containers are a must! Configure your application’s deployment with a Docker image that can help you automate the deployment process of your microservices. Better yet, use the official Payara Micro image to create your own!
- Lastly, consider using orchestration tools to organize clusters of your micro services like Apache Mesos, Consul, Google Kubernetes or Docker Swarm.
Payara Micro is a good offering for microservices, but for developers demanding an even smaller footprint to implement their services is not enough. A new community group, formed by Payara, RedHat, IBM WebSphere Liberty, Tomitribe and the London Java Community; brings a new initiative for micro services targeted at Enterprise Java developers: MicroProfile! The main purpose of MicroProfile is to design a set of features that application server providers can use to implement a compact version of their runtimes targeted towards micro service environments:
- Small startup times
- Smaller binary size
- Reduced consumption of memory
- Enabling client-side load balancing
- Supporting a reactive programming model (asynchronous receivers, messaging-centered calls, etc.)
- Supporting circuit breakers mechanisms.
For the moment MicroProfile is centered around conforming to the CDI, JAX-RS and JSON-P specifications. While this project goes on, we encourage you to take part in it by voting which other APIs and features could be beneficial to include as well!
Microservices are here to stay. Any enterprise or startup should consider implementing a microservice architecture when there are enough benefits to reap. For this reason alone, Java EE cannot be left behind and must move on in order to help developers transition to this style. Payara Micro is the ideal place to start, especially if you’re already familiar with GlassFish or Payara Server, since deploying and running your Java EE applications is easy enough.
Keep in mind that microservices are not a silver bullet, and this should be a common knowledge: use the traditional monolithic approach whenever possible, and switch to microservices when you think that their benefits suit your needs and justify their use. This transition not only means having a good grasp of the technical challenges you will be facing, but also understanding that there can be organizational and business challenges as well.