Original Title: Untangling Microservices, or Balancing Complexity in Distributed Systems

Original address
address
Translation: Zhu Kunrong


image.png

Microservice

Let's start by defining exactly what services and microservices are.

What is a service?

According to the OASIS standard 9 , one service is:

Provide a mechanism to access one or more capabilities through a prescribed interface

This part of the prescribed interface is very important. The interface of the service defines the functions that it exposes to the outside world. According to Randy Shoup 10 , the public interface of a service is simply any mechanism for getting data in and out of the service. It can be synchronous, such as a simple request/response model, or asynchronous, one production event and one consumption event. In any case, synchronous or asynchronous, the public interface only means letting data in and out of a service. Randy also expressed that the public interface of the service is the same as the front door

Services are defined by public interfaces, and this definition is sufficient for defining what services are microservices.

What is a microservice?

If a service is defined by its public interface, then-

A microservice refers to a service that uses a micro public interface-micro front door

This rule followed in procedural programming is now more relevant in the field of distributed systems. The smaller the service you expose, the simpler its implementation and the smaller its local complexity. From the perspective of global complexity, smaller public interfaces will produce fewer dependencies and connections between services.

The concept of micro-interface also explains the practice of widely used micro-services that do not expose the database. No microservice can access another microservice's database, only through the public interface provided by it. why? Because the database is actually a huge public interface! Just think about how many operations you can perform on a relational database.

Therefore, to reiterate, in a distributed system, we balance the local and global complexity by minimizing the public interface of the service, and then the service becomes a microservice.

caveat

This sounds simple but it is not. If a microservice is only a service with a miniature public interface, then we can directly limit the public interface to only one method. Since this "front door" is already small and can't be smaller, this should be a perfect microservice, right? To explain why not, I will use an example 11

Join us to have the following inventory management services:
image.png

If we break it down into eight services, each with only one simple public method, we can get a perfect service with low local complexity:

image.png

But can we connect them to the system to really manage inventory? It doesn't work. To form a system, a service needs to interact with other services and share the status of each service. But they can't. The public interface of the service is not supported.

Therefore, we have to inherit this "front door" and allow these public methods to support integration between services:
image.png

That's it! If we optimize the complexity by completely independent of each service, then the decoupling is very thorough. However, when we connect the service into the system, the global complexity increases again. Not only caused the system to be involved in a mess; for integration-inheriting the public interface is also beyond our original intention. Quoting from Randy Shoup, in addition to building a small "front door", we also built a huge "employee-only" entrance! This tells us an important point:

A service has more integration methods than business methods, and it has a huge possibility to grow into a distributed big mud ball!

Therefore, the extent to which the public interface of a service can be minimized depends not only on the service itself, but also (mainly) on which part of the system it is. When the decoupling of a microservice should consider the global complexity of the system and the local complexity of the service at the same time.

Design service boundaries

"It's too difficult to find the service boundary... There is no flow chart at all!" -Udi Dahan

What Udi Dahan said above is also true for microservice-based systems. Designing the boundaries of microservices is difficult, and basically it is difficult to do it right the first time. Compromise designing a microservice of appropriate complexity becomes an iterative process.

Therefore, it is safer to start from a larger boundary-it is more appropriate to start from the context boundary 12 -After having more knowledge about the system and its business domains, decouple them into microservices. This is particularly important for services that include core business domains 13 .

Microservices outside of distributed systems

Although microservices have only recently been "invented", you can still find many implementations of the same design philosophy in the industry. These include:

Cross-functional team

We know that cross-functional teams are the most effective. This type of team allows teams of different professional abilities to work on the same task. An effective cross-functional team can maximize the communication within the team and minimize the communication outside the team.

Our industry has only recently discovered cross-functional teams, but task groups have always existed. The underlying principle is the same as that of a microservice-based system: high aggregation within the team and low coupling between teams. The "public interface" of the team is minimized by the skills required to accomplish the task (such as implementation details).

Microprocessing

I want that classic by Vaughn Vernon related topics Bowen to give this example. In his blog, Vaughn described an interesting similarity between microservices and microprocessors. He described the difference between processors and microprocessors:

I found a size specification to help determine whether a processor is a central processing unit (CPU) or a microprocessor: the size of the 21

The microprocessor's data bus is his public interface-it defines the amount of data that can be transferred between the microprocessor and other components. There are strict size specifications for the public interface to define whether the central processing unit (CPU) is a microprocessor.

Unix philosophy

Unix philosophy, or Unix way, is a modular software development norm and culture that upholds minimalism. 22

Someone might argue that my Unix philosophy is not in line with my situation. You cannot assemble a system with completely independent components. Isn't the unix program completely independent and then form a working system? The facts are just the opposite. The Unix approach almost literally defines the micro-interactions that the program needs to expose. Let's look at the Unix philosophy related to microservices:

The first principle allows the program to expose a public interface related to its function, rather than unrelated to its original goal:

Let the program do only one thing and do it well. To do another thing, write a new one instead of old program.

Although Unix commands are considered completely independent of each other, they are not. They need to communicate between them, and the second principle defines how to design the communication interface:

It is expected that the output of all programs will be used as input to other programs, although it may not be known yet. Do not let the output have irrelevant information . Avoid strict columnar or binary input formats. Do not force input for interactive commands.

Not only is the communication interface strictly restricted (standard input, standard output, standard error), based on this principle, the data transmission between commands is also strictly restricted. For example, Unix commands need to expose the micro-interface and never depend on the implementation details of other commands.

What about Nano services?

The word nanoservice is often used to describe a service that is too small. Some people will say that the service of one of the methods introduced in the above example is the nano service. I disagree with this view.

The nano service is used to describe individual services when the overall system is ignored. In the above example, once we put the system into the equation, the service interface will grow. In fact, when we compare the original single-service implementation with the decoupled implementation, we can see that once the service is connected to the system, the system grows from 8 public interfaces to 38. Moreover, the average number of methods exposed per service rose from 1 to 4.75.

Therefore, when we spend the service (public interface) again, the data nano service is no longer established because the service is forced to start to grow to support the use cases of the system.

Is this enough?

Do not. Although minimizing the public interface of a service is a good principle for designing microservices, it is still an exploratory approach and cannot replace common sense. In fact, micro-interfaces are just an abstraction of more basic and more complex coupling and cohesive design principles.

For example, if two services have micro-public interfaces, they need to be coordinated in a distributed transaction, and they are still highly coupled with each other.

It is still instructive for micro-interfaces to solve different types of coupling, such as functions, development, and semantics. But that is the subject of another blog.

From theory to practice

Unfortunately, we do not have an objective way to quantify local and global complexity. On the other hand, we do have some design methods that can optimize the design of distributed systems.

The main content of this article is to tell you that the public interface of the evaluation service is that you have to keep asking yourself:

  • What is the percentage of business-is the given service an integration-oriented endpoint?
  • Is this an endpoint that you don't want to close in business? Can you separate them into 2 or more services without introducing integration-oriented endpoints?
  • Can merging the two services eliminate the endpoint that was originally created to integrate the original service?

You can use these principles to guide your design of service boundaries and interfaces.

summary

I want to conclude with Eliyahu Goldratt's point of view. In his book, he often repeats the following sentences:

"Tell me how you measure me, and I will tell you how I behave"-Eliyahu Goldratt

When designing a system based on microservices, it is very important to measure and optimize the correct metrics. By designing the boundaries for the microservice code base, the definition of the micro team will be easier. Therefore, to develop a system, we must learn to settle accounts. Microservices are used to design systems, not independent services.

Back to the title of this piece-"Solve in a distributed system, or balance the complexity of microservices". The only way to solve the microservice problem is to balance the local complexity of each service with the global complexity of the entire system .

Reference index

  1. Gergely Orosz’s tweet on Uber
  2. Monoliths are the future
  3. Microservices guru warns devs that trendy architecture shouldn’t be the default for every app, but ‘a last resort’
  4. Monolithic Application(Wikipedia)
  5. The Majestic Monolith - DHH
  6. Big Ball of Mud(Wikipedia)
  7. Definition of a System

8 .Composite/Structures Design - book by Glenford J. Myers
9 .Reference Model for Service Oriented Architecture
10 .Managing Data in Microservices - talk by Randy Shoup
11 .Tackling Complexity in Microservices
12 .Bounded Contexts are NOT Microservices
13 .Revisiting the Basics of Domain-Driven Design
14 .Implementing Domain-Driven Design - book by Vaughn Vernon
15 .Modular Monolith: A Primer - Kamil Grzybek
16 .A Design Methodology for Reliable Software Systems - Barbara Liskov

  1. Designing Autonomous Teams and Services
  2. Emergent Boundaries - a talk by Mathias Verraes
  3. Long Sad Story of Microservices - talk by Greg Young
  4. Principles of Design - Tim Berners-Lee
  5. Microservices and [Micro]services - Vaughn Vernon
  6. Unix Philosophy

This article is from Zhu Kunrong's WeChat public account "malt bread, id "darkjune_think"
Developer/Science Fiction Enthusiast/Hardcore Host Player/Amateur Translator

Weibo: Zhu Kunrong

Station B: https://space.bilibili.com/23185593/

Communication Email: zhukunrong@yeah.net

Please specify if reprinted.


祝坤荣
1k 声望1.5k 粉丝

科幻影迷,书虫,硬核玩家,译者