A MicroService WebSocket Chat

This article describes how to create a high performing chat application that functions as a MicroService. Within this MicroService, I will be using Caucho Technology’s Baratine ( v 1.0) framework to demonstrate the following:

  1. Building .jars not .wars
  2. Asynchronous nonblocking methods
  3. Pub/Sub functionality
  4. Performance & Scalability
  5. API/interface based programming
  6. Single-threaded frameworks as a solution for multi-threaded concurrency issues

For reference, the most recent dzone article that detailed a WebSocket chatroom can be found here https://dzone.com/articles/creating-websocket-chat. While the article was a great starting point for people to get familiar with WebSockets, this chat application will demonstrate how open source framework, in particular Baratine, can help developers implement the best current known practices in the industry.

Running the example

To run the example, do the following:

  1. Ensure that you have installed the gradle build tool
  2. Clone the repository from: https://github.com/swily/WebSocketChat.git
  3. Run gradle build
  4. Run gradle run
  5. Open your browser and navigate to localhost:8080

Overview of Files

While the application includes a few POJO classes, majority of the work is done in the following 3 files:

index.js / index.html – Displays chat messages and chatroom

ChatWebSocket.java – Listens to the websocket wire, connects the PubSub message pipes

ChatService.java – Support for long-polling, starts the Baratine server

ChatWebSocket.java

ChatWebSocket relies on Baratine’s implementation of the WebSocket protocol. In order to have access to the WebSocket wire, we implement ServiceWebSocket with our parameterized type Message. Message is our own defined class of what we expect to be coming across the WebSocket wire.

Beyond listening to the WebSocket wire, we also set up our PubSub messaging inside of Baratine. PubSub in Baratine has three components

  1. A PipeBroker
  2. A Pipe Subscriber (PipeSub)
  3. A Pipe Publisher (PipePub)

You’ll notice that we also make use of a _messagePipeHandler to ensure that we can properly implement “close” functionality when a user leaves the chatroom.

Setting up of the pipe is done in lines 88-93 in the following order:

  1. Create a PipeSub endpoint to tell when messages should flow out of the pipe, in our case I want these messages passed to my OnPipeReceive method. I utilize a lambda to achieve this.
  2. I subscribe the instance of my PipeBroker to the PipeSub endpoint.
  3. I create a handler to close the pipe when the connection is closed.

Here is the setup of the pipe:

Screen Shot 2016-08-05 at 3.56.47 PM

ChatService.java

ChatService is responsible for creating ChatMessages and passing them into the pipe. The methods are fairly straightforward, however scanning the class three important pieces might jump out:

  1. Annotations such as @Query on the send method provide long-polling fallback for http. Methods can be called directly over WebSocket by clients, or accessed over HTTP.
  2. Our main method uses the Baratine specific (Web.include(foo.class)) in order to provide the Baratine server with access to these classes.
  3. Baratine’s Result is used as an asynchronous callback so that methods do not block. Instead, a method finishing processing when given the .ok() call.

We start our Baratine web server with a simple Web.start() method as such:

Screen Shot 2016-08-05 at 3.57.09 PM

Performance

This MicroService was benchmarked on a MacBook Air Core i7 3667U with the following results

20 million messages/second/instance with no acknowledge messages

9 million messages/second/instance with acknowledge messages

6 million messages/second/instance with full ping-pong acknowledgement on every message

Baratine is able to achieve these results due to its automatic batching and underlying single-threaded implementation. What’s more is that the @Service annotation on a class provides a lock free and ordered inbox for processing messages on a service. Because of this, Baratine does not need to have synchronized code blocks for concurrency; data is only ever accessed by a single service owning thread, thus making dreaded concurrent access a thing of the past.

In fact, because of this improved underlying programming model, Baratine can persist data to internal data stores without the need for a data schema or an outside data source. Baratine does have MySQL drivers for the database you have already licensed, but many applications and services can rely on operating with their data in-memory and persisting to Baratine’s internal data store when needed.

Conclusion

Baratine 1.0 is officially released under the GPL license and offers a significant improvement over many of the issues that plague and prevent agile development in today’s programming world. With Baratine, developers can simply code an API and know that the implementation will be ready to be consumed by today’s IoT clients from any language (JSON permitting). This application can be embedded into an existing Java EE project, or used as a standalone service. This is the promise of MicroServices as features to an application can be added and removed without an overall impact to the current architecture.

While you may or may not need a specific chat implementation added to your current web app, I am hoping that people will take away the structure of the underlying architecture in this example application and apply it for their specific use case. Feel free to fork the github and continue the development!

Advertisements

Implementing a BookStore as a MicroService in 40 Lines of Code

MicroServices are the new trend in web service development. Much has been written about their architecture and benefits, but when it comes to actual implementation, many developers are using the same underlying technologies that they have used before.

In this post, we will look at an implementation of the common “Bookstore” application as a single MicroService. We’ll discuss the architectural benefits & performance the MicroService coded in Baratine presents compared to a JAX-RS implementation.

In doing so, we put forth the idea that if developers are still using similar multithreaded components to build with, they are in fact building monolithic solutions with the same inherently flawed monolithic models, just on a smaller scale.

Part 1: The service

Our Baratine Bookstore is only 40 lines of code in its entirety, so let’s take a look at the entire application:

Bookstore Baratine

  1. @Service creates a single-threaded service. Because it is single-threaded, we do not need synchronization and can use a simpleHashMap.
  2. @Get(“/books”) maps the method to a GET request at the URL “/books”.
  3. Then result.ok() completes the asynchronous request.

That’s all there is to it. The service is fully self contained, and because we used Baratine’s Result, all of our methods are nonblocking (do not tie up threads in the background) and can be called concurrently. It’s also worthwhile to point out this API can be consumed by a client of any language that can understand JSON.

Now let’s take a look at JAX-RS:

JAX_RS2

JAX_RS

web.xml:

JAX_RS3

  1. JAX-RS requires three files: an application class, a path class, and an empty web.xml.
  2. It must use a ConcurrentHashMap because the application is multi-threaded.
  3. It must be deployed in a container like Tomcat or JBoss.

In terms of complexity, JAX-RS is more complicated than Baratine (albeit more configurable). It requires at least 3 files, a servlet container, and the developer needs to mind concurrency issues.

Performance:

Even though Baratine is single-threaded, it easily outperforms JAX-RS (RESTEasy) by over 2x. You can scale out Baratine to take advantage of all the CPU cores on your machine and Baratine will scale up linearly – something that you cannot do with JAX-RS.

Persistence:

Our bookstore example stores the data in memory. What about saving it to a database? Persistence is out of the scope of JAX-RS and it forces you to use another library like JPA. With Baratine, it comes with a document-style persistence layer. No additional libraries and only a trivial change to our bookstore:

BookstorePersist

There are only two changes to our bookstore:

  1. @Data added to the class, to tell Baratine to save this object into its internal reactive database.
  2. @Modify on addBook() to tell Baratine that this object has been modified and that Baratine should add it to the save queue.

Even though the new bookstore is persistent, we still get the same high performance as before because the persistence is asynchronous and bookstore operates mostly in-memory. That is the beauty of Baratine and only possible because Baratine is reactive. There are no comparable platforms out there.

If you would like to expand this application, take note of the following Baratine maven dependency that was used:

mvn