Introduction to microservices

Posted August 9, 2020 - 6 min read
Topics:  

Today microservices are very popular among companies and developers. Often they are used in high loaded and distributed systems. Nevertheless, implementing microservices and dealing with their cost and complexity are still big challenges to take for many developers.

This is the first post of a series of posts about how to design and build microservices. Within this post, we are going to analyse a typical monolith and find out its advantages as well as disadvantages. From then, we will overview microservices as an alternative solution.

Monolithic systems

Typically, a monolith is an application which is built as a single unit and consists of 3 layers:

  • UI (presentation)
  • Business layer
  • Data access layer

  ┌───────────────────────────────────────────────────────┐
  │ ┌──────────────┐       ┌────────┐       ┌───────────┐ │
  │ │      UI      ◄───────►Business│       │Data Access│ │
  │ │(Presentation)│       │  Layer ◄───────►   Layer   │ │
  │ └──────────────┘       └────────┘       └───────────┘ │
  └───────────────────────────────────────────────────────┘

Sometimes the UI can be built as a stand-alone application (for example an SPA/mobile application). In this case the application is split into a front-end application and a back-end application:

  • UI (presentation)
  • API
  • Business layer
  • Data access layer

  ┌──────────────┐
  │     UI       │
  │(Presentation)│
  └────▲─────────┘
       │
  ┌────┼─────────────────────────────────────────┐
  │ ┌──▼──┐       ┌────────┐       ┌───────────┐ │
  │ │ API ◄───────►Business│       │Data Access│ │
  │ │Layer│       │ Layer  ◄───────►  Layer    │ │
  │ └─────┘       └────────┘       └───────────┘ │
  └──────────────────────────────────────────────┘

Monolith is an easy way to start developing an application. But over time, the application may grow enough by having many features and reaching a point where it becomes difficult to understand, to maintain, and to scale.

Pros

  • Simple to develop. The application codebase is in the same language, in the same project, and using the same framework.

  • Easy to debug and test. The application shares a common codebase which is easy to run and test as a single unit with minimal efforts. Also, it is easy to debug and fix an issue. Code refactoring is also easy to perform.

  • Centralized data model. all application data lives in the same database. No data inconsistency issues. When using a RDMS, requirements such as ACID can be easily fulfilled.

  • No network latency issues. Application modules share the same process. When modules are split, cross module communication requires a transport medium which may increase the time to send a request and receive a response.

Cons

Once the application has grown, we may deal with the following issues:

  • Big and complicated codebase. Only few developers may have the entire picture of the application underlying and may understand the complex workflow of different operations. Bring new team members and integrating them into the development process is often difficult.

  • Agile development is no more the same as it used to be. New features take more time to implement, bugs are difficult to resolve.

  • Slow database queries. Database size may increase significantly and as a result queries may take more time to execute. Scaling and optimizing the database become difficult.

  • Publishing and deploying new updates to production become a nightmare. The whole application needs to be rebooted. This is not what we want if we are talking about several updates a day.

  • More resource usage (cpu+memory). Additionally, the application may take more time to start up.

  • Vulnerable application stability and reliability. The application codebase runs within and shares the same process. A single bug, in any place may cause the whole application to shut down (a memory leak issue for example).

  • Refactoring and migrating to new technologies become difficult.

Microservices

Often when scaling monoliths and dealing with their issues, microservices come to the rescue which in fact are the next iteration in their evolution path.

Microservices allow to split an application to many services where each service is a minimal standalone application, having its own database, performing a single task (for example user registration). That why it is called a microservice.

The most common approaches for implementing microservices are:

  • Event-driven microservices:

                           ┌─────────────┐
        ┌──────────────────►Front Service│
        │                  └─────────────┘
        │
        │
        │     ┌─────────┐    ┌─────────┐    ┌─────────┐
        │     │Service A│    │Service B│    │Service C│
        │     └────▲────┘    └────▲────┘    └────▲────┘
        │          │              │              │
        │          │              │              │            Event bus
  ──────▼───▲──────▼───────▲──────▼───────▲──────▼───────▲───────────────
            │              │              │              │
            │              │              │              │
       ┌────▼────┐    ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
       │Service D│    │Service E│    │Service F│    │Service G│
       └─────────┘    └─────────┘    └─────────┘    └─────────┘

  • Restfull APIs (and similar architectures):

                    ┌───────┐
                    │ Front │
       ┌────────────┤Service├─────────────┐
       │            └───┬───┘             │
       │                │                 │
  ┌────▼────┐      ┌────▼────┐       ┌────▼────┐
  │Service A│      │Service B│       │Service C│
  │  ┌───┐  │      │  ┌───┐  │       │  ┌───┐  │
  │  │API│  │      │  │API│  │       │  │API│  │
  └──┴─┬─┴──┘      └──┴───┴──┘       └──┴─┬─┴──┘
       │                                  │
       └────────┐                         │
                │                         │
           ┌────▼────┐      ┌─────────┐   │
           │Service D│      │Service E│   │
           │  ┌───┐  ├──────►  ┌───┐  │   │
           │  │API│  │      │  │API│  │   │
           └──┴─┬─┴──┘      └──┴───┴──┘   │
                │                         │
           ┌────▼────┐      ┌─────────┐   │
           │Service F│      │Service G│   │
           │  ┌───┐  │      │  ┌───┐  ◄───┘
           │  │API│  │      │  │API│  │
           └──┴───┴──┘      └──┴───┴──┘

Pros

  • Single responsibility principle. Each microservice is independent and performs a single business task.

  • Decentralized database. Instead of a single shared database storing all application data, each microservice owns and manages its database. Database queries are executed within the microservice boundaries and does not affect other queries from other microservices. A service database can be scaled independently to meet the scaling needs.

  • Smooth deployments. Each microservice is a single unit which can be deployed independently and without influencing the operation of the entire application.

  • Better productivity and development speed. Instead of a shared codebase which may grow and become difficult to maintain, each microservice lives in its own codebase and provides a single application component which can be developed and maintained independently.

  • Better isolation and resilience. Microservices do not share a single process, but run independently of each other. Critical issues and bugs do not affect the whole application, but only one or more microservices. This hugely improves application resilience.

  • Better scalability. Instead of scaling the entire application, only one or more microservice can be scaled depending on its own load.

Cons

  • Complexity. Microservices introduce more complexity than convenience for small to medium applications.

  • Eventual data consistency. Application data are split between many microservices. Managing data consistency is difficult and requires extra steps and coordinating mechanisms to be implemented to deal with inconsistencies.

  • Increased latency. Communication between microservices requires extra network calls (for Restfull APIs and similar architectures) which may increase overall application latency.

Which architecture is better for me?

Early optimizations are the root of all evil. Microservices should be regarded as an evolution of a monolith.

If you are starting a new project and hesitating about either to use microservices or not, it is definitely obvious that you should go with a monolith. Even if your application is expected to grow fastly and have a large number of client requests.

The limits of a monolith can be more than enough for most common applications and use-cases. Do not forget that monoliths can be scaled too.

When you start hitting the limits and encountering different issues, you may consider migrating to microservices.

Conclusion

Within this post we have reviewed monolith and microservices architectures and discussed the pros and cons of the both architectures.

For sure, microservices architecture sounds very promising, modern, and attractive but, the hidden side of it is that it requires a lot of expertise and experience for dealing with its cost and complexity. That why it is usually advised to start with a monolith for simplicity and ease of management.

However, as we have seen, despite the extra cost and complexity, microservices architecture is a convenient alternative with many advantages to a big monolith.

So as for every technology, nothing comes without a cost. You should always keep a balance between the cost of a solution and its benefits.