📜 ⬆️ ⬇️

Just about microservices

Introduction


Almost every second person who first encounters with MSA (Micro Service Architecture) at first exclaims: “Yes, I still have these microservices ... more than twenty years ago." In part, they are right. And I, too, was from this very half, and did not understand why such noise?



Indeed! After all, MSA is also about software development. What kind of revolution can there be? All techniques are familiar. In some places one may even wonder: “Is it really different?” Fans of Agile and DevOps will also say that this is all ours, dear.
')
But I ask you to be patient and continue reading further.

What is microservice architecture (MSA)


To paraphrase Wikipedia, the definition of microservice architecture can be as follows:
MSA is the principle organization of a distributed system based on microservices and their interaction with each other and with the environment over the network, as well as the principles that guide the design of the architecture, its creation and evolution.

What is microservice (MS)


With architecture sorted out quickly. With microservices let's more in detail.
It is easiest to understand the essence of microservice by comparing, or even contrasting it with a large application - a monolith. Unlike MSA, I will not define microservice, but list its most important characteristics.

And then we look at each of them in more detail.



I highlighted eight properties of microservice:

  1. He is not big.
  2. He is independent.
  3. It is built around a business need and uses a limited context (Bounded Context) .
  4. It interacts with other microservices over the network based on the pattern of Smart endpoints and dumb pipes.
  5. Its distributed essence obliges to use the Design for failure approach.
  6. Centralization is bounded above at the minimum.
  7. The processes of its development and support require automation.
  8. Its development is iterative.

Already at this point, those who allegedly created microservices in prehistoric times should think whether everything was really so advanced ... Personally, at this stage I moved into the category of doubters.

Small


What is “small”? Such a uninformative wording! Actually, you can’t tell otherwise. Each must independently determine the size. Best in practice. As an indicative assessment can be guided by the recommendations of experts. The size of microservice should be such that one of the following conditions is met:

  1. One service can be developed by one team of no more than a dozen people.
  2. A team of half a dozen people can develop half a dozen services.
  3. The context (not only of business, but also of development) of one service is placed in the head of one person.
  4. One service can be completely rewritten by one team for one Agile iteration.

Independent


Microservice architecture is the epitome of High Cohesion and Low Coupling patterns. Everything that contradicts this is rejected mercilessly. Otherwise, the team will face big problems. So microservice must be an independent component.

Here I ask you not to start a holivar about what a “component” is. In this article, let's get together on the fact that
A component is a software unit whose code can be independently replaced or updated.

Of course, any more or less serious program is written with a division into components, which, of course, are based on the same principles. But in a monolith, a common code base opens up possibilities for breaking low connectivity. And with a weak discipline, sooner or later the code turns into spaghetti.

Third-party libraries are also suitable for this component formulation. Here it is more difficult with violation of boundaries by arbitrary links, but not by a lot.

At the same time, the methodology of splitting into separate microservices forces them to adhere to their strict separation, because they must meet more stringent criteria of independence.

So, each microservice works in its own process and therefore must explicitly define its own API. Considering that other components can use only this API, and besides, it is remote, minimization of connections becomes vital.



This separation gives a clear gain in terms of the independent development of different components. And with this in mind, various languages ​​introduce constructions that allow the explicit creation of independent components (for example, modules in Java 9), and this is no longer the prerogative of the microservice approach.

I don’t want the impression that the use of libraries is prohibited in the microservice architecture. Their use is not welcome , because somehow it leads to dependencies between microservices, but it is still allowed . As a rule, this assumption applies to infrastructure functions such as logging, calling a remote API, error handling, and the like.

Independence of microservices allows you to organize an independent development life cycle, create individual assemblies, test and deploy.

Since the size of microservices is small, it is obvious that there will be a lot of them in large systems. Managing them manually will be difficult. Therefore, the team must have an acceptable level of automation according to Continuous Integration and Continuous Delivery.

Where is microservice (business need)


So, you decided to design a new microservice.

Defining its boundaries is the most important step. The whole future life of microservice will depend on this, and this will seriously affect the life of the team responsible for it.

The main principle of determining the microservice responsibility area is to form it around a certain business need. And the smaller it is, the more formalized its relationship with other areas, the easier it is to create a new microservice. In general, a fairly standard message. It is based on the creation of any other components. The only question is to continue to withstand this area of ​​responsibility, which we discussed in the previous paragraph.

When the boundaries of microservice are set and it is highlighted in a separate code base, it is easy to protect these boundaries from unwanted influence. Further, inside the microservice create their own microcosm, based on the pattern of "limited context". In microservice for any object, for any action there can be its own interpretation, different from other contexts.



But what if the borders were wrong? In this case, a change in functionality in a new microservice leads to a change in functionality in other microservices. As a result, the interfaces of all dependent microservices will “float”, followed by integration tests. And everything turns into a snowball. And if these microservices also belong to different teams, then inter-team meetings, coordination and the like begin. So the correct boundaries of microservice are the basis of a healthy microservice architecture.

To minimize errors in determining the boundaries, you must first think them over. Therefore, the Monolith First approach is justified, when the system is first developed in the traditional paradigm, and when established areas appear, they are distinguished into microservices. But everything flows and changes. And the boundaries can also change. The main thing is that the gain from splitting exceeds the difficulty of revising these boundaries. Such an approach to the gradual formation of a set of microservices is similar to the iterative development used in Agile, also called “Evolutionary Design”.

There is another interesting consequence of the creation of microservices, corresponding to Conway's law (Conwey Law).

If an organization uses a monolithic application, then it violates compliance with the structure and communications within the organization. And the development teams are built around the architectural layers of the monolith: UI, server logic, database.

Microservice architecture brings IT and business in harmony, from the point of view of Conway. Since microservices are formed around the business needs of specific business units, the enterprise architecture begins to repeat the organizational structure and channels of social and business communication. And teams become cross-functional and form around these business needs / business units.



Since different microservices are independent not only logically but also technologically, and different teams can create them, nothing prevents you from choosing suitable programming languages, frameworks and even operating systems for each case.

Integration. Smart endpoints and dumb pipes


Integration of microservices dispenses with ESB, as a central intermediate. Probably, the community has already suffered from unsuccessful options for implementing this approach. What was and successful - not taken into account. However, the ESB also contradicts such criteria as decentralization and independence. Thus, the complexity of integration is distributed from the central level in the form of an ESB directly to the components to be integrated: “smart end points”.



As a rule, simple text protocols based on HTTP are used for integration in order to offset possible technological differences between microservices. REST-like protocols are practically standard. As an exception, binary protocols like Java RMI or .NET Remoting can be used.

There is a dilemma. Of course, binary protocols are much more efficient. But, first, there are technological limitations. Secondly, on binary protocols it is more difficult to implement the Tolerant Reader pattern, while maintaining efficiency. Thirdly, the dependence of the provider and consumers appears again, since they operate on the same objects and methods, that is, are linked by code base.

Another distinctive feature of the interaction of microservices - synchronous calls are not welcome. It is recommended to use one synchronous call per user request, or refuse from synchronous calls altogether.

And a couple of comments.

  1. The main difficulty of splitting a monolith into microservices is not defining their boundaries. They should already be formed and settled. The difficulty is that local calls become remote. And this affects not only the organization of calls, but also the style of interaction, since frequent calls are no longer suitable. Most likely, it is necessary to revise the API itself, make it larger, and, as a result, revise the logic of the components.
  2. Since asynchronous event interaction is practically a standard in the microservice architecture, it is necessary to understand the creation of event-driven architecture (Event Driven Architecture), and microservices themselves must comply with the requirements of Reactive.

Design for failure for a distributed system


One of the most critical places in the microservice architecture is the need to develop code for a distributed system, the constituent elements of which interact through a network.

And the network is unreliable in nature. The network can simply refuse, it can work badly, it can suddenly stop missing some type of messages, because the firewall settings have changed. Dozens of causes and types of inaccessibility.



Therefore, microservices may suddenly stop responding, may begin to respond more slowly than usual. And every remote call must take this into account. Must properly handle different options for failure, be able to wait, be able to return to normal operation when the counterparty is restored.

An additional level of complexity brings event architecture. And the debugging of such a system is not one microservice, but systems where many streams of multidirectional disordered events are difficult to imagine. And even if each of the microservices will be flawless in terms of business logic, this is not enough. By analogy with sports, “stars” do not guarantee a star team, because in a team, not the “stars” are more important, but the coherence of all its players.



And since the complexity of such systems is very high, the problem is solved as follows.


All this is useful for any monolith, but for microservices such infrastructure is a matter of life and death.

Data decentralization


Another one of the most important elements in the microservice paradigm.
Each microservice in its database!

Populist slogan on the election.

In fact, in the monolith, you can fight for the isolation of components, for example, at the level of server code. If isolation occasionally leaks, modern tools offer advanced refactoring tools. Use. Although, as a rule, there is time for this only when things are already very bad.

Now we will lower down, on database level. For some reason, attention here is much less often paid to isolation. As a result, after a couple of three years of active development in the monolith database, the entropy of the advanced level is formed if not chaos. To overcome it, there is not enough one line in backlog. It takes months of hard and long work.

In microservice architecture, this is solved by the guillotine. There is simply no common database.

In addition to isolation, there are side advantages. For example, it is easier to implement Polyglot Persistence when the base is selected for specific goals. Nothing prevents you from doing this without microservices, and they often do this. But nevertheless in one case it is the law, in another - an exception.



This medal has a downside. Many bases, many contexts, how to harmonize them all? The old technique of distributed transactions is complex and has low speed. Perhaps this can sometimes be experienced. But the need for simultaneous interaction of several microservices can not arrange, and it can not be overcome.

The problem is solved unconventionally for the monolith: the rejection of the constant consistency of data. Welcome to the world of Eventual consistency . At first, this causes a wave of “just” anger. But if you figure it out, is immediate data consistency needed at the end of the transaction everywhere? On closer examination, a significant portion of cases can be dropped. Where possible, replace a single distributed transaction with a series of local transactions with compensation mechanisms. Somewhere they put up with a temporary inconsistency. And possible errors are either processed at the expense of a more complex architecture, or due to monitoring data. If nothing happens, then in extreme cases, they use distributed transactions. But this, from my point of view, is a violation of the principles of MSA.



Monolith against microservices


The microservice approach carries quite a lot of problems. They are not difficult to find and everyone can exercise.

For example, organizational issues. How to keep a hundred microservices in a state-coordinated version that are constantly and unpredictably redefined. And access to the environments of each engineer of each team? Which team will write integration tests? And if someone agrees, then try again to write them for such a confusing configuration. And if an error occurs, then whose is it? Only the team that broke? How not to know on Friday evening that the API version of the Nth service you are using has suddenly become deprecated?

Yes, these are really problems. But teams that practice Agile and DevOps already know the solution. Therefore, to begin the path to microservice architecture is the introduction of these practices.

In addition to organizational and purely architectural. How to move from a monolith, where everything is synchronous, consistent and uniform, to a distributed event architecture based on many small elements, in which possible inconsistency of data should be taken into account? This alone is enough to think: is the game worth the candle? Against this background, for example, a drop in the speed of processing a single request seems trivial. At least it works!



Then why? If you have no problems with your "monolith", then do not look for them.

But if there is a problem, then look at the advantages of MSA, and maybe it will save you.

The division into independent components gives unconditional and incontestable advantages: easy understanding of the context, flexibility of development, management and scaling. Independence and small size provide unexpected advantages in terms of infrastructure. You no longer need a monster machine for $ 100,500. Microservices can be installed on ordinary cheap cars. And it turns out that even all together they will cost an order of magnitude less, but to work more efficiently than the very super machine that you, for sure, in your organization, pray and blow dust particles off of it.

Here another slogan from the populist is appropriate. Although, like the previous one, it is quite serious.
Each microservice on the server!

We continue to agitate for microservices. Look at the leaders of the IT industry: Amazon, Netflix, Google and others show impressive results. Their flexibility and speed of output of new products are amazing. Therefore, the game is definitely worth the candle! It is appropriate to recall here that in the above-mentioned organizations of the “level of god” teams there is not one and not two. The complexity of microservice architecture is in the teeth. And if you propose to create a monolith, then they will make it so that it will shine a guiding star.

And, for example, Amazon worked for itself on a monolith, already being a giant and having billions of dollars in turnover. The site of the Guardian newspaper is still, and possibly forever, based on microservices around the monolith. This suggests that a significant part of the tasks successfully, and often easier, is solved without the involvement of microservices.

And yet this does not mean that microservices are not for you. Not gods burn pots. But rushing headlong into the pool is also not worth it. For microservice architecture, the team should be quite mature. One of the main criteria: Does it use Agile and DevOps? The team must be competent. It is difficult to formalize, but still try to soberly assess the possibilities. For example, how advanced is the team in Reactive and Event-Driven Architecture? In addition, the team must have a prepared infrastructure to support the microservice system.

However, enough. Just try it. I hope, it will turn out and enjoy.

Source: https://habr.com/ru/post/346380/


All Articles