Advantages and disadvantages of monomers
A single application is to package all the functions of an application into an independent unit, which ultimately exists as a WAR package or JAR package without any external dependencies, and contains all the logic such as DAO, Service and UI. Monomer application has the following advantages:
Easy development: only with IDE development, debugging functions can be completed
Easy to test: Testing is done by unit testing or a browser
Easy to deploy: Package as a single executable JAR package and execute the JAR package to complete the deployment
Unfortunately, this simple unit has major limitations. With the iteration of business requirements and the expansion of additional functions, the application eventually becomes a behemoth, becoming more complex, logically coupled and difficult to understand. Unclear responsibilities of team developers, difficult deployment, huge cost of regression testing, and greatly reduced delivery efficiency. In summary, single application has the following five major disadvantages:
1. High complexity
Code is hard to understand
At a certain stage of the development of business scale and team scale, these deficiencies are more obvious. The deficiency of single architecture is firstly manifested in complexity. Maven modules increase, multiple modules are coupled together, and the code structure is chaotic, so that no one in the team understands the whole code logic.
Incomprehensibility leads to low quality code and further complexity
Incomprehensibility leads to less reusable code because you don’t know what to reuse; Even if the changes are made, the scope of impact is uncertain, which leads to development preferring to create a new method and a new class, further accumulating duplicate code;
Code is difficult to modify and refactor
If you don’t understand code, you can’t write highly cohesive, poorly coupled code, and the quality of your code continues to decline. Further complexity
As complexity increases, the coupling becomes more intense and the code becomes more and more dependent, making it difficult to modify and refactor.
Team responsibilities are not clear
The highly coupled single project makes the logical boundary blurred, new business requirements development tasks cannot be effectively assigned to people, team members’ responsibilities are not clear, and communication costs increase.
2. Low delivery efficiency
It is time-consuming to build and deploy, difficult to locate problems, and inefficient to develop
The amount of code is relatively large. First of all, the compilation time becomes longer, and most of the development and debugging time is spent on recompilation. As the amount of code increases, it is difficult to locate bugs, which further reduces the development efficiency. These are all factors that lead to development efficiency underground;
The code was complex and the impact of the change was hard to understand, and it took days to complete full testing
When we develop a new feature or fix a bug, it is difficult to predict the impact of the code change, so we should go into regression testing of the full functionality before each release.
Full deployment takes a long time, has a wide range of impacts, and has high risks
Such full deployment takes a long time, has a wide range of influence, and has high risks. As a result, we gather many functions and fixes together to complete the development, which leads to reduced product release frequency, and whether new functions and replacement experiences can be presented to users in a timely manner, or even overtaken by competitors
3. They are not scalable
A single unit can only be extended horizontally as a whole, not vertically by modules
IO – and CPU-intensive modules cannot be upgraded or expanded independently
Service modules have different resource requirements. Because all modules are deployed together, THE I/O intensive modules and CPU intensive modules in a single architecture cannot be upgraded or expanded independently, such as image compression, encryption and decryption, which are CPU intensive. Cpus should be upgraded. IO intensive modules, such as log collection services, require more memory and use disks with better performance, such as SSDS.
4. Poor reliability
A bug can cause an entire application to crash
Since all modules are deployed in an instance, a bug can cause the entire application to crash. For example, a memory leak of an unimportant module can cause all application instances to crash one by one
5. Impeding technological innovation
Limited by the technology stack, team members share the same framework and language
Limited by the technology stack, team members must use the same framework and language. Modules cannot be split and new languages and frameworks cannot be used.
Upgrading and changing the technical framework becomes difficult
When there are new technologies or new versions that fit the business scenario, the refactoring costs and risk changes associated with upgrading and changing the technology framework are high
Trying new languages becomes difficult
It can also be difficult to experiment with new languages, as development costs rise, refactoring and new requirements iterations can’t be reconciled, and the final compromise is to stick with the original framework and language
So how do you solve the singleton problem by moving to a microservice architecture, so let’s see what microservices are?
Definition of microservices
Microservice architecture: Single applications are divided into multiple small services with high cohesion and low coupling. Each small service runs in an independent process and is developed and maintained by different teams. Lightweight communication mechanism is adopted between services, independent automatic deployment can be adopted, and different languages and storage can be adopted.
Monomer architecture to the whole team to develop a large maintenance project and a single library, the service architecture, user requests through the API Gateway is routed to the downstream service, with lightweight communication protocol for communication between services, service registry found each other, each service has the development of specialized maintenance team, each corresponding to a separate database service, Services are independently developed, deployed and launched.
Next, we summarize the advantages of microservices.
Advantages of microservices
1, easy to develop and maintain
Microservices are relatively small and easy to understand;
Short start-up time, high development efficiency.
2. Independent deployment
Changes to one microservice do not require coordination with other services.
3. Strong scalability
Each service can scale horizontally and vertically;
Each service can be independently expanded based on hardware resource requirements.
4, to match the organizational structure
Microservices architecture can better match architecture and organization;
Each team is individually responsible for certain services, resulting in higher productivity.
5. Technical heterogeneity
Use the technology best suited to the service;
Reduce the cost of trying new technologies.
The challenge of microservices
No technology is a silver bullet, micro services are the same, more or less some shortcomings and problems. Then we must solve these problems one by one, which is what we will focus on in the next chapter.
The first thing I faced was splitting the unit into services.
1. Service separation
Principles of microservice fragmentation: domain model, contextual constraints, organizational structure, Conway’s Law
In reality, there is no specific and clear method to achieve the separation in one step. Instead, it follows certain principles, such as the separation based on domain model, organizational structure and single responsibility. In the process of separation, experience should be combined with judgment.
Each microservice has its own database
Service separation should also take into account the independence of the storage database. When multiple services directly read and write to the same table in the database, any changes to these tables need to coordinate the deployment of these related services.
This violates the principle that services are independent of each other.
Shared data stores can easily inadvertently create coupling. Each service needs to have its own private data. For example, the order table is shared by the order service and the commodity service. If the commodity service does statistics alone, it does not know how many goods are sold in a day, and does not know which data is generated by the service, it cannot carry out technical product planning, and the modification of the table structure also needs to notify multiple services, which is intolerable.
Each service needs its own database, but these databases can be co-located on a shared data server, and the point of database privacy is that services should not be aware of the existence of other services’ underlying databases. A shared data server can be used to start development, and later, if the amount of data and concurrency becomes large, the server can be isolated. Once the server is quarantined, you can isolate the databases of different services simply by changing the configuration.
Service boundaries are determined between microservices and connections are established through shared models
Each microservice has its own business capabilities, so the part of interaction between services is the service boundary;
Border services is also a problem, need to know enough about their products and business to determine the most natural border border services adhere to the principle of service to the weak coupling and high cohesion and weak coupling is a service with other any communications should be through publicly exposed interface (API, events, etc.), These interfaces need to be well designed to hide internal details. In this way, our services remain independent and can be easily reconstructed in the future. High cohesion means that multiple closely related functions should be included in the same service as far as possible, so as to minimize the interference between services.
2. Data consistency
In a singleton architecture, the operations that we do through database transactions cannot be done in a distributed microservices architecture because instances are deployed on different servers, such as order services for placing orders, and inventory destocking should be placed in the same transaction. Under the microservice architecture, the order operation and the inventory withholding operation are distributed on different servers, so the distributed transaction operation needs to be carried out. However, the distributed transaction has the disadvantages of high latency and not supported by noSQL database.
These disadvantages prevent distributed transactions from being applied to microservices. In microservices scenarios, we usually use final consistency instead of strong consistency:
Reliability event mode
Compensation mode – SAGas mode
3. Service communication
Communication technology solution: RPC vs REST vs asynchronous messaging
RPC, REST API, asynchronous message, asynchronous message we can use some message queue framework such as Kafka, rrabbitMQ, now let’s talk about the choice between RPC and similar REST API using HTTP protocol, TTP benefits are easy to debug, cross-language, low threshold, widely accepted. The same disadvantage is that the protocol document is not easy to maintain, the protocol is more complicated, the performance is worse than TCP HTTP protocol deficiencies.
Rpc communication is usually based on Tcp, and the common technology selection is thrift, GRPC, and Dubbo. Thrift and GRPC need to define IDL files and generate Java code through IDL files. The advantages of Rpc are IDE friendly, code prompt, and protocol maintenance in the code. Both the parameter passing and the response result are known through the code. But at the same time, it also has disadvantages, such as many RPC schemes do not know cross-language, the supported languages are limited, idL files need to be defined and maintained, and there are certain learning costs, in addition, RPC is not easy to debug and test.
Service registration and discovery
In an environment where service instances vary, hard-coding IP addresses is not an option, and some sort of discovery mechanism is needed for services to look each other up. This requires us to register our service information in a distributed store, which is called the service registry and the service registry can act as an authoritative source of information. This contains information about available services, as well as service network locations such as IP and port numbers. What components can be used to implement this? Eureka and ZooKeeper are common, but etCD, Consul, Redis are also available.
Load balancing
The registration function, the client via a service registry which instance instance list and decided to connection, on the client side load balancing, compared based on the client to do load balancing server load balancing has many benefits: first of all, save the hardware balancers to reduce the operational cost, second can achieve a variety of load balancing strategy such as response to the perception of load balancing strategy.
4. Service gateway
API Gateway
If our microservice communicates with end users, it is bound to consider identity authentication, security defense and other aspects. If each microservice deals with end users, multiple copies of these codes need to be implanted into each microservice business code. This causes coupling between business code and authentication code, reducing code reusability. This needs to realize the network border a service gateway (where the network boundary can be thought of as the boundary between internal network and external network), the identity authentication, security defense, flow control these functions into the service level, to the business service shielding network border service details, make business services focused on the development of the business logic to maintain and test.
Backends For fornends
For example, public API, desktop client, and mobile client correspond to one service Gateway respectively. The service Gateway can be AN API Gateway that outputs only API, or a back-end that serves the front-end. Here is the back-end of front-end service. Such as aggregating data from multiple services back to the front end.
Identity authentication, routing services, traffic limiting and brush prevention, and log statistics
5, high observable
Health detection and centralized monitoring
Each service and used component has a health detection mechanism, so that we can find abnormal nodes in time, and then make judgments and adjustments. All monitoring indicators are aggregated and output visual charts and interfaces to help us find problems quickly and intuitively.
Log aggregation and retrieval
For example, in the e-commerce app, we found that it was impossible to place orders. Under the distributed architecture, logs were scattered among multiple servers and multiple services. We did not know which server the error logs were placed on. This requires us to achieve log format standardization, and through some means to gather together for retrieval query. Logs can be searched across all services, a specific service, or an instance of a service; The code used to send logs to a centralized logging system can be included in a shared library or provided through code scaffolding.
Distributed tracking
In micro service architecture scenario, a client of mounting calls eventually request go through multiple services aggregated data structure returned to the client, but we don’t know this request don’t know what service, after call which service problems, what is the input and output for each service, it has brought us location problem, in addition, if a request takes longer, We don’t know which service takes the most time to optimize for specific performance. With the evolution of architecture, we in the architectural design planning needs to know when the dependencies between services, this need what technology to realize, this is what we want to introduce a distributed tracking and distributed tracking using the correlation id, the request source to create this correlation id, and between services for passthrough, will eventually correlation id information such as the aggregation query analysis together.
6. Reliability
In talking about singleton, we said that a memory leak in one business module can cause the entire process to exit.
In the microservices scenario, a memory leak in one service will not affect services without dependencies.
However, it can cause the upstream service threads to hang because the exception service is dead or unavailable, resulting in a cascading effect and further upstream propagation of the fault.
Flow control, timeout control
Reliability technology ensures that service consumers are not slowed down by downstream services and recycle business threads in time through traffic control and timeout control.
Bulkhead isolation, circuit breaker mechanism
Circuit breaker means that when the number of service invocation errors reaches a certain number in a certain time, the invocation switch of the service is automatically turned off, and the request is returned or transferred to the degraded method to reduce the risk of resource exhaustion. When the service is unavailable, a degraded method should be written for the interface method as a service consumer.
Service degradation, idempotent retry
Because the communication between services is transmitted over the network, network exceptions and network partition faults often occur. In such cases, we can retry the call. During the retry, we should pay attention to two points: first, the interface must be idempotent, and the final result must be the same no matter how many times the interface is run. Idempotence ensures that retries do not have negative effects. During the retry process, the hibernation time should increase exponentially. Otherwise, the alarm effect will occur. For example, after a service recovers from a fault, a large number of other services are trying again in the same retry window, which will easily cause great pressure to the system.
Refining code scaffolding
In addition to developing business logic, we also need to build a set of available framework for microservice engineering. This is to speed up team work efficiency, keep unified microservice solutions, enhance code reuse, and conduct unified optimization. There are many problems to be solved in microservice, so it is necessary to extract service code templates. It includes service registration discovery, service communication, monitoring, logging, exception handling, and so on.
Migrate from monomer to microservice
1. When to migrate microservices?
With all this talk about the benefits of microservices, can we abandon the monolithic architecture and go straight to microservices?
Martin Fowler in MicroservicePremium
“Don’t even consider microservices unless you have a system that’s too complex to manage as a monolith.” Don’t consider using microservices if your system isn’t complex enough.
Monolithic architectures can be more productive than microservice architectures when the business is not complex and the team size is small. Because establishing a microservices architecture requires additional overhead to support and manage microservices, reducing productivity; However, as business complexity increases and team size increases, productivity declines in monolithic architectures are more pronounced than in microservice architectures.
When complexity reaches a critical point, microservice architectures are more productive than monolithic architectures because the loosely coupled autonomy of microservices slows down the productivity decline.
So when we’re working on a project, it’s important to judge when to use microservices based on your team and the complexity of your business.
According to my experience, a new project in 1-3 teams can be divided into an API gateway and a back-end service that integrates all the business. The API gateway pays attention to authentication and routing, and deals with partial failures. Back-end services should be divided into business modules; At the beginning of the project, there was no need to add components such as flow control and circuit breakers because there was not much flow.
At the same time, even after the migration to microservices architecture, the granularity of the split should evolve from coarse to fine, depending on the size of the business complexity and the size of the team.
2. How to migrate to microservices?
One strategy: Don’t rewrite code in a big way (only if you’re committed to rebuilding a whole new set of microservices-based applications). Rewriting code sounds great, but it’s fraught with risk and ultimately fails, as Martin Fowler said: “The only thing a Big Bang rewrite is a Big Bang!”
Instead, the strategy of gradually migrating monomer applications should be adopted. By gradually generating new microservice applications and integrating them with old monomer applications, the proportion of monomer applications in the entire architecture will gradually decrease over time until they disappear or become part of the microservice architecture. This strategy is a bit like maintaining a car at 70 miles per hour on the freeway. While challenging, it’s much less risky than rewriting.
Martin Fowler called this modern strategy the strangler App, named after the strangler Vine, also known as the Strangler FIG, found in the rain forest. In order to climb to the top of the forest, the strangler vine has to grow around the uncle. After a period of time, the tree dies, leaving the tree vine. This app uses the same model, developing new microservices apps around traditional apps that will fade away.
SOA VS microservices
The contrast between SOA and microservices is an old topic, and I think the biggest difference between the two is the technical context and context in which they were proposed.
SOA emerged as a solution to a historical problem: there was a need for a mechanism to integrate a variety of systems that were isolated from each other during enterprise informatization, hence the emergence of ESBs. Similarly, services are a big concept in the early days of SOA, often specifying a system that can operate independently.
Microservices have no historical baggage, and the size of the service is usually not too large. In terms of service granularity, SOA is more like a simple combination of individual units, while microservices are finer grained services. Secondly, data splitting SOAs tend to share databases, with microservices per service per database.
If you want to know the technical knowledge of architecture, please follow me. I will share more knowledge about distributed architecture in the future. In addition, I recommend a learning group: 697-57-9-75-1, which will share some videos recorded by senior architects: Spring, MyBatis, Netty source code analysis, high concurrency, high performance, distributed, microservice architecture principles, JVM performance optimization has become an architect’s essential knowledge system. You can also get free learning resources, which have benefited a lot at present. The following knowledge system map is also obtained inside the skirt.