Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Micro-service architecture: the difficulty of splitting individual applications

2025-03-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

The difficulty of splitting monomer applications into services

On the face of it, the strategy for creating a micro-service architecture by defining services that correspond to business capabilities or subdomains seems simple. However, you may encounter several obstacles:

Network latency.

Synchronous interprocess communication results in reduced availability.

Maintain data consistency between services.

Get a consistent view of the data

The class of God hinders the split.

Let's look at each problem, starting with network latency.

Network delay

Network delay has always been a problem in distributed systems. You may find that a specific decomposition of a service results in a large number of round-trip calls between the two services. Sometimes, you can reduce latency to an acceptable number by implementing a batch API to get multiple objects in a round trip. In other cases, however, the solution is to combine multiple related services and replace expensive interprocess communication with function calls in the programming language.

Synchronous interprocess communication results in reduced availability

Another issue to consider is how to handle inter-process communication without reducing the availability of the system. For example, the most common way to implement the createOrder () operation is to have Order Service invoke other services synchronously using REST. The downside of this is that a protocol such as REST reduces the availability of Order Service. If any of the invoked services are in an unavailable state, the order cannot be created. Sometimes this may be a forced compromise, but after learning about asynchronous messages in Chapter 3, you will find that there are better ways to eliminate the tight coupling merge generated by such synchronous calls to improve availability.

Maintain data consistency between services

Another challenge is how to maintain data consistency between services when some system operations need to update data in multiple services. For example, when a restaurant accepts an order, it must be updated in both Kitchen Service and Delivery Service. Kitchen Service changes the state of Ticket. Delivery Service arranges the delivery of the order. These updates must be done in an atomized manner.

The traditional solution is to use a distributed transaction management mechanism based on two-phase commit (two phase commit). But as you will see in Chapter 4, this is not a good choice for today's applications, and you have to use a very different approach to transaction management, which is Saga. Saga is a series of local transactions that collaborate using messages. Saga are more complex than traditional ACID transactions, but they work well in many cases. One limitation of Saga is that they are ultimately consistent. If you need to update some data atomically, it must be in a single service, which can be an obstacle to decomposition.

Get a consistent view of the data

Another obstacle to decomposition is the inability to get a truly consistent view of data across multiple databases. In a single application, the properties of the ACID transaction guarantee that the query will return a consistent view of the database. In contrast, in a micro-service architecture, even if the database of each service is consistent, you cannot get a globally consistent view of the data. If you need some consistent view of the data, it must reside in a single service, which is a problem with service decomposition. Fortunately, this rarely leads to real problems in practice.

The class of God hinders the split.

Another obstacle to decomposition is the existence of the so-called God class. The God class is a global class used throughout the application. The God class usually implements business logic for many different aspects of the application. It has a large number of fields mapped to database tables with many columns. Most applications have at least one such God class, each representing a concept that is critical to the domain: bank accounts, e-commerce orders, insurance policies, and so on. Because the God class binds the state and behavior of many different aspects of the application, splitting any business logic that uses it into services is often an insurmountable obstacle.

The Order class is a good example of the God class in FTGO applications. This is not surprising: after all, the purpose of FTGO is to provide food orders to customers. Most parts of the system involve orders. If the FTGO application has a single domain model, the Order class will be a very large class. It will have states and behaviors that correspond to many different parts of the application. Figure 6 shows the structure of the Order class created using traditional modeling techniques.

Figure 6 Order, the God class, carries too many responsibilities.

As you can see, the Order class has fields and methods corresponding to order processing, restaurant order management, food delivery, and payment. Because a model must describe state transitions from different parts of the application, this class also has a complex state model. In the current situation, the existence of this class makes it extremely difficult to split the code into services.

One solution is to package the Order class into a library and create a central Order database. All services that process orders use this library and access the database. The problem with this approach is that it violates a key principle of the microservice architecture and leads to tight coupling that we particularly don't want to see. For example, any change to the Order schema requires other development teams to update and recompile their code synchronously.

Another solution is to encapsulate the Order database in Order Service, which is called by other services to retrieve and update orders. The problem with this design is that such an Order Service will become a pure data service, an anemic domain model (anemic domain model) with little or no business logic. Neither of these solutions is attractive, but fortunately, DDD provides a good solution.

A better approach is to apply DDD and treat each service as a separate subdomain with its own domain model. This means that each order-related service in the FTGO application has its own domain model and its corresponding version of the Order class. Delivery Service is a good example of a multi-domain model. Order is shown in figure 7, which is very simple: pick up address, pick up time, delivery address, and delivery time. In addition, DeliveryService uses a more appropriate Delivery name than Order.

Figure 7. Domain model of Delivery Service

Delivery Service is not interested in any other attributes of the order.

Kitchen Service has a simpler view of the order. Its Order version is a Ticket (post-cook order). As shown in figure 8, Ticket contains only status, requestedDeliveryTime, prepareByTime, and a list of order items that tell the restaurant to prepare. It doesn't care about consumers, payments, delivery, and other things that have nothing to do with it.

Figure 8. Domain model of Kitchen Service

Order Service has the most complex order view, as shown in figure 9. Even though it has quite a number of fields and methods, it is still much simpler than the original version of the Order God class.

Figure 9. Domain model of Order Service

The Order classes in each domain model represent different aspects of the same Order business entity. FTGO applications must maintain consistency between these different objects in different services. For example, once OrderService authorizes a consumer's credit card, it must trigger the creation of a Ticket in Kitchen Service. Similarly, if Kitchen Service rejects the order, it must be cancelled in Order Service and refunded to the customer. In Chapter 4, we will learn how to use the event-driven mechanism Saga mentioned earlier to maintain consistency between services.

In addition to some technical challenges, having multiple domain models can also affect the user experience. The application must transform between the user experience (that is, its own domain model) and the domain model of each service. For example, in a FTGO application, the Order status displayed to the consumer comes from Order information stored in multiple services. This transformation is usually handled by API Gateway and will be discussed in Chapter 8. Despite these challenges, the God class must be identified and eliminated when defining a microservice architecture.

Let's now look at how to define the service API.

6 define service API

So far, we have a list of system operations and a list of potential services. The next step is to define the API for each service: that is, the operations and events of the service. There are two reasons for service API operations: first, some operations correspond to system operations. They are invoked by external clients and possibly by other services. Again, there are other operations to support collaboration between services. These operations are invoked only by other services.

Services can collaborate with other services by publishing events to the outside world. Chapter 4 describes how to use events to implement Saga, which can maintain data consistency between services. Chapter 7 discusses how to use events to update CQRS views that support valid queries. Applications can also use events to notify external clients. For example, you can use WebSockets to pass events to the browser.

The starting point for defining a service API is to map each system operation to a service. It is then determined whether the service needs to collaborate with other services to achieve system operation. If collaboration is required, we will determine which API must be provided by other services to support collaboration. First, let's take a look at how to assign system operations to services.

Assign system operations to services

The first step is to determine which service is the initial entry point for the request. Many system operations can be clearly mapped to services, but sometimes the mapping is less obvious. For example, consider using the noteUpdatedLocation () operation to update the location of the delivery man. On the one hand, because it is related to the caterer, this operation should be assigned to the Courier Service. On the other hand, it is a DeliveryService that needs a delivery place. In this case, assigning an operation to a service that requires the information provided by the operation is a better choice. In other cases, it may make sense to assign an operation to a service that has the information it needs to process it. Table 4 shows which services in the FTGO application are responsible for which operations.

Table 4 system operations of FTGO applications are mapped to specific services

After assigning operations to services, the next step is to determine how services interact with each other as each system operation is processed.

Identify the API required to support service collaboration

Some system operations are handled entirely by a single service. For example, in a FTGO application, Consumer Service handles the createConsumer () operation completely independently. But other system operations span multiple services. The data required to process one of these requests may be scattered around multiple services. For example, in order to implement the createOrder () operation, Order Service must call the following service to verify its pre-condition and make the post-condition valid:

Consumer Service: verify that consumers can place orders and get their payment information.

Restaurant Service: verify the order line items, verify that the shipping address and time are in the service area of the restaurant, verify the minimum requirements of the order, and get the price of the order line items.

Kitchen Service: create a Ticket (post-cook order).

Accounting Service: an authorized consumer's credit card.

Similarly, in order to operate the acceptOrder () system, Kitchen Service must call Delivery Service to arrange for the delivery order to be delivered by the delivery man. Tables 2-3 show the service, revised API, and collaborators. To fully define the service API, you need to analyze each system operation and determine the required collaboration.

Table 5 Services, revised API and collaborators

Summary

Services in microservices are organized according to business needs, according to business capabilities or subdomains, rather than technical considerations.

There are two decomposition modes:

Decompose by business capability, which originates from the business architecture.

Based on the concept of domain-driven design, it is decomposed by sub-domain.

The God class, which causes interlaced dependencies that hinder decomposition, can be eliminated by applying DDD and defining a separate domain model for each service.

This article is extracted from "Micro Services Architecture Design pattern" and published under the authorization of the publisher.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report