Microservices


Microservice architecture – a variant of the service-oriented architecture structural style – arranges an application as a collection of loosely coupled services. In a microservices architecture, services are fine-grained and the protocols are lightweight.

Introduction

There is no single definition for microservices. A consensus view has evolved over time in the industry. Some of the defining characteristics that are frequently cited include:
A microservice is not a layer within a monolithic application. Rather it is a self-contained piece of business functionality with clear interfaces, and may, through its own internal components, implement a layered architecture. From a strategy perspective, microservices architecture essentially follows the Unix philosophy of "Do one thing and do it well". Martin Fowler describes a microservices-based architecture as having the following properties:
It is common for microservices architectures to be adopted for cloud-native applications, serverless computing, and applications using lightweight container deployment. According to Fowler, because of the large number of services, decentralized continuous delivery and DevOps with holistic service monitoring are necessary to effectively develop, maintain, and operate such applications. A consequence of following this approach is that the individual microservices can be individually scaled. In the monolithic approach, an application supporting three functions would have to be scaled in its entirety even if only one of these functions had a resource constraint. With microservices, only the microservice supporting the function with resource constraints needs to be scaled out, thus providing resource and cost optimization benefits.

History

As early as 2005, Peter Rodgers introduced the term "Micro-Web-Services" during a presentation at the Web Services Edge conference. Against conventional thinking and at the height of the SOAP SOA architecture hype curve he argued for "REST-services" and on slide #4 of the conference presentation, he discusses "Software components are Micro-Web-Services". He goes on to say "Micro-Services are composed using Unix-like pipelines. Services can call services. Complex service-assemblies are abstracted behind simple URI interfaces. Any service, at any granularity, can be exposed." He described how a well-designed microservices platform "applies the underlying architectural principles of the Web and REST services together with Unix-like scheduling and pipelines to provide radical flexibility and improved simplicity in service-oriented architectures.
Rodgers' work originated in 1999 with the Dexter research project at Hewlett Packard Labs, whose aim was to make code less brittle and to make large-scale, complex software systems robust to change. Ultimately this path of research led to the development of resource-oriented computing, a generalized computation abstraction in which REST is a special subset.
In 2007, Juval Löwy in his writing and speaking called for building systems in which every class was a service. Löwy realized this required the use of a technology that can support such granular use of services, and he extended Windows Communication Foundation to do just that, taking every class and treating it as a service while maintaining the conventional programming model of classes.
A workshop of software architects held near Venice in May 2011 used the term "microservice" to describe what the participants saw as a common architectural style that many of them had been recently exploring. In May 2012, the same group decided on "microservices" as the most appropriate name. James Lewis presented some of those ideas as a case study in March 2012 at 33rd Degree in Kraków in Micro services - Java, the Unix Way, as did Fred George about the same time. Adrian Cockcroft, former director for the Cloud Systems at Netflix, described this approach as "fine grained SOA", pioneered the style at web scale, as did many of the others mentioned in this article - Joe Walnes, Dan North, Evan Bottcher, and Graham Tackley.
Microservices is a specialization of an implementation approach for service-oriented architectures used to build flexible, independently deployable software systems. The microservices approach is a first realisation of SOA that followed the introduction of DevOps and is becoming more popular for building continuously deployed systems.
In February 2020, the Cloud Microservices Market Research Report predicted that the global microservice architecture market size will increase at a CAGR of 21.37% from 2019 to 2026 and reach $3.1 billion by 2026.

Service granularity

A key step in defining a microservice architecture is figuring out how big an individual microservice has to be. There is no consensus or litmus test for this, as the right answer depends on the business and organizational context. For instance, Amazon famously uses a Service-oriented architecture where a service often maps 1:1 with a team of 3 to 10 engineers.
It is considered bad practice to make the service too small, as then the runtime overhead and the operational complexity can overwhelm the benefits of the approach. When things get too fine-grained, alternative approaches must be considered - such as packaging the function as a library, moving the function into other microservices.
If Domain-driven design is being employed in modeling the domain for which the system is being built, then a microservice could be as small as an Aggregate or as large as a Bounded Context.

Benefits

The benefit of decomposing an application into different smaller services are numerous:
The microservices approach is subject to criticism for a number of issues:
The architecture introduces additional complexity and new problems to deal with, such as network latency, message format design, Backup/Availability/Consistency, load balancing and fault tolerance. All of these problems have to be addressed at scale. According to the findings from the State of Microservices 2020 report, maintenance and debugging is still one of the biggest problems for the development teams building microservices.
The complexity of a monolithic application does not disappear if it gets re-implemented as a set of microservice applications. Some of the complexity gets translated into operational complexity. Other places where the complexity manifests itself is in the increased network traffic and resulting slower performance. Also, an application made up of any number of microservices has a larger number of interface points to access its respective ecosystem, which increases the architectural complexity. Various organizing principles have been applied to reduce the impact of such additional complexity.

Technologies

Computer microservices can be implemented in different programming languages and might use different infrastructures. Therefore, the most important technology choices are the way microservices communicate with each other and the protocols used for the communication. In a traditional system, most technology choices like the programming language impact the whole system. Therefore, the approach for choosing technologies is quite different.
The Eclipse Foundation has published a specification for developing microservices, Eclipse MicroProfile.

Service mesh

In a service mesh, each service instance is paired with an instance of a reverse proxy server, called a service proxy, sidecar proxy, or sidecar. The service instance and sidecar proxy share a container, and the containers are managed by a container orchestration tool such as Kubernetes, Nomad, Docker Swarm, or DC/OS.
The service proxies are responsible for communication with other service instances and can support capabilities such as service discovery, load balancing, authentication and authorization, secure communications, and others.
In a service mesh, the service instances and their sidecar proxies are said to make up the data plane, which includes not only data management but also request processing and response. The service mesh also includes a control plane for managing the interaction between services, mediated by their sidecar proxies. There are several options for service mesh architecture: Istio, Linkerd, Consul and many others in the . The service mesh management plane, , provides lifecycle, configuration, and performance management across service mesh deployments.

A comparison of platforms

Implementing a microservice architecture is very difficult. There are many concerns that any microservice architecture needs to address. Netflix developed a microservice framework to support their internal applications, and then open-sourced many portions of that framework. Many of these tools have been popularized via the Spring Framework – they have been re-implemented as Spring-based tools under the umbrella of the Spring Cloud project. The table below shows a comparison of an implementing feature from the Kubernetes ecosystem with an equivalent from the Spring Cloud world. One noteworthy aspect of the Spring Cloud ecosystem is that they are all Java-based technologies, whereas Kubernetes is a polyglot runtime platform.
Microservices concernSpring Cloud & Netflix OSSKubernetes
Configuration management: configuration for a microservice application needs to be externalized from the code and be retrievable via a simple service call.Spring Config Server, Netflix Archaius both support a Git-repository—based location for configuration. Archaius supports data typing of configuration.Kubernetes ConfigMaps exposes the configuration stored in etcd via services. Kubernetes Secrets supports the service-based secure deployment and usage of sensitive configuration information.
Service discovery: maintain a list of service instances that are available for work within a microservice domain.Spring Cloud Eureka allows clients to register to it, maintains a heartbeat with registered clients, and maps service names to hostnames for clients that lookup services by service name.Kubernetes Services provide deployment-time registration of instances of services that are internally available within the cluster. Ingress is a mechanism whereby a service can be exposed to clients outside the cluster.
Load balancing: The key to scaling a distributed system is being able to run more than one instance of a component. Load has to be then distributed across those instances via a load balancer.Spring Cloud Ribbon provides the ability for service clients to load balance across instances of the service.Kubernetes Service provides the ability for the service to be load-balanced across service instances. This is not the equivalent of what Ribbon provides.
API gateway: The granularity of APIs provided by microservices is often different than what a service client needs. API Gateways implement facades and provide additional services like proxying, and protocol translation, and other management functions.Spring Cloud Zuul provides configuration-based API facadesKubernetes Service and Ingress resources, Istio, Ambassador are solutions that provide both north–south as well as east–west API gateway functions.
Security concerns: Many security concerns are pushed to the API gateway implementation. With distributed microservice applications, it makes sense to not reinvent the security wheel and allow for policy definition and implementation in components that are shared by all services.Spring Cloud Security addresses many security concerns through Spring Cloud ZuulThe Kubernetes ecosystem provides [|service meshes] like Istio, which are capable of providing security through their API gateway mechanisms.
Centralized logging: It is important to have a centralized log gathering and analysis infrastructure to manage a plethora of services – many of which are operating in a distributed fashion.ELK Stack EFK Stack
Centralized metrics: A centralized area where the health and performance of the individual services and overall system can be monitored is essential to proper operations.Spring Spectator & AtlasHeapster, Prometheus, & Grafana
Distributed tracing: Per-process logging and metric monitoring have their place, but neither can reconstruct the complex paths that transactions take as they propagate across a distributed system. Distributed tracing is an essential tool for a microservices platform.Spring Cloud SleuthHawkular, Jaeger
Resilience and fault tolerance: Distributed systems must be capable of auto-routing around failures, and be capable of routing requests to the service instance that will provide an optimum response.Spring Hystrix, Turbine, & RibbonHealth check, service meshes
Autoscaling and self-healing: Distributed systems respond to higher load by scaling horizontally: the platform must detect and auto-respond to such conditions. Furthermore, the system needs to detect failures and attempt auto-restarts without operator input.-Health check, self-healing, and auto-scaling
Packaging, deployment, and scheduling: Large-scale systems require robust package management, and deployment systems to manage rolling or blue-green deployments, and rollbacks if necessary. A scheduler helps determine which particular execution node a new set of services can be deployed to based on current conditions.Spring Boot, Apache Maven. The Spring Cloud system does not have a true scheduler.Docker, Rkt, Kubernetes Scheduler & Deployment, Helm
Job management: scheduled computations disconnected from any individual user requests.Spring BatchKubernetes Jobs and Scheduled Jobs
Singleton application: limit a specific service to run as the only instance of that service within the entire system.Spring Cloud ClusterKubernetes Pods