In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article will explain in detail how to analyze the difference between micro-service architecture and SOA. The content of the article is of high quality, so the editor will share it with you for reference. I hope you will have some understanding of the relevant knowledge after reading this article.
The difference between micro-service architecture and SOA
Micro-services are hot now, but the popular comparisons in the industry are so-called Monolithic single applications, and a large number of systems were distributed systems more than a decade ago, so what is the difference between micro-services as a new concept and the original distributed systems, or SOA (Service-oriented Architecture)?
Let's first look at the similarities:
Registry is required to implement a dynamic service registration discovery mechanism
Distributed transaction consistency needs to be considered. Under the CAP principle, two-stage commit can not guarantee performance, and transaction compensation mechanism needs to be considered.
Synchronous invocation or asynchronous message delivery, how to ensure message reliability? SOA all messages are integrated by ESB
They all need a unified Gateway to aggregate and orchestrate interfaces, implement a unified authentication mechanism, and provide RESTful interfaces used by APP.
We should also pay attention to the problem of how to redistribute the location system and how to do log tracking, just like the signaling tracking function that we have done in the telecommunications field for more than ten years.
So what's the difference?
Continuous integration, continuous deployment? For CI and CD (continuous integration, continuous deployment), this itself is intertwined with Agile and DevOps, which I think is more inclined to the field of software engineering than to the micro-service technology itself.
Is it different to use different communication protocols? The benchmark communication protocol of micro-service is RESTful, while the traditional SOA is generally SOAP, but at present, there are many lightweight RPC frameworks such as Dubbo, Thrift and gRPC. In Spring Cloud, there is also the RPC-like behavior of Feign framework transforming standard RESTful into code API. These communication protocols should not be the core difference between micro-service architecture and SOA.
Is it a popular container-based framework or a virtual machine? Docker and virtual machine or physical machine are both a way of architecture implementation, not a core difference.
The essence of micro-service architecture is segmented.
There is a big difference in the segmentation of services. SOA originally appeared as an "integration" technology, and many technical solutions encapsulate the original internal services into an independent process, so that new business development can reuse these services, these services are likely to be very large particles such as supply chain and CRM; while micro services are "micro", it shows that he is fastidious and uncompromising in segmentation. Countless cases have proved that if your shredding is wrong, you will not get the advantages of "low coupling, no impact of upgrade, and high reliability" of micro-service commitment, but will have more trouble than using Monolithic.
Micro services without split storage are pseudo services: in practice, we often see an architecture in which back-end storage is all and in a database, only splitting the front-end business logic into different service processes, essentially the same as a Monolithic, only changing intra-process calls between modules into inter-process calls, this segmentation is not desirable, violates the first distributed principle, and module coupling is not solved. Performance has been affected.
The first principle of distributed design-"Don't distribute your objects"
The word "Micro" for microservices is not as small as possible, but we need smaller and more appropriate granularity than coarse-grained services like SOA, and this Micro is not infinitely small.
If we combine two (synchronous) communications with small / micro services, and according to the principle of "1 class = 1 service", we are actually going back to the 1990s using Corba, J2EE, and distributed objects. Unfortunately, the new generation of developers have no experience with distributed objects, so they don't realize how bad the idea is. They are trying to repeat history, only this time using new technologies, such as replacing RMI or IIOP with HTTP.
Microservices and Domain Driven Design
A simple library management system certainly does not need a micro-service architecture. Since the use of micro-service architecture, then the problem space must be relatively large, such as the entire e-commerce, CRM.
How to disassemble the service?
What method is used to disassemble the service? Methods such as 1 class = 1 service, 1 method = 1 service, 2 Pizza team, and 2-week rewriting are popular in the industry, but these methods lack the basis for implementation. We must find from some software design methods that the problem space applicable to object-oriented and design patterns is a module, and the concept of functional programming works more at the code level.
Eric Evans's "domain-driven design" is a great reference for micro-service architecture, which proposes a technology that can split a large problem space into relationships and behaviors between domains and entities. At present, this is the most reasonable solution to the split problem. Through the concept of Bounded Context (hereinafter referred to as BC), we can encapsulate the implementation details so that BC can implement the principle of SRP (single responsibility). Each micro-service is the physical mapping of BC in the real world, and the micro-services in line with the idea of BC are independent and loosely coupled with each other.
Micro-service architecture is a good thing, forcing people to pay attention to the rationality of design software. If domain analysis and object-oriented design are not done well in Monolithic, changing micro-services will magnify the problem exponentially.
Take the two areas of order and commodity in e-commerce, for example, according to DDD disassembly, they should be two independent bounded contexts, but the order must contain goods. If the order is hastily split into two BC, the relationship between query and invocation will be coupled, and there will even be troublesome distributed transactions. How to disassemble this relationship? BC theory holds that in different BC, even if it is a term, his focus is different. In commodity BC, he focuses on attributes, specifications, details, etc. (in fact, commodity BC has price, inventory, promotion, etc., and it is unreasonable to regard it as a separate BC. Here, in order to simplify the example, we first think that commodity BC is the basic information of goods.) In the order BC, we pay more attention to the inventory and price of goods. Therefore, in the actual coding design, the order service often redundancy the product name, price and other attributes in the order, this design frees from the strong relationship with the commodity BC, the two BC can provide services independently, independent data storage.
Summary
The first thing that micro-service architecture should pay attention to is not the concept of RPC/ServiceDiscovery/Circuit Breaker, nor the technical framework such as Eureka/Docker/SpringCloud/Zipkin, but the boundary of services and the division of responsibilities. if the division is wrong, it will fall into a large number of mutual calls and distributed transactions between services. In this case, micro-services bring not convenience but trouble.
DDD brings us a reasonable means of division, but the concepts of DDD are numerous and obscure, so how to grasp the key points and apply them reasonably to the micro-service architecture?
I think the following architectural ideas are the top priority.
Hyperemia model
Event driven
Microservice and hyperemia model
DDD such a complex theory, aggregation roots, value objects, event traceability, how do we start?
In fact, DDD and object-oriented design, design patterns and other theories are inextricably linked, if you are not familiar with OOA, OOD,DDD is not good to use. However, when learning these OO theories, we often feel useless, because most of the Java programmer's development career begins by learning J2EE's classic layering theory (Action, Service, Dao). In this layering theory, we have little opportunity to use those so-called "behavioral" design patterns. The core reason here is that the development of J2EE classic layering is a "anemia model".
In his book "Enterprise Application Architecture pattern", Martin Fowler proposes two development methods, "transaction script" and "domain model", which correspond to "anaemia model" and "hyperemia model" respectively.
Transaction script development mode
The core of the transaction script is the process. It can be considered that most of the business processing is a piece of SQL. The transaction script organizes a single SQL into a piece of business logic. When the logic is executed, the transaction is used to guarantee the logical ACID. The most typical is the stored procedure. Of course, in the usual J2EE classic hierarchical architecture, we often use transaction scripts in the Service layer.
Cdn1.b0.upaiyun.com/2017/08/a94f96eec2f1f7e2cff19dbcedff74ee.jpg ">
With this development approach, objects are only used to transfer data between layers, and the object here is the "anemia model", with only data fields and Get/Set methods, and no logic in the object.
Let's take an inventory deduction scenario as an example:
Business scenario
First of all, let's talk about the business scenario. An order is deducted from inventory (lock inventory). This is very simple.
First judge whether the inventory is sufficient, then deduct the salable inventory, increase the inventory occupied by the order, and then record a log of inventory changes (as vouchers).
Design of anemia model
First design an inventory table Stock with the following fields
Design a Stock object (omitted by Getter and Setter)
one
two
three
four
five
six
Public class Stock {
Private String spuId
Private String skuId
Private int stockNum
Private int orderStockNum
}
Service entrance
Design a StockService and write logic in the lock method in it
Input parameters are (spuId, skuId, num)
Implement pseudo code
one
two
three
four
five
six
seven
Count = select stocknum from stock where spuId=xx and skuid=xx
If count > num {
Update stock set stocknum=stocknum-num, orderstocknum=orderstocknum+num where skuId=xx and spuId=xx
} else {
/ / insufficient inventory, deduction failed
}
Insert stock_log set xx=xx, date= new Date ()
Ok, finish the work, if you do better, you can combine update and select count, so you can use a sentence to complete spin, solve the concurrency problem (master).
A brief summary:
Have you found that during the operation of placing an order deducting inventory, which is a very important core logic in this business area, the Stock object does not need to appear at all, it is all database operation SQL, and the so-called business logic is composed of multiple SQL. Stock is just a data object of CRUD, and there is no logic to speak of.
The "anemia model" defined by Martin Fowler is an anti-pattern, it is no problem to develop a simple small system in the way of transaction script, the business logic is complex, and the business logic and various states are scattered in a large number of functions. the cost of maintenance and extension rises all of a sudden, and the anemia model has no basis for implementing micro-services.
Although we use an object-oriented language such as Java to develop it, it is actually the same as a procedural language, so in many cases it will be better for people to use database stored procedures instead of Java to write logic. (ps: Spring boot is not a micro service)
Development pattern of domain model
Domain models encapsulate data and behaviors and map them to real-world business objects. Each category has a clear division of responsibilities, so that the logic is dispersed into the appropriate object. Such an object is the "hyperemia model".
In practice, we need to make clear the concept that the domain model is stateful and represents an actual thing. Continuing with the example above, we need to design a Stock object that represents the actual inventory of an item and adds a method of business logic to it.
When doing the single-lock inventory business logic, you must first restore the Inventory object from Repository according to the primary key load, then execute the corresponding lock (num) method to change the state of the Inventory object (property is also a kind of state), and then persist the object to storage through the save method of Repository.
What completes the above series of operations is that Application,Application provides an interface for this kind of integrated operation.
The most important thing in the domain model development method is to put the details of the state changes caused by deductions into the Inventory object execution, which is the encapsulation of business logic.
The lock method of the Application object can be compared with the lock of the transaction script method StockService. StockService fully grasps all the details, and once there is a change (for example, the inventory is 0 can also be deducted), the Service method will change accordingly; while the Application method does not need to be changed, as long as it is calculated inside the Inventory object. The code is in the right place, the calculation is at the right level, and everything makes sense. This design can make full use of various theories of OOD and OOP to realize the business logic beautifully.
Shortcomings of hyperemia model
From the above example, it takes some time to load in Repository to execute business methods, and then to save, but if multiple threads request locks on Inventory inventory at the same time, it will lead to state inconsistency. The trouble is that concurrency for inventory is not only difficult to handle but also common.
The anemia model depends entirely on the database support for concurrency, and the implementation can be simplified a lot, but the hyperemia model has to be implemented on its own. Whether by locking the object in memory or using the remote locking mechanism of Redis, it is more complex and less reliable than the anemia model, which is the challenge brought by the hyperemia model. A better approach is to eliminate concurrency through an event-driven architecture.
The relationship between domain model and micro-service
The implementation of the domain model is mentioned above, but what is the relationship between it and microservices? In practice, this Inventory is an aggregation root of a bounded context, and we can think of an aggregation root as a microservice process.
However, the problem arises again. An Inventory in inventory must be related to commodity information. It is not enough to rely on the redundancy of commodity ID in Inventory. The status of goods on and off the shelves, and so on, is required by business logic. Does it not introduce heavy objects such as commodity Sku into this micro-service? Two heavy objects in one service? Such micro-services can not be separated, or must we rely on commodity repositories?
To recommend a programmer learning exchange group: 878249276, there are shared videos, interview guides, architectural materials, as well as mind maps, group announcements and videos, all of which are practical information, which you can download. Mainly share distributed architecture, high scalability, high performance, high concurrency, performance optimization, Spring boot, Redis, ActiveMQ, Nginx, Mycat, Netty, Jvm large-scale distributed project practical learning architect video. Make good use of every minute of your time to learn to improve yourself, and stop using "no time" to hide your mental laziness! Work hard while you are young and give your future self an account!
Event-driven architecture
We adopted the domain-driven development approach, used the hyperemia model, and enjoyed his benefits, but also had to face his disadvantages. This drawback is magnified under the distributed micro-service architecture.
Transaction consistency
Transaction consistency is not a big problem under Monolithic, but it is fatal under microservices. Let's review the so-called ACID principle.
Atomicity-atomicity, changing the state of data is either done together or fails together
Consistency-consistent, the state of the data is completely consistent
Isolation-isolation line that does not affect each other even if there are concurrent transactions
Durability-persistence, irrevocable once the transaction is committed
In single services and relational databases, it is easy to complete ACID through the characteristics of the database. But once you split the aggregation root-microservice architecture according to DDD, their databases have been separated, and you have to face distributed transactions independently and satisfy ACID in your own code.
For distributed transactions, you will generally think of the previous JTA standard, 2PC two-stage commit. I remember that almost every week in the Dubbo group, people asked Dubbo when to support distributed transactions. In fact, according to the CAP principle in distributed systems, when P (partition tolerance) occurs, the forced pursuit of C (consistency) will lead to the decline of (A) availability and throughput. At this time, we generally use the final consistency to ensure the AP capability of our system. Of course, it doesn't mean to give up C, but in general, CAP can guarantee that in the case of partitioning, we can ensure data consistency through ultimate consistency.
Example:
In the e-commerce business to place orders to freeze inventory scenarios. It is necessary to determine whether the order is closed according to the inventory situation.
Suppose you have adopted a distributed system, where the order module and inventory module are two services, each with its own storage (relational database).
In a database, two tables can be modified by one transaction, but not in microservices.
In the concept of DDD, a transaction can only change the state within one aggregation, and if state consistency is required between multiple aggregations, then the final consistency must be adopted. Orders and inventory are obviously aggregates that belong to two different bounded contexts, and event-driven architecture is needed to achieve ultimate consistency.
Event-driven to achieve ultimate consistency
The event-driven architecture synchronizes the state between domain objects through asynchronous messages, and some messages can be published to multiple services at the same time. After the message causes the synchronization of one service, it may cause another message, and the event will spread. Strictly speaking, event-driven is not called synchronously.
Example:
After a new order is added to the order service, the status of the order is "opened" and an Order Created event is issued to the message queue
After receiving the Order Created event, the inventory service subtracts the salable inventory from a sku in the inventory table, increases the inventory occupied by the order, and then sends an Inventory Locked event to the message queue
The order service received an Inventory Locked event and changed the status of the order to "confirmed"
Some people ask, what if the inventory is insufficient and the lock is not successful? Simply, the inventory service sends a Lock Fail event, and after the order service receives it, it sets the order to "cancelled".
Good news, we don't have to lock it! A big advantage of event drivers is that concurrency is eliminated, and all requests are queued in, which is very helpful for us to implement the hyperemia model, so we don't have to manage locks in memory ourselves. Unlocking, queue processing is very efficient, and event-driven can be used in high concurrency scenarios, such as panic buying.
Yes, the user experience has changed. With this event driver, the user experience may change. For example, when there is no inventory in the original synchronization architecture, you will immediately tell you that the order cannot be issued if the conditions are not met, and the order will not be generated; however, if the event mechanism is changed, the order is generated immediately, and it is likely that the system will inform you that the order has been cancelled after a while. Just like snapping up "Xiaomi mobile phone", hundreds of thousands of people are waiting in line to tell you that they are out of stock for a long time. Come back tomorrow. If you want users to get immediate results, you can find a way at the front end and use locks such as CountDownLatch in BFF (Backend For Frontend) to convert back-end async to front-end synchronization, which of course consumes a lot of BFF.
No way, the product manager does not accept, the product manager said that the user's experience must be no inventory will not generate orders, this program will continue to generate cancelled orders, he can not accept, what to do? When querying the list of orders, skip these orders with cancel status, and may need an extra view to do so. I am not an idealist. Solving the current problem is my first consideration. We designed the microservice to solve the business concurrency. What we are facing now is the problem of user experience, so architecture design also needs to be compromised: (but at least after the analysis, I know where my compromise is, why I compromise, and it is possible to change in the future.
Multi-domain multi-table Join query
I personally think that the aggregation root mode is particularly suitable for modifying the status, but it is indeed inconvenient for searching data. For example, the aggregate root object itself cannot undertake batch query tasks for the requirement of screening a batch of eligible orders, because it is not his duty. Then you have to rely on facilities like "domain services" (Domain Service).
When a method is inconvenient to be placed on an entity or value object, using domain services is the best solution. Make sure that domain services are stateless.
Our query tasks are often very complex, such as querying the list of goods, sorting according to last month's sales, sorting according to the return rate of goods, and so on. However, after micro-service and DDD, our storage model has been detached, and the above queries are all related to the data of orders, users and goods. How to do it? At this point we are going to introduce the concept of a view. For example, the operation of querying an order under the user's name and directly calling the two services themselves in memory join efficiency is undoubtedly very low, coupled with some filter conditions, paging, can not be done. So we broadcast the events, receive them by a separate view service, and form a materialized view (materialized view). The data has been join, processed, and placed in a separate query library, waiting for a query, which is a typical space-for-time processing.
After analysis, in addition to simple Find according to the primary key or not too many associated List queries, most of our query tasks can be placed in a separate query library, which can be a relational database ReadOnly library or a NoSQL database. In fact, we use ElasticSearch as a special query view in the project, and the effect is very good.
Bounded context (Bounded Context) and data coupling
In addition to the problem of multi-domain join, we often encounter some scenarios in our business, such as the commodity information in e-commerce is basic information and belongs to a separate BC, while other BC, whether it is marketing service, price service, shopping cart service, order service, all need to refer to this commodity information. But the commodity information needed is only a small part of the total. Marketing services require the id and name of the goods, the status of the goods on and off the shelves, and the order service requires the goods id, name, catalogue, price, and so on. This is only a small subset compared to the commodity center defining a commodity (commodity id, name, specification, specification value, details, etc.). This indicates the same term in different bounded contexts, but refers to different concepts. This kind of problem is mapped to our implementation, and it is definitely not appropriate to query the commodity module directly in the order and marketing module every time, because
The commodity center needs to adapt the data needed by each service and provide different interfaces.
The concurrency must be very large.
The coupling between services is serious, once the downtime, the impact of upgrade is very large.
In particular, the last one seriously limits the advantages we can get from microservices: "loosely coupled, each service can be upgraded frequently without affecting other modules." This requires us to use the event-driven method to appropriately redundant some data to different BC to disassemble this coupling. This coupling is sometimes embedded into the entity through Value Object, which is redundant when the entity is generated, for example, when the order is generated, the product information is redundant; sometimes through the additional Value Object list, the marketing center redundancy part of the relevant product list data, and pay attention to monitor the superior and subordinate status of the goods at any time, synchronously replace the product list in this limit context.
The following figure shows the analysis of an order issuing scenario. In the e-commerce system, we can think that members and commodities are the basic data of all businesses, and their changes should be released to various fields by broadcast. Each domain retains the information it needs.
Ensure final consistency
The success of ultimate consistency depends on many conditions.
Depending on the reliability of message delivery, system A may have changed its state, and the message was lost when it was sent to system B, resulting in inconsistent state of AB.
Depending on the reliability of the service, if system A changes its state, but dies before it can send a message. It can also lead to state inconsistency.
I remember that JMS in the JavaEE specification has requirements for dealing with these two problems, one is that JMS uses a variety of confirmation messages (Client Acknowledge, etc.) to ensure the reliability of message delivery, and the other is that the message delivery operation of JMS can be added to the transaction of the database-that is, no message is sent, which will cause a rollback of the database (no information, not a very accurate description, please experts correct). However, there are few MQ conforming to the JMS specification, especially the need to reduce performance to maintain consistency. Now MQ, which boasts high throughput, has left the problem to our own applications. So here are several common ways to improve the effect of final consistency.
Use local transactions
Or an example of withholding credit with the above order.
The order service starts the local transaction. Add the order first.
Then insert the Order Created event into a dedicated Event table, and the transaction commits
There is a separate scheduled task thread that scans the Event table periodically, throws to MQ what it needs to send, and sets the Event to "sent".
The advantage of the solution is that the transaction of the local database is used, and if the Event is not inserted successfully, the order will not be created; the thread scans and sets the event to be sent, which ensures that the message will not be missed (our goal is to resend rather than miss, because the Event processing will be designed to be idempotent).
The disadvantage is that you need to deal with Event separately and publish it in the business logic, which is tedious and easy to forget; the sending of Event lags behind; the performance of timing scanning consumes a lot, and it will cause the hidden danger of high water level in the database.
With a little improvement, we can use the database-specific MySQL Binlog trace (Ali's Canal) or Oracle's GoldenGate technology to get the change notification of the database's Event table, so that we can avoid scanning through scheduled tasks.
However, the tools that use these database logs will be bound to a specific database implementation (or even a specific version), so be careful when making decisions.
Trace the source of events using Event Sourcing
Event traceability is a special idea for us, he does not persist the Entity object, but only records the initial state and the Event of each change, and restores the latest state of the Entity object in memory according to Event, which is very similar to the implementation of database Redolog, but he puts this mechanism into the application layer.
Although there are many claimed advantages of event traceability, special care should be taken to introduce this technology. First of all, it may not be suitable for most business scenarios. Once it changes a lot, efficiency is indeed a big problem; other query problems are also troubling.
On how to analyze the difference between micro-service architecture and SOA to share here, I hope that the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.
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.