im_004426.jpg

Matteo Formica

Find me on:

Recent Posts

Microservices: everything you need to know (part 4)

Author: Matteo Formica

In the previous post, microservices part 3, we mentioned there can be different approaches to building a microservices architecture. In this final post in the current series on microservices, I’ll be looking deeper into those. Read on:

Request-Response (Synchronous) and Service Discovery

In the examples shown so far in this series, the pattern used is request-response; the services communicate with each other directly by their public HTTP REST APIs. The APIs are formally defined using languages like RAML or Swagger, which are considered the de-facto standard of microservice interface definition and publication.

This pattern is usually adopted in combination with a component called Service Discovery:

Why do we need it? Remember that we are in a distributed context, where the network conditions can change quite frequently, and the services can have dynamically assigned network locations. So, the services need to know how to find each other at all times. A service discovery tool allows to abstract away the physical location of where the services are deployed from the clients consuming them.

When a service is started or shut down, it registers/deregisters itself to the service discovery tool, communicating that it is alive and what is its current location. It also queries the address of all its dependencies, which it needs to call in order to perform its task.

Examples of Service Discovery tools are Spring Netflix Eureka and Consul.

Event-driven (Asynchronous)

In those cases where microservices collaborate for the realisation of a complex business transaction or process, an event-driven approach is also adopted, which totally decouples the services from each other.

This means that the services don’t need to expose a public API anymore (unless we use a combined approach), as they entirely communicate with each other via events. This is possible only by introducing a new component in the architecture called Message Broker:

The message broker is responsible for delivering messages from producers to consumers running on respective microservices. The key point of the message broker is high availability and reliability; it guarantees that the messages are delivered to the respective consumers, in a reliable fashion. If a consumer is down, messages will be delivered when it comes back online.

Message brokers also provide features such as caching and load balancing. Being asynchronous by nature, they’re easily scalable. Standards like JMS and AMQP are dominant in major broker technologies in the industry.

This component enforces the pattern of choreography; the services collaborate in a choreography asynchronously by firing business events, published to the message broker. No further complex orchestration or transformation takes place, as the complexity of the business logic lies inside the actual microservices.

One of the most popular technologies used for Message Broker at the moment is Apache Kafka.

Composite (Hybrid)

Of course, nothing is preventing us from mixing the two approaches; the composition of microservices is realised with a mix of direct calls through HTTP and indirect calls through a message broker.

Microservices Technologies

As you can imagine, we’re seeing an explosion technologies you can use to implement microservices at the moment. Which one to use really depends on which language, framework or capabilities we expect to use - and this may depend, in turn, on the skills we have in our team, existing products licenses we already have, and so on.

As a general principle, any language or framework which allows us to expose a REST interface, or is able to use messaging protocols (e.g. JMS) is a candidate for implementing a microservice. Remember, one of the main points of adopting this kind of architecture is that technology choices don’t really impact the overall system, so we have total freedom to choose whatever is best for the purpose.

To mention some of the popular microservices oriented frameworks, you may opt for Java ones (Spring Boot & Spring Cloud, Dropwizard, Jersey - the open-source reference implementation of JAX-RS), Node.JS (Express, Sails), Scala (Akka, Play, Spray), Python (Flask, Tornado) and many more.

This is not meant to be an exhaustive list at all, there are countless options you can choose from.

What about the distribution of our microservices? Where are we supposed to deploy them, and how are going to manage them (especially where they start growing in number)?

To answer this question we need to introduce the concepts of Application Container, Container Orchestrator and cloud-based Managed Container Service.

Application Containers

Application Containers are a big topic now, and it’s becoming the preferred way to distribute microservices. I don’t want to go too deep into this topic - you can find plenty of information about how containers work, what are the differences and advantages when compared to the traditional physical/virtual machines. By far, the most popular technology for containers today is Docker, and here you can find the full explanation about what a container is.

All you need to know at this stage is that a container consists of the application plus the bare minimum necessary to execute and support it. A container is meant to be portable across different physical hosts, virtual machines and cloud providers, and across environments; you should be able to run your container in your laptop, on DEV environment or in Production exactly the same way. The only external dependency of a container is the technology needed to run the containers themselves.

Usually the container runs a very lightweight Linux distribution (like TinyCore, CoreOS, Alpine Linux, etc), containing only the bare essential OS libraries the application needs to run.

If you have a look at the adjectives describing a container (lightweight, isolated, portable, etc.) you may understand why this is a perfect match for distributing microservices!

Container Orchestrators

Usually the containers are used in combination with Container Management technologies, also known as Container Orchestrators or Schedulers.

Remember that microservices are meant to be deployed as distributed applications; this means we need to take care of things like high availability, clustering, and load balancing, scaling service instances on the fly, rolling upgrades and taking care of the dependencies and constraints, etc. Luckily for us, this is exactly what these products take care of.

Among the most popular technologies at the moment we can find Kubernetes, Apache Mesos or Docker Swarm).

Managed container services

If you don’t want to worry too much about the underlying infrastructure, you may opt for a managed container service, delegating the operations above to a cloud provider.

All of the main vendors now provide cloud platforms which use all (or many of) the technologies mentioned above in a transparent way for the end user. To mention some of those; Oracle Application Container Cloud Service, Amazon’s  AWS Elastic Beanstalk, Google App Engine and Microsoft’s Azure App Service.

In a nutshell, via these platforms we can upload our microservices (in a packaged format, like JAR, WAR or ZIP), specify a very basic configuration (like the command needed to execute the service, the environment variables needed for the application to run, ports to open, etc.) and then, behind the scenes, the platform provisions a new container and deploys the application on it. After the container is started, the full lifecycle of our distributed application can be managed via the platform (load balancing, scaling, starting and stopping the containers, etc).

Conclusion

We’ve finally reached the end of this series!

I tried to give a 360 degree view of this topic without getting too much into the details, which was not really the point of this series.

I’m sure I’ll be back in the future with more microservices related posts, so make sure you subscribe for updates – otherwise you might miss it!

Microservices: everything you need to know (part 3)

Author: Matteo Formica

Wait! Have you read part 1 and part 2? You’ll need to cover those out before reading on.

How to decompose a monolith

When it comes to microservices, the million dollar question is: “How do I decompose my monolith into microservices?”. Well, as you can imagine this can be done in many ways, and here I’ll be suggesting some guidelines.

The first step of course is the design. We need to establish our service granularity, then decompose our domain into exclusive contexts, each of them encapsulating the business rules and the data logic associated with that part of the business domain. The architect will be responsible of defining the service boundaries - and this is not an easy task. I’d say that decomposing a business domain is an art, rather than a science. On the other hand, in a monolith, it’s not always clear where a service ends and another one starts, as the interfaces between modules are not well defined (there is no need for this).

To identify the microservices we need to build, and understand the scope of their responsibility, listen to the nouns used in the business cases. For example, in e-Commerce applications we may have nouns like Cart, Customer, Review, etc. These are an indication of a core business domain, hence they make good candidates to become microservices. The verbs used in the business cases (e.g. Search, Checkout) highlight actions, so they are indications of the potential operations exposed from a microservice.

Consider also the data cohesion when decomposing a business problem. If you find data types that are not related to one another, they probably belong to different services.

In a real life scenario, if the monolith uses a centralised shared storage (e.g. RDBMS) to store its data, the new architecture does not necessarily imply that every microservice has his own database: it may mean that a microservice is the only once having access to a specific set of tables, related a well specific  business case.

As a general principle, when decomposing a monolith, I personally think it’s best to start with a coarse grained granularity, and then refactor to smaller services, to avoid premature complexity. This is an iterative process, so you won’t get this right at the first shot. When services start having too many responsibilities, accessing too many different types of data or having too many test cases, it’s probably time to split one service into multiple services.

My last guideline is not to be too strict with the design. Sometimes aggregation is needed at some point (maybe some services keep calling each other and the boundaries between them is not too clear), and some level of data sharing may be also necessary. Remember, this is not a science, and compromises are part of it.

Challenges and pitfalls

If you made this far, you may have already spotted some potential challenges.

Whether we’re migrating from a monolith, or building a new architecture from scratch, the design phase requires much more attention than in the past. The granularity needs to be appropriate, boundaries definition needs to be bulletproof, and the data modelling very accurate, as this is the base we may decide to build our services on.

Since we’re now in the kingdom of distributed systems, we rely heavily on the network for our system to work correctly; the actual bricks which make our application up are scattered at different locations, but still need to communicate with each other in order to work as one.

In this context, there are many dangerous assumptions we could make, which usually lead to failures. We cannot assume our network is reliable all the time, we have no latency, infinite bandwidth, the network is secure, the topology won’t change, the transport cost is zero, the network is homogenous, and so on. Any of these conditions can happen at any time, and the applications need to be ready to cope with it.

So, the first point is making sure our services are fault tolerant; that means adopting the most common distributed systems implementation patterns, like circuit breakers, fallbacks, client side load balancing, centralised configuration and service discovery.

To have full visibility of the status of our services, good monitoring needs to be in place – and I mean more than before (everything fails all the time, remember?). Compared with monolithic architectures, we may have less complexity on the implementation side (smaller and more lightweight services), but we have more complexity on the operations layer. If the company does not have operational maturity, where we can automate deployments, scale and monitor our services easily, this kind of architecture is probably not sustainable.

Another important factor to consider is that in large distributed systems, the concept of ACID transactions does not apply anymore. If you need transactions, you need to take care of this yourself.

It’s not realistic to think we can guarantee the strong consistency we used to guarantee in monolithic applications (where all components probably share the same relational database). A transaction now potentially spans different applications, which may or may not be available in a particular moment, and latency in data updates is a likely thing to happen (especially when we are adopting an event driven architecture – more on this later).

This means we are aiming to guarantee eventual consistency rather than strong consistency. In a real world business case, more than one service can be involved in a transaction, and every service can interact with different technologies, so the main transaction is actually split in multiple independent transactions. If something goes wrong, we can deal with it by compensating operations.

Some of the most common microservices implementation patterns work particularly well in this context, such as event-driven architectures, event sourcing and CQRS (Command Query Responsibility Segregation)…but these are not the topic of this post. In fact, in next week’s blog post I’ll be looking at these architecture patterns in detail. Make sure you subscribe to catch the final post of this series on microservices.

Microservices: everything you need to know (part 2)

Author: Matteo Formica

I’m going to pick up from last week’s post when we discussed what microservices are, and looked at the alternative approach to microservices, aka the monolith. Make sure you read that before carrying on with part 2.

Let’s jump in…

A different approach

Why is the microservices approach different? Let’s explore the main features one by one.

1. Business focussed

The main point of a microservice architecture is that each one of them need to encapsulate a specific business capability.

The focus shouldn’t be on the technology, but on the business case. This complies with the “single responsibility principle”; the service shouldn't be limited to mere data carrying, or reduced to CRUD responsibilities, but instead should encapsulate all responsibilities relevant to the business domain for which it was designed.

This is one of the reasons why the design phase of microservices can be more complex than for a monolithic application; dividing the business domain into exclusive context (this is a concept coming from DDD, or Domain Driven Design) is not a straightforward task.

The word ‘microservice’ itself can be misleading, as the size is not necessarily the compelling factor here, but rather the fact that it must be business focussed, and the choice of technologies we make inside is purely aimed to get the best for the purpose. Anyway, if we look for some sort of size guidance, let’s say it needs to be easy to comprehend for a single developer, small enough to be managed from a small team (see the “2 pizza rule” I mentioned in the previous episode), predictable, and easy to experiment with.

We can see the microservice as a vertical slice of functionality, a micro-silo with multiple tiers (including UI if necessary) and spanning across multiple technologies.

To make things a bit clearer, let’s make an example of a Music Search microservice. Just bear in mind, as I mentioned at the beginning you’ll find a lot different approaches in building microservices, so this is not intended to be the best solution - it’s just one viable solution according to the main microservices design principles.

Like many other microservices, this service exposes it’s functionalities via public REST APIs for other services to consume. But it also contains a set of UI widgets which could be embedded from a portal or external website.

The search capability does not span across other services - everything is included in here. For this reason, the storage technologies (in this example Apache Cassandra and PostgreSQL) are included inside the microservice; the search business logic is the only one accessing this data, so there is no reason to have them outside.

This way, the service is self-contained, as it includes all of its dependencies, isolated from the other microservices. All it needs to expose to the outside world is the public APIs and UI Widgets for others to consume or embed.

A single team is responsible for maintaining this whole service in its entire lifecycle, from development to release.

2. Open, lightweight, and polyglot

Sticking to Fowler’s definition, in a microservices architecture the applications should communicate with each other using lightweight and open protocols and payloads. This will guarantee the reusability and the performances of these services. So, depending on the pattern we choose (request-response, event-driven or hybrid) we will choose protocols like REST/HTTP, JMS or AQMP for example, and the payloads will likely use JSON.

A big advantage in this kind of architecture is not having a long-term commitment to any technology stack.

This gives us the possibility to choose the best language/framework suited for the purpose:

In this example, we might decide to implement:

  • Search service using Spring Boot (Java), Elastic Search as search engine and Cassandra as storage.
  • Reviews service with NodeJS and Express, Solr as search engine and Mongo as storage.
  • Shopping cart service with Scala and Spray, using Redis as a cache to store the cart items.
  • Contact service with Dropwizard (Java based) using PostgreSQL as storage.

What do these services have in common? The answer is…nothing, apart from the fact they communicate between themselves via public APIs or events (we will get to this later on). Every microservice is free to adopt the language or framework that is most appropriate for this business domain. They also use different storage technologies. The concept of pan-enterprise data models and shared RDBMS does not apply anymore. It doesn’t mean RDBMS is gone for good (not at all), but it won’t be used anymore as a common way to share information, tightly coupling application together and preventing scalability.

You may notice that in the figure above the API (the service interface) is separated from the actual service implementation (which is tied to a technology); this is just to stress the importance of separating the interface of the microservice (you can see the API as the “door” to access the service) from its implementation (see ‘Loosely Coupled, Isolated’ section later on).

3. Scalable

By nature, microservices need to be easy to scale horizontally, to be able to handle flexible workloads.

In order to achieve this, they need to be reasonably small in size (perfect candidates to be distributed via Docker containers), isolated and stateless. Once these prerequisites are filled, we can leverage the features of the most popular container management platforms, like Docker Swarm, Kubernetes, or Apache Mesos, and scale our application easily:

When we’re talking about scaling, the financial factor needs to be considered; it’s much cheaper to scale out containers (inside the same physical or virtual machine), rather than scaling out entire machines. With monolithic applications, scaling the entire physical or virtual machine may be the only choice we have. This is because the components of the monolith cannot be scaled individually, and because there are many more external dependencies than individual microservices. Basically, we need many more resources (physical and financial) to be able to scale out.

4. Loosley coupled, isolated

Dependencies between services are minimised by defining clear interfaces (APIs), which allow the service owners to change the implementation and underlying storage technologies without impacting the consumers. This concept is not new at all; it’s one of the basics of Service Oriented Architecture.

Every microservice owns its own data and dependencies, so there’s no need to share this with anyone else; it contains everything it needs in order to work correctly. Let’s bear in mind though, in real life scenarios there may be the need for some microservices to share some sort of session, or conversation. In these cases, a possible solution is to consider using distributed caching solutions (e.g. Redis or Coherence).

But if we’re doing this the best possible way, the only resource a microservice is supposed to expose is its public APIs. (Note: this is not true if we adopt a full event-driven approach – more on this in the last episode).

The external dependencies the microservices usually have are the platform capabilities themselves. The functionalities to start, stop, deploy, monitor or eject metadata inside a microservice cannot be part of the service itself, but rather a feature of the platform we are using to distribute them.

5. Easy to manage

Now let’s have a look at microservices management from the DevOps point of view.

Microservices and DevOps.png

In a scenario with multiple independent applications, it’s likely that we’re going to have one dedicated team in charge of the development and deployment for each one of them.

In some cases, some services may be small and simple enough that one mid-size cross-functional team could maintain them all.

Since the services are business focused, the code base should be reasonably small to digest in a short time, and a new developer should be able to make changes on his first day on the project.

The deployment of a microservice is completely independent from the others, so whenever a change is ready it can be deployed at any time. The same team is responsible for development, testing and release, so there is no need for a separate team to take control of the release process.

If you think about it, this is exactly what DevOps is about; building, testing and releasing software happens rapidly, frequently and reliably, whereas development team and operations team tend to become the same thing.

Fault Tolerant

Keep in mind, in a microservice architecture every component is potentially a client and a server at the same time; every service needs to be able to work (or at least know what to do) when one of its dependencies (i.e. services it needs to call according to his business function), is down.

Since in distributed systems “Everything fails all the time” (as Amazon’s Werner Vogels reminds us), every microservice needs to be designed for failure, and circuit breakers need to be in place to prevent individual service failures to propagate through a large distributed system.

This implies that the larger our distributed application is, the more monitoring we need (much more than we need for a monolith), to identify any failures in real time.

Microservices: Service Oriented Architecture in disguise?

A common misconception is to consider these two approaches as alternative to each other, but actually, the microservices approach is actually based on a subset of SOA patterns.

As an architectural style, SOA contains many different patterns, like orchestration, choreography, business rules, stateful services, human interaction, routing, etc. Mainly, SOA is focused around the integration of enterprise applications, usually relying on a quite complex integration logic to integrate simple “dumb” services; a SOA architecture usually relies on centralised governance.

On the other side, microservices are more focused on decomposing monoliths into small independent applications, focusing on a small subset of SOA patterns, in particular choreography and routing. The microservices don’t need a centralised governance to work with each other, they simply regulate their behaviour to interact smoothly with each other. The integration logic is relatively simple (routing and nothing more), while the complexity is actually moved into the business logic of the service implementation itself.

As an example, think of a SOA as big cross junction, and microservices as a crowd of pedestrians. Without governance (i.e. traffic lights, signs, lanes) in a cross junction, cars would crash into each other and traffic jams would happen all the time. The system wouldn’t work at all. This doesn’t happen with a crowd of pedestrians; the pedestrians regulate their speed and behaviour smoothly and naturally in order not to crash into each other, and there is no need for a third party to tell them how to do it.

In summary, borrowing the definition of Adrian Cockroft (previous cloud architect at Netflix and now AWS) we can define microservices as a “fine grain SOA”:

Microservices are fine grain SOA.png

In a later blog post, I’ll be taking a deeper look into some of the challenges of using microservices and possible approaches to decompose a monolith. We’ll introduce event-based microservices, and have a quick look to technologies and frameworks we can use to implement microservices, along with some of the most popular cloud platforms to distribute them.

Subscribe to the Infomentum blog to receive updates!

Microservices: everything you need to know (part 1)

Author: Matteo Formica

The discussion on microservices has exploded recently. It’s been heralded as the future. But is it really so new, or something more familiar than we think? Well, let’s start by setting the scene; what are microservices? Unfortunately, there is no universal and unique definition. In the most generic way possible, this is an “architectural style”, so it can be implemented in different flavours, and can be defined in many different ways. I personally think that the definition of Martin Fowler is the most clear and exhaustive:

“In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.”

I like this definition because it captures some of the key features that the industry tends to agree on:

  • A microservices architecture is the result of a decomposition of a single application into a suite of smaller services.
  • Every microservice is a stateless, isolated and independent process.
  • They communicate with each other using open protocols (such as REST/HTTP, messaging).
  • They can be written using different languages / frameworks.
  • Each microservice encapsulates a specific business capability.
  • Every microservice must be independently deployable, replaceable and upgradeable.
  • They need a bare minimum of centralised governance.
  • They must be easily scalable.

Despite the industry interest in microservices at the moment, they aren’t an entirely new concept; we’ll see later on that microservices are actually one of the many ways to implement a SOA architecture, focusing on a few specific patterns.

In general, explaining microservices is easier when making a comparison with the traditional “monolithic” applications…

Once upon a time: the monolith

Monolith application.png

Way back in the “traditional” web applications of the 90s and 2000s, we would probably see something like the above: a typical MVC structure where the services are accessing data from a single centralized RDBMS, which is probably shared by many other applications across the entire enterprise.

The services in this context are better described as “libraries”, i.e;

  • They are part of the application
  • They don’t have a very clear interface definition (as they don’t need it)
  • They call each other using proprietary and closed or heavy protocols
  • They share the same data
  • And, most likely, they won’t be very reusable outside the context of this application.

The controller layer is responsible for invoking the services and rendering the data on the front-end, serving only one type of client (typically a web browser) - mobile apps and other devices weren’t a priority at the time.

Monolith image 2.png

From the deployment point of view, the whole application is packaged into a single artefact (e.g. a WAR or EAR), and the deployment team is responsible for deploying it across environments (CI, CD and DevOps were not a thing back then!). This means that a single change in one of the libraries implies a redeployment of the whole application, and worse, that a problem at the end of the pipeline can block the entire release, preventing many other changes to go live. When the application grows in size, the code base may be split in different repositories, and different teams may be responsible for different parts of the code. But the deployment still represents a potential bottleneck.

The application above is very likely to be implemented using a specific language or framework. This decision was made at the design phase before the application was implemented, and now moving to a different technology stack is unrealistic; who’s going to pay for that?

Finally a note on the actual development team; a large codebase cannot be digested from a single team, and when the team becomes too big the maintenance becomes more difficult. I’m a fan of Amazon’s “two pizza rule” when it comes to development teams; according to the rule, you should never have teams so big that two pizzas couldn't feed the entire group.

So that’s the history of the monolith. But why are microservices a different approach, and what benefits can they offer us? I’ll be diving into that in next week’s blog post.

What to be notified when that blog is live? Subscribe to receive updates! 

Follow infoMENTUM on Twitter