DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • How To Build Web Service Using Spring Boot 2.x
  • How To Validate HTTP Post Request Body - Restful Web Services With Spring Framework | Spring Boot
  • Google Cloud Pub/Sub: Messaging With Spring Boot 2.5

Trending

  • AI's Dilemma: When to Retrain and When to Unlearn?
  • Top Book Picks for Site Reliability Engineers
  • Artificial Intelligence, Real Consequences: Balancing Good vs Evil AI [Infographic]
  • Ethical AI in Agile
  1. DZone
  2. Coding
  3. Frameworks
  4. An Introduction to Microservices With Undertow

An Introduction to Microservices With Undertow

Undertow can be a great tool in your microservices tool-built. In the first article of this series, we discuss just why that is.

By 
Sachin Walia user avatar
Sachin Walia
·
Feb. 14, 19 · Tutorial
Likes (12)
Comment
Save
Tweet
Share
30.0K Views

Join the DZone community and get the full member experience.

Join For Free

Introducing Undertow

This is a series of articles trying to cover a powerful and yet an uncommon Java-based NIO server called Undertow. Over the sequence of these articles, I’ll try to cover what Undertow is and how you can leverage it to build a full-featured Java-based production quality network service that provides a REST-based interface and supports modern messaging systems such as Kafka. These articles will purposefully avoid topics on using Servlet APIs, as Undertow follows a simple programming model based around a single abstract interface (SAM) called HttpHandler.

Litany of Distributed Computing Concepts in Java

If you’ve been building Java-based distributed systems, then you’d agree that no other platform has seen so many techniques of building distributed systems as Java has. In fact, most Java developers have used more than a couple of the following programming models for building such systems:

  • Remote Method Invocation (RMI)
  • Java Messaging Service (JMS)
  • CORBA
  • Enterprise Java Bean (EJB)
  • Java Servlet
  • Spring
  • SOAP
  • REST
  • GRPC
  • Modern messaging framework (Kafka, RabbitMQ)
  • Actor framework (Akka)
  • Netty

Rise of Microservice Frameworks

Before microservice became ubiquitous as a concept we had service-oriented architecture (SOA) that worked with both SOAP- and REST-based multiple monolithic services. However, these monolithic services showed limitations in terms of how large they could grow before becoming unmaintainable and compromising the software release cycle.

Microservices as an architectural style was first coined in May 2011 and officially agreed upon a year after in May 2012. Since then, Java has seen myriads of microservice frameworks and the list keeps on growing every day. Some of the most popular ones you may have heard of are:

  • Spring Boot
  • DropWizard
  • Jooby
  • SparkJava
  • Vertx
  • Ninja Framework
  • Play Framework 
  • Lagom
  • Micronaut
  • Various MicroProfile implementations

Most of these microservice frameworks follow an opinionated way of programming and are built on top of one or more of the following Java containers or toolkits:

  • Tomcat
  • Jetty
  • Grizzly
  • Netty
  • Undertow

One of the commonalities across all these frameworks is that they all follow the Uber-jar (also called fat-jar) model of deployment and they are launched like a Java application.

What Is Undertow?

Undertow is an NIO server built and maintained by the Red Hat JBoss team. Beginning with Wildfly version 8, Undertow became Wildfly's default web container. Before that, the JBoss team was relying on Apache Tomcat for handling web requests. 

Undertow uses another JBoss project called XNIO for its NIO capabilities.

Although Undertow is an NIO server, it is designed to handle both blocking and non-blocking requests. 

The first version of Undertow was released in February 2014. As of writing this article, Undertow is at version 2.0.17 and can optionally support the full Servlet 4.0 spec.

Some microservice frameworks such as Spring Boot and Jooby also support Undertow as a web container. The Wildfly team built their MicroProfile implementation, called Thorntail, on top of Undertow. 

We can visualize Undertow as a barebones Java-based Http Server that is fully programmable using its HttpHandler interface. We can use it for building any kind of HTTP-oriented services.

What it Isn’t

Most of the major microservice frameworks support multiple capabilities such as:

  • Dependency injection.
  • HTML template engines.
  • Automatic wiring of messaging systems (Kafka, RabbitMQ).
  • Automatic HTTP request and response lifecycle handling.
  • Annotation-based URL routing.
  • Data binding (SQL, NoSQL) and migration support (Flyway, Liquibase).
  • Circuit breakers and service discovery.

Undertow supports none of the above capabilities out of the box and everything needs to be programmed. With this definition, Undertow is not a microservice framework and it doesn’t try to be one. 

Perhaps the biggest question is why one must use Undertow (and in what use cases) if none of the above capabilities are supported out of the box.

Considering the extremely slim profile of Undertow, it frees developers from following any convention when using third-party libraries. So, in a way, your microservices actually follow the model of BYOL (bring your own library). 

Over the course of these articles, I’ll cover the various options available when solving problems where you need to talk to external systems and services such as Redis, RDBMS, and other microservices so that you don’t end up writing extremely low-level code.

Undertow Architecture

Assembling Undertow-based applications is straightforward. Undertow is composed like a standard Java application where server configuration can be specified through both internal or external configuration such as properties files, etcd, consul, AWS KMS, etc. 

The following is how various components interact in an Undertow application:

Undertow application

Here are various lifecycle steps:

  • The server receives an HTTP request through an HTTP handler, such as the routing handler, that understands how to resolve route to a specific HTTP handler.
  • The request is passed on to the HTTP connector.
  • The connector routes it to the XNIO worker instance.
  • If tje request is blocking, then it is desirable to hand it off to worker pool; if this is not availble then we'd hand it off to the IO pool.

JBoss XNIO

XNIO is another project started at JBoss that is a building block of Undertow. This is a low-level IO framework that provides channel-based abstractions similar to Java NIO. However, it adds the notion of callbacks and thread and resource management making it easier to access lower level networks and IO files. This makes it easier for programmers to build high-performance network services. The detailed discussion of XNIO is out of scope for these series of articles, as most developers will rarely need to directly use XNIO low-level APIs.

Undertow's Handler Interface

Undertow's request and response cycles are managed via an instance of the HttpHandler interface. HttpHandler can be chained and any handler in the chain can generate a response and end the conversation. This is very similar to how it is done in Golang via its HttpHandler interface.

To compose a request handler, one must implement the HttpHandler interface. This is a SAM interface with a signature like the one below:

package io.undertow.server;

public interface HttpHandler {
    void handleRequest(HttpServerExchange exchange) throws Exception;
}

A sample application towards the end of this article shows how to implement this method and define an HTTP route. Usually, one implementation of a handler per API is sufficient. However, services may have more than one implementation of handlers per API if multiple handlers exist in the chain of execution.

Core Undertow Concepts

Undertow is a configurable server with sane default settings. Application developers may want to customize those settings to fit the needs of their application. Some of the configurations to keep in mind are:

  • Worker Thread Pool: Worker thread pools manage blocking tasks. All blocking API calls must chain their handler within BlockingHandler to ensure the worker threads are used. This pool size can be much higher than the IO thread pool. The general recommendation is around ten per CPU core. Note: In your log file for a given API call, if the thread name is shown as XNIO-1 task-{some-thread-Id} this it means the worker thread is used for handling such calls.

  • IO Thread Pool: The IO thread pool manages threads that perform non-blocking tasks. Any API call that requires external blocking systems such as a database, a Redis instance, or API gateways, are blocking in nature and should not be executed on IO threads. Such calls must be offloaded to worker threads. To offload those calls to a worker thread pool, BlockingHandler can be used. The IO thread pool size of two per CPU core is a reasonable recommendation. Note: In your log file for a given API call, if the thread name is shown as XNIO-1 I/O-{some-thread-Id} this means that the IO thread is used for handling such calls.

A Simple Undertow-Based REST Service

package com.undertow_articles.article01;

import io.undertow.Undertow;
import static io.undertow.Handlers.path;

public class Application {

    public static void main(String[] args){
        Undertow.Builder builder = Undertow.builder();
        builder.setIoThreads(2);
        builder.setWorkerThreads(10);
        builder.addHttpListener(8080, "0.0.0.0");
        builder.setHandler(path()
               .addPrefixPath("/", exchange -> {
                   exchange.getResponseSender().send("Hello World");
                })
        );
        Undertow server = builder.build();
        server.start();
    }
}

Explanation of server configuration:

  • Line #10 - Sets the server IO threads.

  • Line #11 - Sets the server worker threads.

  • Line #12 - Defines the HTTP listener at port  8080 and any network address. If the network address is left empty, then it defaults to  localhost so the service will not be accessible via the IP address. 

  • Line #13 - Defines the path handler. This can be chained to specify multiple path patterns.

  • Line #14 - This is the handler that listens to the application root path ( "/" ). This may be used as catch-all handler.

  • Line #15 -  HttpServerExchange generates a response that may be consumed by callers (browsers, services).

  • Line #19 - This command starts the server as a daemon thread.

What's Next

In next several articles, I’ll show how to build a production quality microservice with Undertow using all the standard patterns used by popular microservice frameworks, including externalized configurations via a configuration file, Consul, or etcd; data access and caching; messaging with Kafka, Metrics, Service Discovery, and Circuit Breaker. 

Stay tuned!

Resources

  • GitHub project link

  • Undertow 2.x documentation

  • JBoss XNIO

microservice Spring Framework Framework Web Service application Java (programming language) Spring Boot Apache Tomcat Requests

Opinions expressed by DZone contributors are their own.

Related

  • Distributed Tracing System (Spring Cloud Sleuth + OpenZipkin)
  • How To Build Web Service Using Spring Boot 2.x
  • How To Validate HTTP Post Request Body - Restful Web Services With Spring Framework | Spring Boot
  • Google Cloud Pub/Sub: Messaging With Spring Boot 2.5

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!