This article is the sixth of a series of courses on "Internet high concurrency MicroServices architecture practice"
The first five articles are:
The cornerstone of micro-service-Continuous integration
Access layer design of micro-service and isolation of static and dynamic resources
Database design and read-write separation of microservices
The non-state and containerized of micro-service
Design of micro-service cache
first, the premise of service splitting
When it comes to microservices, service splitting is not a matter of the past, but microservices are not about dismantling, there are many prerequisites, and we need to complete the sections discussed in the previous sections.
First of all, there is a continuous integration of the platform, so that the service in the process of splitting, the consistency of the function, this consistency can not be through human experience, but need to undergo a large number of regression test set, and continuous splitting, continuous evolution, continuous integration, so as to ensure that the system at the moment can be verified delivery status, Instead of closed-door split for a period of time, ultimately, no one knows whether the function eventually has a bug, so it takes another one months to specifically modify the bug.
Second, in the Access layer, API and UI to the static separation, API by the API Gateway Unified management, so that the back end in any case, can be guaranteed for the front end, unified access, and can achieve the split process of gray-scale publishing, routing distribution, traffic segmentation, so as to ensure smooth split. and split the micro-service between, for high-performance, is not recommended every call to authenticate authentication, but in the API gateway to do a unified authentication, once into the gateways, the call between the services is credible.
Three for the database, need to do a good design, should not have a large number of joint queries, but the database as a simple key-value query, complex joint queries through the application layer, or through the elasticsearch. If the coupling between the database tables is very serious, in fact, the service split is not broken out.
Its four to do the application of the stateless, only the application of stateless, in order to scale horizontally, so that the split has meaning.
Second, the timing of service splitting
After satisfying the premise of service splitting, which module to remove first, then which module? Under what circumstances should a module be split?
Micro-service splitting is not a great leap forward movement, initiated by the high-level, the pieces of an application split, eventually greatly increase the operation and maintenance costs, but will not bring revenue.
Micro-service splitting process, should be a pain point driven, is the business really encountered a rapid iteration and high concurrency problem, if not split, will affect the development of the business, only this time, the micro-service split is a definite benefit, the increase in operation and maintenance costs is worthwhile.
One of the problems that microservices solve is the fast iteration.
The characteristics of Internet products is the rapid iteration speed, general 1.5 can be decided the outcome, the first eminence, the second was the first acquisition, the other dead upturned. So fast online, fast iteration, is the lifeline, and once success is billions of dollars, so no matter how much operation and maintenance costs, the use of micro-service architecture is worthwhile.
This is why most of the micro-service architectures are internet companies because of the obvious benefits for these companies. And for many traditional applications, half-yearly update, enterprise operations relatively smooth, it system of good or bad for the business has no critical impact, in their eyes, the effect of micro-service transformation, rather than the development of more than a few classes.
Micro-service split time: Commit code frequently has a large number of conflicts
MicroServices for the effect of fast iteration, the first is to develop independent, if it is a single application, hundreds of people develop a module, if you use Git to do code management, then often encountered is the code submission conflict.
Same module, you also change, he also changed, hundreds of people have no way to communicate. So when you want to submit a code, found and others submitted conflict, so because you are submitted after the person, you have the responsibility to merge code, finally merge successful, and so on again, when the discovery conflict, you are not very annoyed. The greater the team size, the greater the probability of conflict.
So should be split into different modules, every 10 people around the maintenance of a module, that is, a project, the first code conflict probability is much smaller, and there is a conflict, a group roar, basically solve the problem.
Each module provides external interface, other dependent modules can not focus on the specific implementation details, only need to ensure that the interface is correct.
Micro-service split time two: small function to accumulate to large version to go online, on-line Director Level Conference
The effect of microservices for fast iterations is first of all on-line independence. Without splitting microservices, it's a pain to go live every time. When you modify a corner of the small function, but you do not dare to go online, because you rely on the other modules to develop half, you have to wait for him, and so he is not afraid to go online immediately, because another dependent module also developed half, when all the modules are coupled together, interdependent, no one can be independent on-line, But need the director to coordinate the various teams, we open the meeting, agreed a time point, regardless of the size of the function, dead and alive to this day on the line.
This mode leads to on-line, a single-line demand list is very long, so the risk is relatively large, may be small function of the error will lead to a large function of the line is not normal, will be so long function, need a little check, very careful, so that the line time long, the impact of a large range. So this iteration speed is not fast, at most one months at the time is good.
After the service has been split, the different modules can be launched independently in the case of stable interfaces. This increase in the number of online, a single-line demand list is smaller, can be rolled back at any time, the risk of smaller, shorter time, the impact of small, resulting in faster iteration.
For the interface to upgrade the part, to ensure that the gray level, the first interface is added, instead of the original interface changes, when the registration center to monitor the call situation, found that the interface has not been used, and then deleted.
The second problem that microservices solve is high concurrency.
The characteristics of the Internet a product is to accumulate a large number of users in the short term, which is even more important than revenue and profit, if there is not a large number of user base, financing will be problematic.
Therefore, for a system with little concurrency, the driving force of microservices is poor, if only a small number of users online, multi-threaded can solve the problem, at most do not state, the front deployment of load balancing, single application deployment of multiple copies.
MicroServices Split Opportunity Three: scale-out process complexity, major business and secondary business coupling
Once the monomer application is stateless, it can carry a certain amount of concurrency by deploying multiple copies, but the resources are wasted. Because some businesses need to expand, such as orders and payment, some businesses do not need to expand, such as registration. If you are expanding together, the resources consumed may be several times after splitting, and the cost may be a few billion more. And because of the complex configuration, in the same project, often in the configuration file is organized, this piece is the module, the next piece is another module, such as the expansion of the time, some corner of the business, but also need to be detailed configuration of the audit, otherwise dare not rashly expansion.
Micro-service split time four: The blow down all rely on if-else
In high concurrency scenarios, we want a request to fail if it is unsuccessful, not to consume resources, should be unsuccessful as soon as possible, and hopefully, when some corner of the business is not normal, the main business process will not be affected. This requires a fuse strategy, that is, when a call B, and B is always abnormal, in order to let B do not ripple to a, can be a call to B to fuse, that is, a does not call B, but return to the temporary fallback data, when B normal, then release the fuse, make a normal call.
Sometimes in order to ensure the core business process, corner of the business process, such as comments, inventory number, etc., manually set to a degraded state, which is not called by default, all resources for the big promotion of the order and payment process.
If the core business process and the corner business process in the same process, it is necessary to use a large number of if-else statements, according to the distribution of the configuration to determine whether to fuse or downgrade, which makes the configuration is very complex, difficult to maintain.
If the core business and the corner business are divided into two processes, you can use the standard fuse downgrade policy, configure in some cases, discard the call to another process, can be unified maintenance.
Third, the method of service splitting
Well, when you think you want to split a part of a program, is there a way to ensure that it's smooth?
The first thing to do is to standardize the original engineering code, which we often call "anyone who takes over any module can see a familiar face"
For example, to open a Java project, you should have the following package:
API Interface Package: All the interface definitions are here, for internal calls, but also to implement the interface, so that once you want to split out, for local interface calls, you can become a remote interface call
Access to external service packs: If this process is to access other processes, the encapsulation of external access is here, and for unit testing, this part of the mock can make functional testing without relying on third parties. For service splitting, calling other services is also here.
Database DTO: If you want to access the database, define the atomic data structure here
Accessing a database package: The logic to access the database is all in this package.
Service and business logic: This is where the main business logic is realized, and the split is split from here.
External services: The logic of providing services externally here, for the provider of the interface, to be implemented here.
In addition, the test folder, each class should have unit testing, to audit unit test coverage, the module should be a mock method to implement integration testing.
Next is the configuration folder, configuration profile, the configuration is divided into several categories:
Internal configuration items (unchanged after startup, change requires restart)
Centralized configuration (configuration center, can be issued dynamically)
External configuration items (external dependencies, and environment-related)
When the structure of a project is very standardized, then in the original service, the first independent function module, the specification of input and output, forming a separation of service internal. Before separating out the new process, the new jar is separated, and as long as the new jar can be separated, the basic is loosely coupled.
Next, you should create a new project, start a process, early registration to the registry, start to provide services, this time, the new project code logic can not first, just go to call the original process interface.
Why do you have to be independent as soon as possible? Even if you haven't realized the logic to be independent first? Because the process of service splitting is gradual, with the development of new features, the introduction of new requirements, this time, for the original interface, there will be new requirements to modify, if you want to separate the business logic, independent of the half, the new needs to come, change the old, the new is not appropriate, the new has not provided independent services, If the old changes, it will result in the migration from the old project to the new project, side migration side change, merging more difficult. If the early independence, all the new requirements into the new project, all the callers update the time to call the new process, the old process of the call will be less and more, the end of the new process will be the old process all proxy.
You can then move the logic from the old project to the new project gradually, because the code migration does not guarantee that the logic is completely correct, so it needs continuous integration, grayscale publishing, and the MicroServices framework can switch between the new and the old interfaces.
Finally, when the new project is stable, and in the call monitoring, there is no call for the old project, you can put the old project offline.
IV. specification of service splitting
After the micro-service split, the project will be much more, if not a certain specification, will be very chaotic, difficult to maintain.
The first thing people often ask is that after the service is split, the original function call in a process has now become a call B call C call D call E, will it be because the call chain goes by long and makes the corresponding slow?
Specification for service splitting one: Service split up to three layers, two calls
Service splitting is for scale-out and should therefore be split horizontally instead of vertically. That is, the goods and orders should be split, rather than the order of 10 steps to split, and then one call one.
Vertical split up to three layers:
Basic service layer: Used to shield the database, the cache layer, to provide the Atomic object query interface, there is this layer, in order to make certain changes in the data layer, such as sub-database tables, databases, cache replacement, and so on, for the upper layer transparent, the upper level only call the interface, not directly access the database and cache.
Composite Service layer: This layer calls the basic service layer, completes the more complex business logic, realizes the distributed transaction also many at this layer
Controller layer: Interface layer, call the composite service layer to external
Specification of service splitting: one-way invocation only, no cyclic call is allowed
MicroServices split, the dependency between the service complex, if the loop call, the upgrade is a headache, do not know which should be upgraded first, after upgrade which, difficult to maintain.
Thus the calls between levels are defined as follows:
The underlying service layer is primarily a database operation and some simple business logic that does not allow any other services to be invoked.
Composite service layer, can invoke the underlying service layer, complete complex business logic, can invoke the composite service layer, not allow circular calls, not allowed to invoke the Controller layer service
Controller layer, which can invoke the composite business layer service and not be allowed to be called by other services
If a cyclic call occurs, such as a call to B,b also calls a, it is divided into the controller layer and the composite service Layer two, a calls the lower level of B, and b calls the lower layer of a. You can also use Message Queuing to invoke synchronous calls instead of asynchronously.
Specification for service splitting three: Changing a serial call to a parallel call, or asynchronously
If you have a combination service processing process that is really long and calls for multiple external services, you should consider how to implement asynchronous decoupling through Message Queuing.
For example, after the order, to refresh the cache, to notify the warehouse, and so on, these do not need to order a successful time to finish, but can send a message to the message queue, asynchronous notification of other services.
And the advantage of using Message Queuing is that you just send a message, whether the downstream relying party has one, or there are 10, is a message to be done, but a few more downstream listening messages.
For orders that must be done at the same time, such as deduction of inventory and coupons, can be called in parallel, so processing time will be greatly shortened, not the sum of times of multiple calls, but the longest system call time.
Specification for service splitting four: interfaces should be idempotent
After the microservices are split, the call between services will be retried when there is an error, but in order not to make two orders, pay two times, all the interfaces should be idempotent.
Idempotent generally needs to design a idempotent table to be implemented, the primary key or unique key in the Idempotent table can be a transaction ID, or a business ID, which can be identified by the uniqueness of this ID as a unique operation.
There are idempotent operations using state machines, when a call arrives, often triggering a state change, when the next call arrives, the discovery is not the state, it means that the last time has been called.
The change in state needs to be an atomic operation, that is, when it is called concurrently, it can be executed only once. You can use distributed locks, or optimistic locking CAS operation implementations.
Specification of service splitting five: interface data definition strictly forbidden embedded, transmission
MicroServices interface between data transmission, often through the data structure, if data structures through transmission, from the bottom up to the upper layer using the same data structure, or the upper layer of data structures embedded in the underlying structure, when the data structure to add or delete a field, the affected surface will be very large.
Thus the interface data definition, in every two interfaces between the agreement, strictly prohibit the embedded and the transmission, even if the similar, but also should be redefined, so that the interface data definition changes, the impact surface only in the caller and callee, when the interface needs to be updated, more controllable, but also easy to upgrade.
Specification for service splitting VI: standardized project name
Micro-service after splitting, the project name is very many, developers, the development team is also very much, how to let a developer see a project name, or the name of the jar, you probably know what to do, need a standardized convention.
For example, pay is paid, the appearance of order is the order, the account is the user.
If the appearance of compose is the combination layer, controller is the interface layer, basic is the basic service layer.
The API is the interface definition, IMPL is the implementation.
PAY-COMPOSE-API is the payment combination layer interface definition.
Account-basic-impl is the implementation of the user base service layer.
V. Selection of service discovery
After MicroServices are split, calls between services require service discovery and registry maintenance. There are several ways to mainstream it.
The first is that DUBBO,DUBBO is the standard of the SOA architecture MicroServices Framework, which has been heavily used, although the intermediate outage has been maintained for some time, but with the advent of microservices, re-maintenance is a preferred choice for many familiar with Dubbo RPC developers.
The second is springcloud,springcloud for MicroServices, and in the case of Dubbo has no one to maintain, the introduction of a mature framework to support micro-services.
Dubbo vs. Springcloud contrast, Dubbo more attention to service governance, the original function is not comprehensive, and springcloud focus on the entire micro-service ecosystem, the tool chain is very comprehensive.
Springcloud can be customized, through a variety of components to meet a variety of micro-service scenarios, the use of Springboot unified programming model, can quickly build applications, based on annotations, easy to use, but the learning threshold is relatively high.
Dubbo registered to zookeeper inside is the interface, and Springcloud registered to Eureka or consul inside is an instance, in the case of small size, no difference, but once the scale is large, such as the number of instances of the class, interface data even if the 100,000 level, For zookeeper in the tree size is larger, and zookeeper is strong consistency, when a node hangs, the data synchronization between the nodes will affect the use of the line, and Springcloud is much better, the instance level is less one magnitude, the other consul is not strong consistent.
The third is that although kubernetes,kubernetes is a container platform, he designed it to run microservices, thus providing a number of components for microservices to run.
Many springcloud can do things, kubernetes also have the corresponding mechanism, and because it is a container platform, relatively common, can support multiple languages, for business without intrusion, but also because it is a container platform, for the operation of micro-service life cycle maintenance more comprehensive, For calls and governance between services, the service can only meet the most basic service discovery needs.
Thus, when used in practice, kubernetes and springcloud are often used together, kubernetes is responsible for providing the operating environment of the microservices, the calls between services and governance, which is done by Springlcoud.
The service Mesh,service mesh to some extent to make up for the shortcomings of kubernetes service governance, the business code 0 intrusion, the service governance sank to the platform layer, is a trend of services governance.
However, service mesh needs to use a separate process for request forwarding, performance is not satisfactory, in addition, the community is relatively new, lack of maturity, temporarily did not reach the standard of mass production use.
Please pay attention to the public number