Microservices in Practice: Technical Evaluation: Leveraging Microservices For a System's Architecture (ludotheca-share-mesh)

MarcoMarco
5 min read

Github Repo: https://github.com/marco13-moo/ludotheca-share-mesh

When implementing microservices towards a system, one must always keep in mind that there will always be trade-offs in place.

As Fowler and Lewis describes, microservices provide strong modularity- perfect for a large development team building a complex system [4]. Microservices provide greater fault isolation and deployability than traditional monoliths.

If designed correctly, one may easily scale specific microservices as opposed to one large monolith. This saves costs and truly leverages the elasticity of cloud infrastructure. Furthermore, if one microservice starts failing, the correctly implemented style allows for the entire system to still run, with inter-service calls to the failed microservice being returned with a static page as opposed to the user seeing a cascading failure effect. Such an effect may be seen with a 500 response for the book-lending system. Load-balancing further aids this notion as traffic can easily be diverted away from a failing microservice to a healthy one.

Within an enterprise scope, microservices is often seen as a cornerstone to the company's success. One cannot help to think of successful companies such as Amazon and Netflix as being synonymous with the term of microservices. This is especially true as the loosely coupled nature of microservices provided the opportunity for greater scalability, prolonging the system's lifespan and allowing autonomous development teams to fit the best languages and frameworks for their own microservice in the system.

One can see how the system can be altered and extended with a minimal set of governance- provided changes do not hinder the system's core communication and API contracts between services and clients.

Such a powerful notion is truly driven forward within the large-scale system scope, with teams developing products in parallel alongside a minimization of coordination meetings with other teams. But all benefits in architecture come with costs, and microservices are no different:

  • Microservices are inherently distributed systems, making communication to other services and the persistence layer that much more complex- with risks such as networking error and latency.

  • Following suit from the distributed architectural family, microservices can only guarantee eventual consistency, adding further complexity not found in monoliths [3].

  • Microservices further adds greater (and more expensive) operational complexity [14].

  • It assumes one has the resources to run on an automated deployment platform with a strong devops team and experienced developers and architects constructing correct saga and API composition patterns.

With all this in mind, it is evident that at the start, microservices will be far slower to develop and implement than it's monolithic counter-part.

It is far more efficient to start with a monolith unless the system one is to create will be too complex for such a style. One must also take note that if they believe a microservices architecture will solve all underlying issues, then thorough research was not properly conducted. For example, a constant cascading failure of a monolith run on-premise, may prove to have less of such failures if multiple monoliths are deployed in a cloud-based container orchestration mechanism with traffic load-balanced across them [15].

Technical Evaluation: Leveraging the Microservices Book Lending System as a Teaching Framework

Being the sole developer, core aspects such as rapid/parallel development could not be leveraged from the style's independent and strong modular nature.

Yet, as a class of software engineers, it proves useful for the entire class to expand on this base system as semi-autonomous teams. This is due to the book-lending system being componentized via services and interacting only through APIs.

It further allows exploration into correct API design, illustration to Martin's SOLID principles,

[16] as well as a myriad of patterns and their implications upon implementation.

By leveraging Kubernetes as a deployment strategy and hoisting development with Spring, one can easily see the risk of entering a vendor lock in.

Additional risks include losing control over the system by over-shifting developer vigilance up to the architecture.

The book-lending system also shows the cost of "future-proofing" the system. By heavily focusing on reducing evolution effort, actions such as mitigating circuit breakers or asynchronous messaging for sagas came at a cost.

The system now may prove to have the same cascading performance issues as a monolith when using orchestration-based sagas. Although the book-lending service does offer flexibility, from shifting the Spring-Kubernetes microservices architecture to a Istio-Kubernetes microservices service mesh, this is another cost that one has to factor in. The developer is prone again to using expensive cloud-based infrastructure when in reality, such a simple book-lending system may have been speedily built and run on premise. A monolithic approach would have provided minimal costs in time, network latency and infrastructure. As a teaching tool, using the book-lending system to show students at what application scale is appropriate for microservices proves beneficial.

To further illustrate how the book-lending system may be leveraged within a teaching perspective not purely siloed toward styles, patterns and development practices; is analysing the application of microservices in accordance to Martin's SOLID design principles [16].

The SOLID principles are practices used for software development in order to give way for greater extensibility and maintainability, minimizing smells.

  • Single Responsibility: Each microservice forms part of a sub-domain with granularity defined at the business capability level.

  • Open-Closed: The microservices do not have to be altered to provide situational functionalities. For example, a minor few line addition to the lending service pushes returned loans to a RabbitMQ queue, allowing for extension of the system without heavy alterations.

  • Liskov Substitution: Liskov substitution states derived classes of the system must be substitutable for their base classes [16]. Within a microservices context, the derived class may be seen as the microservices version. Through API contract fulfilment and RESTful communication, one can apply the Liskov Substitution Principle as a new version would be compatible with the previous [17].

  • Interface Segregation: Microservice domain-driven decomposition enforces granular interfaces that are microservice specific and not dependent on other microservices.

  • Dependency Version: Not only does Spring comply with this principle by using dependency injection; the style also leverages service discovery, creating abstraction to service name communication references as opposed to IP specific communication referencing [18].

0
Subscribe to my newsletter

Read articles from Marco directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marco
Marco

Senior DevOps Engineer exploring the world of distributed systems