We provide users with a Technical Exchange platform where we offer solutions to common issues encountered during daily product use. If you have additional questions, please reach out to us through the Contact Us section, and we will do our best to address any concerns.

The term "microservice architecture" has emerged over the past few years to describe a particular approach to designing software applications as suites of independently deployable services. While there is no precise definition of this architectural style, there are certain common characteristics around organization of business capabilities, automated deployment, end-to-end integration, and decentralized control of languages and data.
"microservice" is just a new term that has appeared on the already crowded street of software architecture. Although we may be dismissive of this new term, the style of software systems it describes has been increasingly drawing our attention. Over the past few years, we have found that more and more projects are adopting this style, and the feedback so far has been positive, to the point that many of my colleagues now treat it as the default approach when designing enterprise architectures. Unfortunately, there is not much information available about what exactly a microservice is or how to use it.
In short, the microservice architectural style is an approach to developing a single application as a suite of small services. Each service runs in its own process and communicates through lightweight mechanisms such as HTTP APIs. These services are built around business capabilities and deployed independently using automated deployment tools. There can be a very lightweight centralized management to coordinate these services. Services can be written in different programming languages and use different data stores.
Before explaining what a microservice is, it is useful to first describe the monolithic application: building an application as a single unit. Enterprise applications typically consist of three major parts: a client-side user interface (composed of HTML and Javascript, accessed through a browser), a database (consisting of many tables forming a common, interrelated data management system), and a server-side application. The server-side application handles HTTP requests, executes domain logic, retrieves and updates data in the database, and selects and populates HTML views to send to the client. This server-side application is a monolith, a single logical executable. Any change to the system requires recompiling and redeploying a new version of the server-side application.
Such a monolithic application is naturally built as a single system. Although the basic features of a development language can be used to encapsulate the application into classes, functions, and namespaces, all requests in the business must be processed within a single process. In some scenarios, you can run and test the application on a developer's laptop, then deploy the tested program to the production environment through a deployment pipeline. You can also scale horizontally by deploying instances to multiple servers behind a load balancer.
Indeed, monolithic applications can be successful. However, more and more people are sensing problems, especially when applications are deployed to the cloud. The change-release cycle becomes tied together: changes that could have been divided into small applications and small requirements must be compiled and released as a whole. Over time, it becomes difficult for developers to maintain a good modular architecture, making it hard to ensure that changes to one module do not affect others. Scaling can only be done as a whole, rather than scaling individual parts as needed.

figure 1:Monoliths and microservices>
These issues have led to the emergence of the microservice architectural style: building applications as services. These services can be independently deployed and independently scaled. Each service provides a clear module boundary, and different services can even be implemented in different programming languages and managed by different teams. The concept of microservice is not something we invented; it traces back at least to the design principles of the Unix era. We believe the benefits of this style have not received enough attention.
We cannot provide a formal definition of microservice, but we can attempt to describe the common characteristics that fit this architectural style. Not every service will possess all of these characteristics, but we do expect most microservice architectures to exhibit the majority of them. Although our authors are already active members of a loosely connected community, we are trying to describe what we understand about microservice from our work and from the components we are familiar with. We do not rely on definitions that have already been explicitly established.
Ever since we have been in the software industry, our desire has been to build systems by assembling components together, much like how things are built in the physical world. Over the past few decades, we have seen significant progress in public libraries across most language platforms.
When talking about components, we run into the difficulty of defining what a component is. Our working definition is: a component is a unit of software that is independently replaceable and upgradeable.
microservice architectures also use component libraries. The primary way to componentize software is to break it down into services. We define libraries as components that are linked into a program and invoked using in-memory function calls. Services are out-of-process components that communicate via mechanisms such as web service requests or remote procedure calls. (This is a different concept from service objects in other object-oriented programs.)
One reason for using services as components (rather than libraries) is that services are independently deployable. If you have an application composed of multiple libraries running in a single process, any change to a single component requires redeploying the entire application. However, by decomposing the application into multiple services, you can expect that changes to each service only require redeploying that service. Of course, this is not absolute; for example, changes to a service interface will require corresponding changes to dependent services. But good architectural design minimizes the impact of changes by cohering service boundaries and evolving services according to contracts.
Another consideration for using services as components is that it results in more explicit interfaces. Most languages do not have a good mechanism for defining an explicit published interface. Often, only documentation and specifications prevent excessive coupling between components. Explicit remote call mechanisms help avoid this problem.
Using services also has its own drawbacks. Remote calls are more expensive in terms of performance than in-process calls. Remote APIs tend to be coarser-grained and less convenient to use. When changing the responsibilities of a component, the impact on inter-process interactions makes the operation more difficult.
As a first approximation, we observe that each service runs in its own process. Note that this is only a first approximation. A service can also consist of multiple processes that are developed and deployed together, such as an application process and a database used only by that service.
When splitting a large application into smaller parts, the focus is often on the technology layer, dividing into UI teams, server-side logic teams, and database teams. When teams are divided along these lines, even a very small change can lead to cross-team project coordination, consuming time and budget approvals. A smart team will optimize around this by focusing on the application logic they are involved in and making better choices from there. In other words, logic is everywhere. Conway's Law is one such example.

The microservice approach to division is different. It tends to organize services around business capabilities. These services can be implemented using different technology stacks, including user interfaces, persistence layers, or any external collaborations. Therefore, teams should be cross-functional, encompassing all the skills required for development: user experience, databases, and project management.

One company organized in this way is www.comparethemarket.com, where cross-functional teams are responsible for building and operating each product, and each product is split into a number of individual services that communicate via messaging.
Large monolithic applications can also be modularized along business capabilities, though such examples are uncommon. We would also encourage a large team building a monolithic application to divide along business lines. The main problem we see is that this form of componentization leads to many contextual dependencies. If the system spans many module boundaries, it is difficult for a single team to resolve issues quickly. Furthermore, we find that modularization requires extensive rules to enforce, whereas services with clear divisions also make the boundaries between teams clearer.
Most development efforts use a model aimed at delivering a piece of software. Once the software is developed, it is handed over to a maintenance team, and the project team is disbanded.
Proponents of microservice suggest avoiding this model and instead having a team own the full lifecycle of a product. A common example is Amazon's "you build, you run it" approach, which requires the development team to take full lifecycle responsibility for Software Products. This enables developers to monitor how the product runs on a daily basis and maintain close contact with users, providing necessary support.
The product approach to development means being tightly aligned with business capabilities, rather than viewing software as a set of completed features. The focus is on how the software helps users enhance their business capabilities.
Monolithic applications can also adopt this product mindset, but finer-grained services make it easier to create the relationship between developers and users.
When building communication structures between different processes, we have seen many products and approaches that emphasize incorporating significant intelligence into the communication mechanism itself. A typical example is the Enterprise Service Bus (ESB). ESB products often include highly intelligent facilities for message routing, choreography, transformation, and applying business rules.
The microservice community advocates a different approach: smart endpoints and dumb pipes. Applications built with microservice aim to be as "highly cohesive and loosely coupled" as possible. They own their own domain logic and work more like classic Unix "filters": receive a request, process the logic, and return a response. These applications are orchestrated using simple REST-style protocols, rather than complex protocols such as WS, BPEL, or centralized orchestration tools.
Two protocols are most commonly used: HTTP request-response with resource APIs, and lightweight messaging protocols. The most important recommendation is:
microservice teams adopt principles and standards based on the internet (broadly speaking, including Unix systems). Frequently used resources can be cached by developers or operators with almost no additional cost.
The second approach is publishing messages over a lightweight message bus. The communication protocol is very simple (simple enough to only handle message routing). Simple implementations like RabbitMQ or ZeroMQ do not even provide reliable asynchronous mechanisms, relying instead on the endpoints or services that produce or consume messages to handle such concerns.
In a monolithic system, components run within the same process and communicate with each other through method calls or function calls. The biggest challenge in transforming a monolithic system into microservice architecture lies in changing the communication patterns. Naively converting in-memory method calls to RPC calls leads to chatty communications between microservice instances, resulting in poor system performance. Instead, fine-grained inter-service communication should be replaced with coarser-grained protocols.