In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly explains "what are the knowledge points of DDD event-driven and CQRS". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn what are the knowledge points of DDD event-driven and CQRS.
I. Preface: start with the details of logistics
Everyone is no stranger to logistics tracking, it records in detail when and what happened, and the data as important evidence is immutable. I understand that there are several aspects of the value behind it: the business side can control each sub-process and know where it is at present; on the other hand, when it needs to be traced back, the entire historical process can be played back only by recording each step.
So we can learn from the idea of logistics tracking to develop software projects and disassemble the complex process into steps, sub-processes and states, which is consistent with our event division, which is a typical case of event-driven.
II. Domain events
Domain event (Domain Events) is a concept in domain-driven design (Domain Driven Design,DDD) that captures what has happened in the domain we are modeling.
Domain events themselves become the language of communication for all project members, including domain experts, as part of the Common language (Ubiquitous Language).
For example, in the aforementioned example of cross-border logistics, after the goods arrive in the bonded warehouse, staff need to be assigned to sort and sort the packages, then "the goods have arrived in the bonded warehouse" is a domain event.
First of all, in terms of business logic, the event is related to the success or failure of the whole process; at the same time, it will trigger the subsequent sub-process; and for the business side, the event is also a landmark milestone. Goods on behalf of themselves are about to be delivered to their own hands.
So generally speaking, a domain event has the following characteristics: high business value, which helps to form a complete business closed loop, which will lead to further business operations. It is also emphasized here that domain events have clear boundaries.
For example, if you are modeling the checkout system of a restaurant, then "the customer has arrived" is not your concern, because you cannot ask for money as soon as the customer arrives. "the customer has placed an order" is a useful event for the checkout system.
1. Modeling domain events
When modeling domain events, we should name events and attributes according to the common language in the bounded context. If the event is generated by a command action on the aggregation, we usually name the domain event according to the name of the action method.
For the above example, "goods have arrived at the bonded warehouse", we will publish the corresponding domain event.
GoodsArrivedBondedWarehouseEvent (of course, in a well-defined context, you can also remove the name of the aggregation and model it directly as ArrivedBondedWarehouseEvent, which is a naming habit).
The name of the event indicates what happens after the command method on the aggregation executes successfully, in other words, pending items and uncertain states cannot be regarded as domain events.
An effective method is to draw the state flow diagram of the current business, including the pre-operation and the resulting state changes. Here, the status that has been changed is expressed, so we do not need to express it in the past tense, such as delete or cancel. It means that it has been deleted or cancelled.
Then event modeling is carried out for the nodes in it. The following figure shows the file cloud storage business. We model "past tense" events, such as PreUploadedEvent, ConfirmUploadedEvent, and RemovedEvent, for pre-upload, upload confirmation, deletion and other links.
2. Interpretation of domain event codes
When creating a domain event, you need to be aware of two points:
Domain events should be immutable (Immutable)
Domain events should carry contextual data information related to the occurrence of the event, but not the state data of the entire aggregation root. For example, when you create an order, you can carry the basic information of the order, while for the user to update the order receiving address event AddressUpdatedEvent event, you only need to include information such as the order, the user, and the new address.
Public class AddressUpdatedEvent extends DomainEvent {/ / verify the validity of the order through userId+orderId; private String userId; private String orderId; / / new address private Address address; / / omit specific business logic} 3. Storage of domain events
The immutability and traceability of events determine the principle that they must be persisted. Let's take a look at several common scenarios.
3.1separate EventStore
In some business scenarios, a separate event storage center may be created, such as Mysql, Redis, Mongo, or even file storage. Here we take Mysql as an example. Business_code and event_code are used to distinguish different events of different businesses. Specific naming rules can be based on actual needs.
We need to pay attention to the scenario where the data source is inconsistent with the business data source. We need to ensure that events can be accurately recorded when the business data is updated, and try to avoid using distributed transactions or cross-database scenarios as far as possible, otherwise you will have to figure out how to compensate. Be sure to avoid, the user updated the shipping address, but the AddressUpdatedEvent event failed to save.
The general principle is Say No for distributed transactions. In any case, I believe that there are always more methods than problems. In practice, we can always think of a solution. The difference lies in whether the solution is simple and decoupled.
# consider whether a split table is required. Event storage suggests simple CREATE TABLE `event_ store` (`event_ id` int (11) NOT NULL auto increment, `event_ code` varchar (32) NOT NULL, `event_ name` varchar (64) NOT NULL, `event_ body` varchar (4096) NOT NULL, `occurred_ on` datetime NOT NULL, `business_ code` varchar (128NOT NULL, UNIQUE KEY (`event id`)) ENGINE=InnoDB COMMENT 'event storage table'; 3.2 store with business data
In a distributed architecture, each module is relatively small, or "autonomous" to be exact. If the amount of current business data is small, events can be stored together with business data, and the relevant identification can be used to distinguish whether it is real business data or event records, or to establish the business's own event storage in the current business database. However, considering that the magnitude of event storage must be larger than the real business data, consider whether a sub-table is needed.
The advantages of this scheme are: data autonomy; avoiding distributed transactions; and no additional event storage centers are required. Of course, the disadvantage is that it can not be reused.
4. How domain events are issued 4.1 send domain events by domain aggregation / * * an example of a hyperemia model about competitions * anemia model constructs a MatchService, and here we use the model to trigger the corresponding events * in this case, specific business details are omitted * / public class Match {public void start () {/ / construct Event.... MatchEvent matchStartedEvent = new MatchStartedEvent (); / / omit specific business logic DefaultDomainEventBus.publish (matchStartedEvent);} public void finish () {/ / construct Event.... MatchEvent matchFinishedEvent = new MatchFinishedEvent (); / / omit specific business logic DefaultDomainEventBus.publish (matchFinishedEvent);} / omit basic properties of Match object} 4.2 event bus VS message middleware
Domain events in microservices can realize business collaboration between different aggregations through event bus or using application services. That is, when domain events occur in microservices, it is not necessary to introduce message middleware because most of the events are integrated in the same thread. However, if an event updates multiple aggregate data at the same time, according to DDD's principle of "one transaction only updates one aggregation root", we can consider introducing message middleware to adopt different transactions for different aggregation roots in the microservice through asynchronization.
3. Saga distributed transaction 1. Saga summary
Let's take a look at how to maintain data consistency using the Saga schema.
Saga is a mechanism to maintain data consistency in micro-service architecture, which can avoid the problems caused by distributed transactions.
A Saga represents one of several services that need to be updated, that is, a Saga consists of a series of local transactions. Each local transaction is responsible for updating the private database of its service, and these operations still rely on the familiar ACID transaction framework and function libraries.
Mode: Saga
Data consistency between multiple services is maintained by using asynchronous messages to coordinate a series of local transactions.
Saga has one less Try operation than TCC, and TCC needs to interact with the transaction participant twice regardless of the final success or failure of the transaction. On the other hand, Saga only needs to interact with the transaction participant once when the transaction is successful, and additional compensation rollback is needed if the transaction fails.
Each Saga consists of a series of sub-transaction Ti
Each Ti has a corresponding compensation action Ci, which is used to undo the results caused by Ti.
As you can see, compared to TCC, Saga does not have a "reserved" action, and its Ti is submitted directly to the library.
There are two orders in which Saga is executed:
Success:T1, T2, T3,..., Tn
Failure:T1, T2,..., Tj, Cj,..., C2, C1, where 0
< j < n; 所以我们可以看到Saga的撤销十分关键,可以说使用Saga的难点就在于如何设计你的回滚策略。2. Saga implementation
Through the above example, we have a preliminary sense of Saga, now let's explore how to achieve it. When Saga is started through a system command, the coordination logic must select and notify the first Saga participant to perform a local transaction. Once the transaction is completed, the Saga coordinates the selection and invocation of the next Saga participant.
This process continues until Saga completes all the steps. If any local transaction fails, the Saga must execute the compensating transaction in reverse order. The following different methods can be used to build the coordination logic of Saga.
2.1 Collaborative (choreography)
The decision-making and execution sequence logic of Saga is distributed among each participant in Saga, and they communicate by exchanging events.
(quoted in the relevant chapter of "Micro Service Architecture Design pattern")
The Order service creates an Order and publishes the OrderCreated event.
The Consumer service consumes the OrderCreated event, verifies that the consumer can place an order, and publishes the ConsumerVerified event.
The Kitchen service consumes OrderCreated events, validates orders, creates trouble tickets in CREATE_PENDING state, and publishes TicketCreated events.
The Accounting service consumes the OrderCreated event and creates a Credit CardAuthorization in the PENDING state.
The Accounting service consumes TicketCreated and ConsumerVerified events, charges consumers' credit cards, and publishes credit card authorization failures.
The Kitchen service uses the credit card authorization failure event and changes the status of the trouble ticket to REJECTED.
The order service consumes a credit card authorization failure event and changes the order status to rejected.
2.2 orchestration (orchestration)
Centralize Saga's decision-making and execution sequential logic into a Saga choreographer class. The Saga choreographer issues imperative messages to each Saga participant, instructing those party services to complete the specific operation (local transaction). Similar to a state machine, when the party service completes the operation, it sends a status instruction to the choreographer to decide what to do next.
(quoted in the relevant chapter of "Micro Service Architecture Design pattern")
Let's analyze the execution process.
Order Service first creates an Order and a create order controller. After that, the process of the path is as follows:
Saga orchestrator sends a Verify Consumer command to Consumer Service.
Consumer Service replies to the Consumer Verified message.
Saga orchestrator sends a Create Ticket command to Kitchen Service.
Kitchen Service replies to the Ticket Created message.
The Saga coordinator sends an authorization card message to the Accounting Service.
The Accounting service department replies with a card authorization message.
Saga orchestrator sends an Approve Ticket command to Kitchen Service.
Saga orchestrator sends an order approval command to the order service.
2.3 compensation strategy
In the previous description, we said that the most important thing about Saga is how to handle exceptions, and the state machine defines a lot of exception states. For example, 6 above will fail and trigger AuthorizeCardFailure, at which point we will close the order and roll back the previously committed transaction. It is necessary to distinguish which are verifiable transactions and which are transactions that need to be compensated.
A Saga consists of three different types of transactions: compensable transactions (which can be rolled back, so there is a compensating transaction); critical transactions (this is the key to the success or failure of the Saga, such as 4 account withholding); and repeatable transactions, which do not need to be rolled back and are guaranteed to be completed (such as 6 update status).
In Create Order Saga, the createOrder () and createTicket () steps are compensable transactions and have compensation transactions that undo their updates.
The verifyConsumerDetails () transaction is read-only, so there is no need to compensate the transaction. The authorizeCreditCard () transaction is a key transaction for this Saga. If the consumer's credit card is authorized, then the Saga is guaranteed to be completed. The approveTicket () and approveRestaurantOrder () steps are repeatable transactions after critical transactions.
It is particularly important to carefully disassemble each step and then evaluate its compensation strategy, and as you can see, each type of transaction plays a different role in the countermeasure.
IV. CQRS
After describing the concept of events and analyzing how Saga solves complex transactions, let's take a look at why CQRS is so widely adopted in DDD. In addition to the characteristics of read-write separation, the implementation of Command logic in an event-driven way can effectively reduce the complexity of the business.
When you understand how to model events, how to avoid complex transactions, when to use message middleware and when to use event bus, you can understand why it is CQRS and how to apply it correctly.
(the picture comes from the Internet)
The following is the design in our project. Why Read/Write Service appears here is to encapsulate the call. The internal service sends events based on aggregation. Because I find that in actual projects, many people will ask me for the XXXService instead of the XXX model in the first place, so in projects where DDD is not fully popularized, it is recommended that you adopt this centring strategy. This is also in line with our decoupling, which depends on my abstract capabilities, but whether I am internally based on DDD or traditional process code is irrelevant and transparent to it.
Let's first look at the timing of events and processors.
Here is the file cloud storage business as an example, the following is some of the core processor code. The comment line is an interpretation of the function, usage, and extension of the code, please read it carefully.
Package domain;import domain.event.DomainEvent;import domain.handler.event.DomainEventHandler;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * @ Description: event registration logic * @ Author: zhangwenbo * @ Since: 2019-3-6 * / public class DomainRegistry {private Map handlerMap = new HashMap (); private static DomainRegistry instance Private DomainRegistry () {} public static DomainRegistry getInstance () {if (instance = = null) {instance = new DomainRegistry ();} return instance;} public Map getHandlerMap () {return handlerMap;} public List find (String name) {if (name = = null) {return null;} return handlerMap.get (name) } / / event registration and maintenance, how many scenarios register is divided according to the business, / / this is the core of the business flow. If multiple events need to maintain front-and-back dependencies, / / you can maintain a priority logic public void register (Class
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.