Microservice architecture has now become a must-talk topic of enterprise application architecture. This paper is a reflection of the author’s years of work and practical thinking, jumping out of the perspective of pure technology to think about architecture, to look at microservices, to ensure the use of existing technology (tools) to maximize business value.
1. Escape from monolithic systems and embrace microservices?

The difference between a monolithic system and a microservice is that a monolithic system is a large and complete set of functions, and each server runs the entire service of the application. Microservices are independent and autonomous functional modules, which are part of the ecosystem and symbiotic with other microservices.

Today, the prevailing view of monolithic systems and microservices in the industry is: Monomer system very easy development, testing, deployment, but monomer system faced with many problems, such as low development efficiency, maintenance costs, deployment influence bigger, poor scalability and high cost of technology selection, and introduced the micro service can implement each micro service development and maintenance, easy to facilitate communication and collaboration, very suitable for a small team of agile development and continuous delivery; Each microservice has a single responsibility, high cohesion and low coupling. At the same time, each microservice can be independently developed, run and deployed. Each microservice is independent. If a service is deployed or down, only the current service will be affected, not the entire service system. With the continuous expansion of the system scale, each micro-service can independently expand horizontally and vertically in the face of massive users and high concurrency. Each microservice can use different programming languages and different storage technologies, making it easier to experiment with new technologies. In addition, business refactoring of a single service does not incur a significant business burden or technical debt.

The author’s view of microservice system is that we need to think carefully about the stage of using microservice in the process of transformation from single system to microservice system. Microservices are not a silver bullet, they put forward higher requirements for design and operation difficulty, but also some technical complexity.

Therefore, we need to think about and solve the distributed complexity, data consistency, service management and operation, automatic deployment of services and other solutions. In fact, microservices reduce the complexity of individual services by breaking up individual systems into smaller services, but as a whole, this approach has resulted in a large number of services and increased calls between services, resulting in a more complex system architecture.

We often ignore the business value and cost considerations, and technology too much pursuit, so may cause we designed the distributed architecture of the serious influence our development speed and quick iteration of the business, and with the uncertainty of business often leads to our architecture in the six months to a year has not entirely applicable, come over.

In addition, if the business does not develop, it will lead to the blind waste of a large number of server resources in the early stage, which is more than worth the loss for the start-up business. Therefore, in the early stage of the project, in order to ensure rapid business growth, ensure that the system is as independent and complete as possible, and reduce the technical complexity after the introduction of micro-service architecture, for example, it puts forward higher requirements for operation and maintenance, because a good micro-service architecture requires stable infrastructure.

As the business develops well, the scale of the system will continue to expand, and its scalability, scalability, availability and performance limit our business development. At this time, we consider microservice transformation with a clear business thinking and invest more resources.

Microservices architecture uses services as modular units, so we can initially isolate dependencies through Maven’s Module modularization during early design, leaving room for further transformation. Note that microcosm is a symbiotic relationship in an ecosystem. Here, not only can they be link dependent, but their business value must be symbiotic. Therefore, the core values and key functions of individual systems are identified in the later stage, and then these functions are divided into independent and self-integrated modules. Here, see chapter 12, “Legacy Microservice Architecture Transformation,” in my book, “Highly available and Scalable Microservice Architecture: Based on Dubbo, Spring Cloud, and Service Mesh.”

To sum up, microservices reduce the complexity of a single service by breaking up a single system into smaller services. However, on the whole, this approach results in a large number of services, and more calls between services, which makes the whole system architecture more complex. Therefore, we should not only focus on technology, but also consider the input-output ratio to ensure the maximum benefit of the current stage.

Two, get rid of the monomer system away from the big mud ball?

One thing that many people complain about with monolithic systems is that their services are so cohesive that they look like a big ball of mud. So, does servitization solve this problem? In fact, microservices reduce the complexity of individual services by breaking up individual systems into smaller services, making the individual systems look more functional, but the overall system architecture becomes more complex. In fact, an invocation between multiple services in a production environment might look like this.

Typically, the microservice ecosystem of a production environment is much more complex than the example above, with dozens to hundreds of services. Therefore, it is very important for us to systematically sort out the dependency and link relations between services. Especially in the promotion of the time, the need for a strong guarantee of the core link, this work is more important. In this regard, I recommend automatic link carding through APM traffic collection.

In addition, when we design the architecture, whenever there is a problem of service granularity, such as the creation of a new project, or ambiguity about service boundaries, we need to discuss the service boundaries clearly and keep our services as cohesive as possible.

Iii. Can migration of microservices improve system robustness?

Here, there is a mainstream view: a single system is a collection of a lot of function, if a service fails, will affect the entire business system, however, use of micro service can be achieved if a service deployment or downtime, will only affect the current service, and will not affect the whole business system.

In fact, this point of view seems very true, but in a real business scenario, it is not the key reason that drives our transformation. First of all, a single unit needs clustering and load balancing to avoid a single point of failure. Note that clustering and load balancing and microservices (service vertical split) are not mutually exclusive, but co-exist in high concurrency and distribution.

In addition, to address service deployment, we can consider rolling publishing services without interruption. Therefore, a single system is not necessarily unrobust. At the same time, introduced the after service, on the whole, this way has caused the presence of large amounts of service, the service call each other between will also increase, which leads to the whole system architecture is becoming more complex, the chances of a link of a node failure is greatly increased, rely more on means the possibility of more problems. At this point, if a microservice on one of the calling links breaks down and cannot provide services, how can the upstream services that are heavily dependent on it ensure their availability? (I’m referring here specifically to strong dependency calls, service degradation, or circuit breakers that can be detrimental to the business and are not effective solutions.) Therefore, in many scenarios, the failure of a service may affect the entire service system.

Therefore, if we do not design for failure and build a system of service governance, it will lead to the unrobustness of the overall service.

Iv. Can migration of microservices improve system performance?

So what are the main drivers for migrating microservices? I think the main benefit drivers are scalability and performance. A service may have reached a bottleneck due to the limitations of the host machine, and it is a good idea to split the service in order to further squeeze the resources of the machine. At the same time, we can further achieve automatic expansion to adjust the use of the machine.

But does migrating microservices necessarily improve system performance? My opinion is not necessarily true. After servitization, the call link becomes longer, and the original RPC communication may become several times, resulting in increased performance loss. For example, one of the main challenges of remote multi-live is network delay. Cross-city delay is bound to be a problem. Suppose that the cross-region network delay may be less than 100 milliseconds, and one HTTP request involves one or two hundred cross-city RPC calls, the overall response time will increase a lot, so the challenge of delay is very big. In order to solve the problem of data delay, Ali first proposed the solution idea of unit, which is to make the requests converge to the same area for completion, with high cohesion of units and no cross-area access, namely, “unit closure”. In addition, there are network timeouts across service invocations, which also increase the potential for synchronous blocking through retries.

Therefore, servitization sacrifices the call performance on the links between services to improve the whole business system’s squeezing of machine resources to improve system performance.

Availability of microservices = is every invocation provided by the service reliable and available?

Many people understand the availability of microservices as being reliable and available every time the service provides a call. That’s not quite right. In fact, microservices guarantee the overall availability of their services. In general, if service A calls service B, if the call takes 10 seconds, then the following situation may block, indirectly, causing the thread pool to burst, making the service unavailable. Therefore, timeouts are used to ensure that the result response is completed in a very short time with as little synchronization blocking as possible.

In addition, if service B fails, all dependent services will be blocked. If there are a large number of requests, thread resources will be consumed and the service will crash. In fact, service-to-service dependencies lead to cascading propagation, which indirectly leads to an “avalanche” effect of service failures, making the entire microservice system unusable. To solve this problem, circuit breakers come into play.

Vi. Are databases independent and transparent in microservices?

A dominant view of microservices is that each service has its own cache and database, and that the cache and database are independent and transparent. Therefore, sharing a cache with a shared database is not a good idea. What if service A needs to get service B’s data? Typically, service B provides an API interface to get this data, and service A invokes this interface for business assembly. Therefore, after microservitization, data exchange between services is carried out through interfaces. If service A accesses the data of service B over the business logic of service B, the data independence between microservices will be destroyed.

At this point, I need to pour cold water. Nothing is absolute, and there are several special scenarios where sharing data may be required.

One is the transition of old services to new services, where the new services reuse the old service database to meet the functional and data transition requirements.

Second, multiple services may depend on the same data source, such as data aggregation of reports.

In this case, if we rely solely on RPC’s interface call, it is likely to lead to occasional call timeout, resulting in a greater chance of failure. Therefore, the common approach to solve this problem is to share data, either through data synchronization in the way of data redundancy, and then based on the local service for data aggregation within the boundary; Either the centralized ETL of data can be carried out through the separation data warehouse scheme, and then the processed data can be passed externally. Third, there is the more realistic question of cost. In fact, more databases bring more overhead costs. A lot of times, we think about it in terms of cost. We chose to reuse the original database tables and wait until the business value is clear before considering a standalone database.

At the same time, shared data technology solutions avoid costly and repetitive data migration when the context between data is unclear, and make it easier to fine-tune the service granularity as needed, and then migrate data once the service granularity is stable. Therefore, we need to find a proper balance between the two, comply with the mainstream view of micro-services as much as possible, and make full use of the benefits of micro-services.

7. Organize and guarantee the implementation of micro services?

Microservices put new demands on the organizational structure. It suggests splitting large teams into smaller teams, each of which develops and operates one or more services independently, and requires continuous delivery, continuous deployment, and DevOps in the process.

Different services may be developed and maintained by different teams. In practical scenarios, the convenience of micro-services lies in the closed-loop generation within the team. In other words, it is easy to develop and maintain within the team and facilitate communication and collaboration, but there are huge communication and collaboration costs for external teams. As shown in the figure, team A’s understanding of service C is A black box. We don’t know whether it is A singleton service or A microservice, how many servers it has deployed, which downstream services it needs to rely on, whether there are traffic limiting, circuit breaker and downgrade policies, and how to access. If we need to validate these issues, it usually requires human collaboration and validation.

Of course, this is an inevitable problem brought about by division of labor. So we try our best to ensure the cohesion of services within our own team, divide them around business modules, and ensure the independence and integrity of business of microservices, with as little service dependence and chain invocation as possible. Here, a new problem arises. How micro are microservices? In fact, it is not always better to split the service as small as possible, even the extreme case is to split a piece of functionality into a service, which is wrong. Therefore, the separation granularity should ensure the independence and integrity of microservices, and the separation of services is based on the separation of business modules. If the business/technical value of separating into services is not clear, then coupling it to a single system is sufficient for the life of the project. If with the development and needs of business, we can adjust the module structure at the source level of the system, and split it into independent microservices.

Sometimes, the team has absolute ownership of the project, so the production of microservices is a “half-finished product” for the benefit of the team. I believe this is not an exception, but the majority of the norm.

Now, let’s look at a case study. Team A developed an “interactive component” with “comment module” functionality in mind for reusability. At this point, team B is unknowingly developing a similar “interactive component.” Team C also has this requirement. It knows that Team A has this “interactive component” and hopes to reuse it. However, since the design of this “interactive component” takes team A’s current business into consideration, it does not have good reuse, for example, it does not support “comment building” function. As Team A was unable to provide immediate support due to the current schedule of other projects, team C evaluated and decided to spend A week developing an “interactive component” that met their business needs. At this point, each project team maintains an “interactive component.”

In this case, due to the responsibilities and boundaries between teams, service reuse is limited, and even leads to a situation of individual competition, which generally requires planning and coordination at the company level. Coincidentally, both team A and Team B are working on A single system, but the two need to be integrated. In order to ensure the existing interests of both teams, they do not break the original architecture and merge, but determine the domain boundary on the original basis.

In addition, assuming that external an RPC interface is not so stable, common practice is to analyze the cause of instability, but under the condition of cross team cooperation, external services is likely to be a black box, and is likely to be an invisible wall between teams, then the communication cost is very big, now need someone to link all lead to everyone’s interest to reach an agreement. The most effective way to circumvent this problem at the moment is probably through other means within the team, such as redundant caching or interface adaptation. Therefore, it may be a better solution to maximize business value under the current organizational structure and environment, we need to adapt to the present and look to the future. When it comes to interface adaptation, there is another very common microservice architecture design: the adapter service pattern. Normally, external services to our news frame type do not match what we need, at this point, we go to push them are not very realistic, so, in order to ensure our business logic without introducing a lot of business logic adaptation, we will introduce adaptation layer (adapter service), it will be an external service message body adapter into a unified standard format, Then upward exposure services, such as refund adaptation, logistics adaptation and so on.

Therefore, the organization of the company greatly influences the determination of service boundaries. Normally, we divide the domain within the boundaries of our team to meet business needs as much as possible. Although this is a “semi-finished product” from a technical perspective, it may be a better solution to maximize business value in the current environment. It is also a good idea for people to consider further integration when they see enough value in it.

Write in the last voice

Finally, let’s talk about introducing new technologies and bringing technology dividends to the project.

A new technology requires consideration of learning costs and maintenance costs, as well as availability assurance and operability. For example, UNDER the escort of operation and maintenance in the company, I can easily use various technologies, etc., but I do not dare to use MongoDB in another company, because I know THAT I am not an operation and maintenance expert in this aspect, and I may not be able to solve any problems. So, the technical risks of introducing a new technology.

A lot of times, we design based on failure, which is the difference between a junior engineer and a senior engineer. For example, Redis distributed lock, many people just want to come to how to achieve this logic through the code, but, if the Redis cluster master service hung, directly switch to the slave service, because it is master and slave asynchronous synchronization, and distributed lock pay attention to is must be the latest lock data to work, is in a moment to take effect, At this time lost distributed lock data, your business will cause repeated requests, and distributed lock if applied in the business, must be a very important scene, especially finance and payment, so the single-point version of Redis distributed lock is not a good method, can not be used, if you want to use, you have to solve the stability problem. (Citing the case “Cheng Chao”, the author of “Highly available Extensible Micro-service Architecture: Based on Dubbo, Spring Cloud and Service Mesh”, shared in the group, which is particularly wonderful.)

Here, a little digression, to get back to the point, we often find that new projects try to use new technologies, while older projects are more conservative because trial and error costs are lower. Interestingly, new companies are more sensitive to technology development, for example, many small companies have a lot of practice and implementation in cloud native. At this point, you probably get the point I’m making: usually, the operation and maintenance of the company and the ability to control the depth of the technology are behind the use of the technology stack. So, we need to have a stock of new technology ahead of time to be ready to go to war, but for the most part, we want to make sure we’re maximizing the value of the business with what we have.

To summarize, this article to precipitate a lot of what I saw and heard in job and practical thinking, the core idea is not singing from the service, but to make everyone stay independent thinking, out of pure technical perspective to think about architecture, to look at the service, to ensure that the use of existing technology (tools) to realize the business value maximization.

About the author:

Liang Guizhao is an architect at Picotech, and co-author of high availability extendable Microservice Architecture: Based on Dubbo, Spring Cloud and Service Mesh.



We look forward to your joining us and growing up together

>>> Follow the official account for more technical sharing and recruitment information <<<