How to avoid coupling problems in microservice design

Distributed monolith  (distributed monolith ) is a humorous term used to imply architectures that are poorly designed. If you ignore the practice of microservice design, you will not only be unable to overcome the shortcomings brought about by the integration, but also cause new and complex problems or worsen existing problems. While you are proud to call it a microservice architecture, due to the lack of purposeful design, the final architecture is no different from randomly blasted fragments.

The first step to avoid distributed integration is very simple: avoid implementing microservices at the same time. One-piece is simple, because there is no need to consider the complexity of distributed systems. A database, a log storage location, a monitoring system, simpler problem location, and end-to-end testing, etc. Unless you have a good reason to use microservices, it is best to adopt the same philosophy.

This article will focus on the importance of loose coupling in microservice design. I will give some simple examples that can avoid coupling and lead to distributed integrated architecture design.

Loose coupling in microservices?

In two systems, if the design, implementation or behavior of either party is modified without affecting the other party, the two services are said to be loosely coupled. When it comes to microservices, coupling may occur, that is, the modification of one microservice will immediately directly or indirectly affect the collaboration with all other microservices.

Let's look at some scenarios where coupling exists in the design.

Database sharing

Database sharing is a common way to achieve coupling. When one service modifies its implementation, it will result in the modification of another service's implementation.

The details of selecting data storage, schemes, and requested languages ​​should not be visible to the client. If the database is shared, all implementation details may be exposed. Why hide implementation details? This is because if the implementation details are exposed, the client code may become unavailable when the implementation details are adjusted in the future, unless the client also makes corresponding changes synchronously (this method is not feasible or sustainable) . On the left side of Figure 1, Customers and Orders share the database, so Orders can access the details of the data model of Customers. When these details change, an exception may be caused.

How should it be handled?

One way is to let Customers provide an API as shown on the right side of Figure 1, and Orders customers can obtain customer data through the API. As long as the Customer’s contract remains the same, the data format will not change. Orders does not need to know the source of the data, and Customers can decide to replace the data with another streaming data source without worrying about the impact on other services.

How to avoid coupling problems in microservice design

 

Fig. 1 — Implementation coupling through database sharing

Code sharing

In addition to using independent databases, microservices may also fall into the trap of shared library coupling. In addition to the problems caused by coupling, the expansion of shared libraries may also lead to the need to continuously update to meet the needs of clients. Therefore, shared code should be as lightweight as possible, and dependencies should be minimized, and logic in specific areas should be excluded.

On the left side of Figure 2, Customers defines a customer object in a library shared with Orders. Customers use this object model to respond to requests for customer data. Orders uses the same object to read the (requested) response body. If Customers intend to adjust the internal structure of the customer object, such as dividing the address field into multiple address lines, this situation will cause the Orders service to crash. Note that this incorrect model may also affect customers' choice of programming language. For example, when Customers decide to switch to a different programming language, it needs to consider all services implemented using its object model.

How should it be handled?

Customers and Orders should contain a copy of the customers object in the independent dependency library. As long as Customers follow the "contract", all services can operate normally.

Remember, every time there is a change, you don't need to glue a bunch of broken services together, you just need to focus on creating a flexible architecture and losing the distributed integration.

How to avoid coupling problems in microservice design

 

Fig. 2–Implementation coupling through code sharing

Synchronous communication

Temporary coupling occurs when processing cannot continue because the service (the caller) expects an immediate response from another service (the callee). Since the callee has a response delay, it may adversely affect the caller's response time. The callee must remain open and be able to respond normally. This situation usually occurs in a synchronous communication scenario.

As shown in Figure 3, the longer it takes Customers to prepare data, the longer Orders waits before responding to the client. In other words, the delayed response of Customers caused the delayed response of Orders. This processing method may also cause cascading errors. If Customers cannot respond, Orders will eventually fail to respond due to timeout. If for a period of time, Customers have been very slow and unable to respond, it may cause Orders to open a large number of connections to Customers, and eventually lead to memory exhaustion and failure. In order to provide a satisfactory service, Orders should eliminate the basis of temporary coupling. No one wants angry customers to wait in line for their orders to arrive, and the distributed all-in-one creator is no exception.

How to avoid coupling problems in microservice design

 

Fig. 3 — Temporal coupling caused by synchronous communication between services

How should it be handled?

The answer to the question depends on whether you need a long-term or a short-term solution. If you need to continue to use synchronous calls, you need to reduce the temporary dependence by caching the (requested) response or using the fuse mode to control the cascade failure. A better way is to switch to asynchronous communication, use polling or rely on a message broker like Kafka to deliver messages. When using asynchronous communication, the service should consider the impact of the delay in reaching the final consistent state with the downstream service on the response time, and make necessary adjustments to prevent the interruption of the "contract". The service level agreement is an important part of the "contract".

Shared test environment

Deployment coupling occurs when continuous integration or continuous release of one service depends on another service. Microservices means agility, independent deployment and processing are necessary to achieve this goal.

A typical example is: deployed services share the same test environment. Suppose a service needs to do a simple performance test before it is finally deployed to the production environment. If the service shares the same test environment with other services (it is possible to run performance tests at the same time), it may cause the test environment to crash or cause resource saturation due to unexpected high traffic, which may eventually lead to deployment failure.

How to avoid coupling problems in microservice design

 

Fig. 4 — Deployment coupling caused by sharing test environments

On the left side of Figure 4, Delivery and Orders use the same Customers service to simulate performance testing. The Orders team originally designed the simulation service to imitate the behavior of customers with a given amount of resources. After adding Delivery, the calculated resource amount will be invalid, and running performance tests of two services at the same time will result in deployment failure. Therefore, the simulation service must be reconfigured to use more resources to mimic the same response rate.

How should it be handled?

It's simple, don't share the mock service with any service.

Downstream services that run integration tests

This is also a deployment coupling. When a functional test is performed on a microservice instance, the microservice instance will directly call downstream services in a non-test environment. This dependency will cause downstream services to be kept running throughout the testing phase. Any delay in availability or response time of downstream services may cause the simultaneous failure of testing, build processes, and deployment.

How should it be handled?

Simulate downstream services in integration testing (unless there is a good reason to use real downstream services). A better way is to containerize downstream services and load them into the same microservice instance to avoid network connection problems.

Sharing too much field data

Domain Driven Design (DDD) is a recommended technology to split all-in-one services into microservices. The general principle is to enable one microservice for each business subdomain. Each microservice runs within the boundaries of its subdomain without having to deal with anything outside of it.

If microservices share domain-specific data, it will cause domain coupling and violate the original intention of separating boundaries. The service will not be able to control how the client uses the shared data. A client may inadvertently own data that it shouldn't own, or use it incorrectly because of lack of knowledge in a particular domain.

Furthermore, if the service shares too much domain data, it may introduce security risks due to the sharing of sensitive data. You may protect the sensitive data you think, but there is no guarantee that the client will take similar actions. This is because the responsibility and awareness of this part of the data are beyond their scope.

Figure 5 shows an example of domain coupling. On the left side of the figure, Orders requests customer data from Customers, and then receives the customer's credit card number and address. Then call Billing, pass the cost and product ID, and all these data. After Billing successfully charges the customer, Orders will send the same set of data fields to Delivery. The right side of the figure shows the expected interaction data between these microservices. If the design is reasonable, Billing should be the only microservice that owns and saves billing information, and does not need to receive this information from other services.

How should it be handled?

Only the data that the client really needs is shared. If the data that the client needs exceeds the domain boundary, the service boundary needs to be reconsidered.

How to avoid coupling problems in microservice design

 

Fig. 5 — Domain coupling through excessive data sharing

to sum up

Microservices is a new architectural style. If it is not adopted properly, it may reduce the benefits it brings. In order to avoid prematurely designing microservice networks, such as distributed integration, your system should be a whole at first, and then gradually break it up into reasonable microservices.

When migrating from an all-in-one to a microservice architecture, there may be many ways to cause design errors, among which the lack of loose coupling is a point that must be paid attention to. Coupling may appear in many forms: implementation, temporary, deployment, and domain coupling. This article gives examples of each type of coupling, as well as some suggestions to help avoid the corresponding coupling scenarios. If your service is already distributed, don’t worry, it’s never too late to follow some of the techniques discussed in this article to take corrective actions.

Original link: https://www.cnblogs.com/charlieroro/p/14428617.html

If you think this article is helpful to you, you can pay attention to my official account and reply to the keyword [Interview] to get a compilation of Java core knowledge points and an interview gift package! There are more technical dry goods articles and related materials to share, let's learn and make progress together!

Guess you like

Origin blog.csdn.net/weixin_48182198/article/details/114086018