preface
With the development of architecture design, microservice architecture can be said to be a hot design concept in the architecture field. In the company, the author has been in charge of the service design and development of the system.
Today, let’s talk about some problems in the practice of micro-service landing. Hope to micro service design do not know how to start friends, play some reference role; In addition, I also hope to share my views and look forward to communicating with everyone to realize my shortcomings.
1. Service separation
The first question we encountered before launching microservices was: How should we split the services?
As you know, there is no universal rule on how to split services. However, there are several elements that we can refer to.
1. Business independence
Normally, that’s the first thing we think about. Business modules in the system are identified according to their responsibilities, and each individual module is divided into an independent service.
After this split, our services meet one principle: high cohesion, low coupling.
For example, we split a system into goods service, order service and logistics service. In general, when we modify logistics services, goods and services will not be affected, which is the embodiment of low coupling; Then the order service functions and logic are all around the order this core business process, it can be said that it is highly cohesive.
2. Business stability
We can classify the services in the system according to stability. For example, as for user registration and login, as long as the code of this part is written, there will be no change basically in our system, so I will split them into user services.
Similarly, there are log services and monitoring services. These modules are basically very stable services and can be separated separately.
3. Service reliability
What is important here is to separate core services with high reliability requirements from non-core services with low reliability requirements, and then focus on ensuring high availability of core services.
Prevent core services from being affected by non-core service failures.
4. Service performance
Based on service performance splitting, the consideration is to split out the modules with high performance pressure. I have two thoughts on this:
- Avoid performance – stressed services affecting other services.
- The high flow of business out of the independent, can not carry the case, convenient horizontal expansion.
For example, in one system I worked with, RocketMQ was used to connect large amounts of data from multiple vendors.
At that time, a separate messaging service was created to consume messages. Then some are processed locally, some are forwarded to other services for processing through RPC interface, and some are directly pushed to the front end for display through WebSocket.
In that case, even if traffic surges, consider adding machines to your messaging service to increase consumption power.
With these methods in mind, we can consider the service separation of our system based on the scope of our business and the size of our technical team.
5. Too much of a good thing
Here, however, it is particularly noteworthy that microservices should not be broken down too finely, but must combine the size of the business and the size of the technical team.
The author once came across a project. In the process of servitization, the technical director at that time separated the services according to the business independence, resulting in the separation of about 10 services. To make matters worse, each business Service separates the Service layer from the Controller layer, and each business method needs to be called remotely. According to the description of the parties, this is to facilitate the later expansion capacity.
But to tell the truth, some system business volume is not so big, blindly cater to the micro word in the micro service, is undoubtedly to increase their difficulty, destroy the stability of the overall system. Therefore, after reorganizing the business process, the author reconstructs the system to reduce the number of services.
Here, the author wants to explain a point. The Service layer and the Controller layer can be split into multiple modules, which is fine. However, it should only be a separation of modules, not a separation of services. For example, we can split them into modules during development and then aggregate them together through Maven Modules, and they are all a service during deployment.
Two, technology selection
Once the service is split, which framework should be used for development, Dubbo or SpringCloud?
The author does not want to discuss their merits and demerits purely, here can share the author’s heart course with this question.
1, SpringCloud
For the initial selection, I chose SpringCloud because it claims to be a one-stop solution for microservices. Then I built a framework, integrated various components, and completed some demo development and testing.
However, after this part of the work is done, you can look at the whole system again and see the Eureka, Ribbon, Feign, Hystrix, Zuul, Config components involved in SpringCloud.
At this point, I have two questions:
- Do these components have to be used? Is there a more portable system solution?
- So many things, any link problems, we can hold?
The author has two understandings of the term one-stop. First, it simplifies the development of distributed system infrastructure and is easy to develop. Second, while simplifying, it must be shielded from complex configuration and implementation principles, making it difficult to understand its principles in depth.
As architects or team technical leaders, we must have a thorough understanding of the technical points involved in our systems, or at the very least, how they work. In this way, even if you encounter a problem, you won’t panic if Baidu/Google doesn’t get a result.
2, Dubbo
Based on this idea, the author turned his attention to Dubbo. For me, Dubbo is familiar with the framework itself, which has implemented load balancing and cluster fault tolerance, as well as interface-based invocation. Compared to SpringCloud, there is no need to introduce additional components like the Ribbon/Feign.
Also, Dubbo benefits from a powerful SPI mechanism that can be easily extended. It can be extended in many places if the business needs it, such as RPC protocol, clusters, registries, serialization methods, thread pools, and so on.
However, Dubbo is only a high-performance RPC framework, and it is more restful and RPC than SpringCloud. At this point, however, this performance difference is not enough to make a final decision, at most it is icing on the cake.
3, safe priority
As for the other components, such as Hystrix Zuul/Config/zipkin etc, the author’s point of view, or the business scale. Microservices are a design idea, an architecture idea, not a distributed framework. These frameworks were created only to solve the problems encountered by microservices.
You need to know that one bite does not make a fat man. When choosing the technology, remember to directly mark the experience of large factories like Ali, JINGdong and Meituan. On the one hand, we may not meet such business scenarios; Moreover, the average company does not have the same talent pool as others. After all, if something goes wrong online, you don’t have anyone to share the loss with.
In general, or combined with their own actual situation, with the most reliable technical solutions to complete the needs of the business.
Third, complications
Split the service, also complete the selection of technical solution, then all is well, start coding? If you’re just a developer, you really need to masturbate. If you’re the person in charge of a system, and you’re just satisfied with the big picture and don’t think about the details, it’s bound to lead to complications.
Timeouts and fault tolerance
After servitization, calls between different services are called remote calls. The most basic setting for remote calls is the timeout period.
For example, in Dubbo, the default timeout is 1 second. We can’t just use the default value or set it to a different value. It’s best to set the timeout for Dubbo to be specific.
For example, simpler services can be set shorter; But for complex business, this time needs to be extended appropriately. There is also a cluster fault tolerance issue involved.
In Dubbo, the default cluster fault tolerance policy is failure retries with a count of 2. If some business itself takes a long time to execute, too short a timeout will trigger a fault tolerance mechanism to retry. A large number of concurrent retry requests could potentially fill Dubbo’s thread pool and even affect the back-end database system, causing connections to be exhausted.
2. Fault tolerance and idempotency
As we mentioned above, if the timeout is set too short, it is possible that a large number of requests will be retried, resulting in exceptions.
There is another detail that is hidden here, namely read and write requests. If it is a read request, retry does not matter; If it is a write request, does our interface also support automatic retry? This is where interface idempotency comes in.
If the interface for writing requests does not support idempotence, then cluster fault tolerance must be failfast.
3. Distributed transactions
I feel that distributed transactions are a technical problem in the industry that has not been completely solved. There is no one-size-fits-all solution, and there is no efficient and easy way to do it.
That being said, we need to consider this in advance, otherwise the data is bound to be messy.
Before considering a solution, we need to see if our system is truly committed to consistency; According to the BASE theory, in a distributed system, different nodes are allowed to have a delay in the synchronization process, but the final consistency of data can be achieved after a period of repair.
Based on these two ideas, we can develop our own distributed transaction scheme.
For scenarios that require strong consistency, you might consider the XA protocol, with two-phase commit or three-phase commit.
For scenarios that require ultimate consistency, consider using the TCC pattern, compensation pattern, or message queue-based pattern.
RocketMQ, for example, is based on the message queue pattern. It supports transactional messages, so the process looks something like this:
- through
RocketMQ
Send transaction messages to message queues; - If the message is successfully sent, the local transaction is executed.
- If the local transaction executes successfully, commit
RocketMQ
Transaction messages, visible to consumers after submission; - If the local transaction fails, it is deleted
RocketMQ
Transaction message, which the consumer will not see.
In addition, here is Ali open source Seata. The latest version is 1.1.0 and supports multiple transaction modes, such as AT, TCC, SAGA, and XA transaction modes.
I have an article based on Seata 0.7 version written, interested friends can understand.
SpringBoot+Dubbo+Seata distributed transaction combat
4. Message queues
In distributed system architectures, message queues are a great tool for decoupling and asynchronous processing between systems, dealing with high concurrency and heavy traffic.
Before using this tool, we also need to consider the potential annoyance caused by message queues.
The first thing to consider is availability. If message queues are not available, will they cause a lot of unavailability to the system itself?
Then, will the message be lost? How to ensure reliable transmission of messages? For example, consider the flush mechanism and synchronization mechanism of the message queue itself; Confirmation of data delivery and submission after consumption;
Then is repeated consumption, if the message will not be lost, more or less may have the problem of repeated messages, at this time we should consider whether there is a problem with repeated consumption, that is, message idempotency;
Also, message ordering, is there a message ordering problem in your business scenario, and if there is a message ordering problem, either design to avoid it, or consume it in order.
5. Unified log
As microservices are unbundled, the logging system may evolve into separate modules. To view the logs, we may need to log in to different servers to view them one by one.
Therefore, it is necessary to build a unified log processing platform. We can use ELK’s solution for log aggregation.
Here, there is also the issue of link tracing. In complex chain calls to microservices, problems can be harder to locate and track than in single applications.
For this problem, we consider introducing a distributed call chain, generating a globally unique TraceID, through which the entire call chain is concatenated. Combined with the Dubbo framework, we implemented our own Filter to pass through the TraceID.
Specific ideas can be referred to: SpringBoot+Dubbo integrated ELK combat
Of course, we can also choose some mature open source framework to solve.
conclusion
This article briefly summarizes some of the issues that may be involved in the design and development of microservices.
The above point of view is just a statement, just the author in the past time experience summary.
If it is helpful to you, please like to encourage ~ if you have different views, please actively speak, common communication ~