Grand opening, up to 15% off all items. Only 3 days left

Microservices — literalness and spirit

Key Point

Link to the original text (Posted on 2021/11/23)

[This article is a personal opinion and does not represent the company]

Microservice patterns are powerful and popular. It will continue to grow in popularity as it solves many of the challenges of modern distributed solutions. Some developers find that microservices become very complex, instead of getting the benefits promised by microservices, they fall into a constant loop of modifying what the pattern throws. Although I've participated in several microservices projects and some have failed, writing a hands-on lesson entitled "Characteristics of Implementing Microservices" (the original title of this article) is useful to the community. I thought it might be. I looked back at each project to see if I could abstract the factors that caused the failure / success and found some interesting facts. The team, who understood microservices as a pattern of "small services," became a complex, unmaintainable solution. Microservices are a pattern of "separation services" (understanding the difference between "small" and "separation" patterns and the fact that developers must make specific design decisions that are consistent with these objectives). The team understood that they were able to make the most of it. With that in mind, I found it beneficial to explain the root causes of good and bad implementations. What we call "small service" and "separation service", or here "Letter" and "Spirit". In the process, we also explain some important concepts about patterns.

Letter: Microservices must be small

According to Wikipedia, the "prefix" comes from the Greek word μικρ? ς (mikrós), which means "small". This unfortunate choice of the word "microservices" was very confusing about the pattern, as many developers made it the ultimate goal of the pattern to cut the solution into "small" pieces, but in reality it was. It's just a way to reach the goals of the pattern.

I saw this misunderstanding directly when I cloned the client's git repository earlier. I found that all the methods (GetName, GetEmail, etc.) are in separate classes (C #) and all the classes are in separate projects. It was literally dozens of projects that required scrolling with the mouse wheel in Solution Explorer (Visual Studio) to see all the projects. I later learned that I did this with the idea that it was the right way to run microservices.

This may seem shocking at first glance, but it's only natural to know that many definitions online include "small" as part of microservices. After all, understanding that microservices mean small services, faced with the unique question of "how small should it be?", By making the solution / code small so as not to miss the benefits of microservices. , You may want to reduce the need for a clear answer.

This is an extreme example, but many other projects have more subtle nuances, but it's true that this anti-pattern exists, let's correct it. The prefix "micro" does not indicate "never small". They initially called it micro / small (assuming that any part is "smaller" than the whole that is part of it) in the context of "monolith" which means "part" of the whole. Or based on a monolith of a single function (a "single" function does not necessarily mean a "small" function), or any other reason you can think of why it is called a "micro". I probably called the one that was divided into micros. I don't think all of these explanations capture anything essential to the pattern. You cannot rename the pattern, but you can stop using "small" as part of the definition. As a first step in implementing a pattern more simply and easily, you need to coordinate the definition of the pattern and the desired implementation.

Note that the fact that microservices are not small services does not mean that microservices should be big services. What I'm saying is that size is irrelevant here and captures the wrong side of the pattern that is distorting the implementation in the wrong direction.

If microservices are not small services, what is it?

Wikipedia has a good definition of microservices. "A structural style that arranges applications as a collection of loosely coupled services."

The idea of ​​patterns is simple. There can be different needs in different parts of the solution. In that case, separate these parts to meet the needs of each part individually without affecting the other parts. Separating these parts standardizes the way they communicate with other parts and abstracts the internal implementation, making them interoperable and reusable.

Let's see an example

Figure A shows a monolithic solution. All services in this solution (represented by the gear icon) are closely linked. With this monolith as a baseline, let's understand why and when microservices are needed.

Note: I wanted to give these gears different shapes / colors to indicate different service types / functions, but emphasized that the monolith does not have to be a mix of different service types. I wanted to, so I decided to keep them all the same. With microservice patterns, monoliths have exactly one service type (for example, different resilience or scale goals) when one or a subset of these services have specific needs that differ from the other services (for example, different resilience or scale goals). Consists of all batch jobs). This is subtle but important for understanding patterns.

Going back to the example, let's say one of the gears in this solution is heavily loaded and needs to be scaled. Select one of the gears from Figure A and call it "Gear X". Since GearX is part of the monolith, you need to scale the entire monolith to meet the requirements for scaling GearX.

Mission Complete! Figure B has successfully scaled GearX and our solution can handle larger / more workloads. However, keep in mind that you encountered a false issue while working to meet your scaling requirements (it's actually a big issue!). As you can see from Figure B, the side effect of scaling GearX with a monolith is that all gears are also scaled and a huge waste of resources! In the on-premises era, we invested capital costs in our data centers. May not have been a big issue. So you usually didn't pay extra when scaling your app. However, in the cloud world, the pay-as-you-go model can't afford to scale all these gears for usage if you just want to scale GearX. Welcome to microservices, you now have your first valid use case for implementing a pattern.

Microservices — 字義と精神

To solve this problem, let's separate GearX so that it can be scaled independently of other gears – Figure C:

You can now scale up / scale out GearX without wasting resources, meeting your initial scaling requirements while maintaining the optimal cost to run your entire solution. – –

Note: Scaling the cost of capital and pay-as-you-go models is fundamental to the fact that microservices associated with the cloud are common, even though the microservices architecture is long before the cloud and is not a valid architecture for the cloud alone. That's why.

You can see where this is heading. If you can split one of the gears to optimize scale / cost, do you think you can't achieve the other goal using this same methodology? For example, the other gears on the monolith are in different parts of the world. An advertising maker processed by another team working in, we have a schedule of frequent releases to develop our daily advertising campaigns, rather than relying on our monolith release schedule. We can split the service and give the advertising team full control. They can use any language / DB / release schedule. The service is now separate / independent, so I don't care.

Communication methods should be standardized to separate these services, make them stateless (when possible), and facilitate expansion and replacement with no / minimal downtime.

In summary, don't divide your solution into smaller pieces in advance. The solution is likely to be difficult to maintain. The process is exactly the opposite. You can think of the solution as one (monolith), review your requirements, and split parts of your monolith to meet your requirements. If you have a vague requirement that you can solve it by splitting a part of the solution, we recommend that you follow good practices (such as SOLID / 12 factor ...) instead of splitting it prematurely. increase. We will make it easy to extract this partition in the future if the requirements become concrete. Absolutely avoid Figure E!

Spirit: Microservices must be separated

Let's return to the definition of microservices on Wikipedia. "It's a structural style that puts your application as a collection of loosely coupled services." – This is the spirit of the pattern, so let's solve the "loosely coupled" part. There are many things that can help loosely couple services (storage dedicated to each service, dedicated source repositories, etc.), but make sure we are on a solid foundation, two I would like to mention the main ones (that is, it cannot be done without two principles and can be added):

  1. Event-driven interactions between services
  2. Versioning the service

Principle 1: Make interactions between services event-driven

Simply put, if a call to ServiceA triggers a series of calls to ServiceB and C and D, and all of them need to succeed in order for ServiceA to return a response, the microservice is implemented in the right way. not.

Ideally, the services do not interact directly with each other. Instead, use integrated services to communicate with each other. This is usually achieved on the service bus. The goal here is to make each service independent of the others so that each service has everything it needs to start a job and doesn't care what happens after this job completes. That is. In the exceptional case where one service calls another directly, you have to handle the situation if the second service fails.

This is what turned a monolith into a typical microservices solution:

Principle 2: Versioning the service

Simply put, microservices aren't implemented the right way if the ServiceA team needs a meeting with the ServiceB team to allow them to make changes in ServiceA.

Microservices present an interesting challenge – on the one hand, the services need to be separated, and on the other hand, everything needs to be normal for the solution to work properly, so it's appropriate without breaking the solution. Need to evolve. Let's look at a simple example:

ServiceA is a service that generates a json message with a username field as a string and queues this message. ServiceB is a service that looks for a user in a json message with the string username field and expects to do something. Now suppose ServiceA has a requirement to include the username and its email address in an array in the json message. ServiceB fails to process this json payload because it expects the username field to be a string. The ServiceA team needs to respond quickly to changes, but at the same time, be careful not to introduce such bugs.

You might want to reconcile the teams working on these services and create one release for all services (when both ServiceA and ServiceB have completed their changes). It's easy to see that can't be maintained. This is a really famous buggy home cooking recipe. More importantly, when adopting this approach, it is worth revisiting the basic assumptions and asking yourself what was the benefit of separating these two services in the first place. – If you can't loosely couple services, it may be right to bring them back together.

The best way to solve this challenge is to continue to develop these services independently and version them so that they are aware of any changes that may occur. (Therefore, it remains backwards compatible until all services stop using the legacy version). In this simple example, ServiceA continues to generate the payload using username as a string (version 1), but adds version 2 which uses username as an array. ServiceB checks the version number and processes the messages that it can process (version 1) while working on the code for version 2.

There are multiple methods of versioning, but any convention is acceptable. I like the 3-digit semantic versioning 0.0.0, which is widely understood by most developers. You can easily determine what kind of change the service has made by simply checking which of the three digits has been updated. If you need a more comprehensive version control strategy, you can also see how Microsoft is doing his NuGet package.

Is version control on Day 1 a premature optimization of microservices?

This is a normal question to ask ourselves. I'm skeptical of what I'm adding to "Day 1". This is no exception, and while we recommend adding version control to Day 1, we don't recommend implementing microservices on Day 1 until the benefits of doing so become apparent. .. However, we automatically signed up for a set of known distributed system challenges once we determined that microservices were the right design. Dividing the solution into different services inevitably means different evolutions of these services. We are solving this problem by introducing version control. In addition, it is difficult to implement version control later in the development phase. Introducing it on Day 1 saves a lot of effort.

Conclusion

Defining a microservice as a "small service" is not entirely wrong, but it captures the wrong side of the pattern and leads to the wrong implementation. "Separation of services" is the spirit of the pattern and the central idea. There are two important separation principles. 1) Services should not communicate directly with each other. 2) Services need to be versioned so that they can grow independently of each other.

About the author

Alaa Tadmori is Microsoft's Cloud Solutions Architect. He is an early adopter of the cloud computing model and an enthusiastic fan. Alaa, responsible he believes in IT. As the solutions built today shape the world and become the world of children, we have the responsibility and choice to make the world a better place. When not working, Alaa likes to spend time with his family and read non-fiction books.

About the author

Alaa Tadmori

Less than see more

Related Articles

 Masaki Aiba's "VS Damashii" member theme song project started!Shori Sato & Yuta Kishi laugh at orders in English

Masaki Aiba's "VS Damashii" member theme song project started!Shori Sato & Yuta Kishi laugh at orders in English

We take the place of ... Children who directly appealed to His Majesty the Emperor for the release of his father in the Nara period (December 11, 2021) --Excite News

We take the place of ... Children who directly appealed to His Majesty the Emperor for the release of his father in the Nara period (December 11, 2021) --Excite News

The 26-year-old who doesn't know love met ... "Literature Virgin-The Story of Late Blooming Love-" (November 22, 2021) --Excite News

The 26-year-old who doesn't know love met ... "Literature Virgin-The Story of Late Blooming Love-" (November 22, 2021) --Excite News

Experts praise Tsuyoshi Shinjo's "Big Boss Reform" "The Leader Theory is Equipped" (December 28, 2021) --Excite News

Experts praise Tsuyoshi Shinjo's "Big Boss Reform" "The Leader Theory is Equipped" (December 28, 2021) --Excite News