Book Image

Hands-On Microservices with Kotlin

By : Juan Antonio Medina Iglesias
Book Image

Hands-On Microservices with Kotlin

By: Juan Antonio Medina Iglesias

Overview of this book

With Google's inclusion of first-class support for Kotlin in their Android ecosystem, Kotlin's future as a mainstream language is assured. Microservices help design scalable, easy-to-maintain web applications; Kotlin allows us to take advantage of modern idioms to simplify our development and create high-quality services. With 100% interoperability with the JVM, Kotlin makes working with existing Java code easier. Well-known Java systems such as Spring, Jackson, and Reactor have included Kotlin modules to exploit its language features. This book guides the reader in designing and implementing services, and producing production-ready, testable, lean code that's shorter and simpler than a traditional Java implementation. Reap the benefits of using the reactive paradigm and take advantage of non-blocking techniques to take your services to the next level in terms of industry standards. You will consume NoSQL databases reactively to allow you to create high-throughput microservices. Create cloud-native microservices that can run on a wide range of cloud providers, and monitor them. You will create Docker containers for your microservices and scale them. Finally, you will deploy your microservices in OpenShift Online.
Table of Contents (14 chapters)

Reactive microservices

Reactive programming is currently a trend topic. This is mainly because of the benefits to implementing software using this new paradigm. Spring Framework 5.0 included numerous changes to give the advantage of this programming model and many new components of the Spring family have evolved to support it. In fact new Spring libraries have been created to add additional support to applications interested in what is called the reactive revolution. Additionally, Spring has rewritten the core of the framework, using reactive technologies that will allow a better technology for the applications that use them. In this section, we will understand the basics and principles of reactive programming and how we could apply it to create reactive microservices.

Reactive programming

We are quite familiar with imperative programming: in our software, we ask to do something and expect a result and meanwhile, we wait, our action is blocked expecting a result. Consider this small pseudo code as an example:

var someVariable = getData()
print(someVariable)

In this couple of instructions, we will set the content of a variable from the output of a function that will return data; when the data is available, we will print it out. The really important part of this small piece of code is that our program stops until we completely get the data, this is what is called a blocking operation.

There is a way to bypass this limitation that has been used extensively in the past. For example, we could create a separate thread to get our data, but effectively, that thread will be blocked until completion, and if different requests need to handle this, we end up in the situation of creating a thread for each one, possibly using a pool, but finally we will reach a limit of how many of those threads we can handle. This is how most traditional applications work, but now, this could be improved.

Let's see some pseudo code for this in reactive programming:

subscribe(::getData).whenDone(::print)

What we are trying to do here is to subscribe to an operation and when that operation is complete, send the result to another operation. In this example, when we get the data, we will print the results; the important part of this is that after that sentence our program continues, so it could process other things; this is what is called a non-blocking operation. But this could be applied not just to a single result, we could subscribe into a reactive stream of data, and when the stream starts to flow, it will be calling our function that will be progressively printing the data that we receive.

A reactive stream is a collection of data that will continuously flow as soon as it is ready, so imagine that instead of querying a database for some results, the database starts sending results as often as it is ready. Many modern database drivers support these concepts.

This new programming model allows us to have high-performance applications to process way more requests than in a more traditional blocking model. This approach utilizes resources more effectively and this could reduce the amount of infrastructure required for our applications. But now we need to understand what are the real principles of reactive programming.

Reactive Manifesto

In 2013, a working group of experts from some of the biggest software companies in the world published the Reactive Manifesto that set the basis of how reactive systems are understood and work, this manifesto is available on https://github.com/reactivemanifesto/reactivemanifesto.

Let's review what the Manifesto said:

First, the Manifesto introduces the current landscape of modern applications, focusing on how this demands a new kind of system that needs to respond to way more data and faster than before, and has to be scalable, resilient and fault tolerant. The intention of the Manifesto is to have a coherent approach to those problems and define reactive systems and what benefits we get from them. Many of those topics were discussed in our Microservices principles section, so it probably is a good idea to review them, but now we need to do a deep dive of how reactive systems are defined in the Manifesto.

If you would like to sign the manifest or have a PDF version in any language you could go to http://www.reactivemanifesto.org/.

Responsive

Modern applications should respond in a timely manner, but not only to the users of the system but also to the responsiveness of our problems and errors; we are long way away from those days where our applications would freeze when something was either taking longer to answer or failing for unknown reasons.

We need to help the users have a seamless and predictable experience so they could progressively work in our system, and doing so with consistent quality, so they will be encouraged to use the system and remove our past stigma with randomized user experiences.

Resilient

We cover much of this topic under our build for failure and isolation principles, but the Manifesto indicates as well that if we fail to have resilience, we tend to affect our responsiveness, something that we should handle.

Some of these issues could be handled, as well as applying correctly our scalability principle, since we could archive resilience by replication and replication, depends on our scalability.

Elastic

Reactive systems should be elastic, so they effectively apply the scalability principle to stay responsive under varying workloads, but more internally, the system itself may have the capability of increasing or decreasing the resources that allocate.

In the older architecture, planning resources was part of our architecture; we design thread pools to handle our request with certain capacity, and we prepare our servers to be able to manage this.

In reactive systems, our services could dynamically fetch more resources if required and free them when they are not needed.

Message-driven

Reactive systems use asynchronous messaging to flow information through the different components with very loosely coupling, that allows us to interconnect those systems in isolation. We could think of this as if we are connecting streams through pipes, one service could subscribe to another to get some information and the second service could be subscribed to a couple of additional services to combine the data and return it back to the original service.

Connecting streams

Each of those services does not know why or how that information is used, so they have little information about the dependencies. This allows us to replace those pieces easily, but as well as handling errors in case of failure, we could simply just create a stream of errors with other receivers that will handle and process them.

But the manifesto speaks about applying back pressure; we need to understand that concept further.

Back pressure

Back pressure is produced when a reactive system is published at a rate higher than the subscriber could handle, in other words, this is how a consumer of a reactive service says: Please, I am not able to deal with the demand at the moment, stop sending data and do not waste resources (for example, buffer memory).

There is a range of mechanisms for handling this, and they are usually close to the reactive implementation, from batching the messages to dropping them, but right now, we don't need to get into the details, just understand that any reactive system must deal with back pressure.

Reactive frameworks

There are several reactive frameworks that we could use to create reactive applications.

Let's list the more important frameworks:

  • Reactive Extensions (ReactiveX or Rx)
  • Project Reactor
  • Java Reactive Streams
  • Akka

Reactive Extensions

Reactive Extensions is probably one of the most popular frameworks to create reactive systems and support a wider set of platforms and programming languages, from JavaScript using RxJS, to Java using RxJava or even in .Net platforms using Rx.Net.

It uses the observable pattern to perform no blocking operations; most of the major reactive systems have been built using Rx.

More details can be found at: http://reactivex.io/.

Project Reactor

Project Reactor is a JVM reactive library that follows the reactive streams specification and provides a high-level library to easily create reactive applications. Spring Framework 5.0 uses Project Reactor extensively.

More details can be found at https://projectreactor.io/.

Reactive Stream is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure. You can refer to http://www.reactive-streams.org/.

Java reactive streams

Since Java 9, we now have an implementation of reactive streams in the Java platform, some projects are migrating existing Rx code into the new Java 9 libraries.

More details can be found in: https://community.oracle.com/docs/DOC-1006738.

Akka

Akka was created by Jonas Bonér, one of the main authors of the Reactive Manifesto, to create a toolkit in the JVM, using Scala, to create concurrent and distributed applications. Akka emphasizes in the actor-base model and has been proven to support high scalable distributed applications.

More details can be found in: https://akka.io/.

Reactive microservices

Now that we have a better understanding of reactive systems, we need to consider why we should create reactive microservices. If we look at microservices and remember what drove SoA into microservices, we could view what we need to create more complex applications and produce a better system for our users driving the architecture. With the new reactive programming model, we could create fast and non-blocking software that will utilize better the resources of our infrastructure. We could provide better responsiveness, and we could simplify our development to create highly reusable services that could be connected loosely with each other. And considering how aligned the reactive systems are with our principles and the extensive support of frameworks that they have, we conclude that the way forward for modern microservices is to become reactive.

We will explore more of this topic in Chapter 4, Creating Reactive Microservices.