This is a creation in Article, where the information may have evolved or changed.
In 2014, Sam Newman,martin Fowler, a colleague at ThoughtWorks, published a new book, Building microservices. The book describes how to design and build a well-scalable and sustainable system based on the Microservice architecture model. In addition, the book combines the system evolution process based on this pattern with the current popular development processes such as continuous delivery, making the Microservice architecture pattern look very appealing. For these reasons, the architecture pattern is quickly known to the industry and is being tried in multiple products. This includes our company's product VRA.
In this more than a year, we have not only really realized the Microservice has a series of advantages, but also made a series of mistakes. So in this article, I will give a brief introduction to the Microservice architecture pattern, and introduce the experience and lessons we have gained to you.
Monolith
The articles on Microservice are often prefaced with monolith, and I am no exception. The reason is that knowing the inconvenience of monolith makes it easier to understand the various advantages of the Microservice architecture model.
First of all, please recall what the service we have developed is like. Typically, the code for this service is made up of multiple projects, and each project has a clear boundary based on the different capabilities it provides. At compile time, these items will be packaged into a jar package and eventually merged together to form a war package. Next, we need to upload the war package to the Web container, unzip the war package, and restart the server. After performing this series of operations, we have completed the compilation and deployment of the service:
This way of organizing all the code and functions contained in a war package is called Monolith. In a small project, this kind of code organization is acceptable: After the code is changed, the software developer can make a cup of coffee while the compiler compiles the code, and take a minute to deploy the newly compiled war package to test the changes that they have just made. But as the project gets bigger, the entire development process becomes long: even if a single line of code is changed, it takes dozens of minutes or more one hours for the software developer to compile all the code and then spend a lot of time redeploying the product that was just built. To verify that your changes are correct.
If the deployment of your application is cumbersome, then to test your changes, software developers need to make a lot of environment settings before deployment, which makes the work of software developers tedious and tedious:
As you can see from the above, the software developer spends significantly more time compiling and deploying than when the app is getting bigger, and even more than the time it takes to change and test the code, the efficiency has become very low.
As we get bigger and larger, the technology we use in our applications will become more and more. Some of these technologies are incompatible, such as a large-scale mix of C + + and Java in a project that is almost impossible. In this case, we need to abandon the use of some incompatible technologies, and choose a technology that is not so appropriate to implement specific functions.
In addition, since code organized according to Monolith will only produce a war package that contains all the features, we can only choose to deploy the war packages repeatedly to extend the capabilities of the service as it expands the capacity of the service, rather than simply extending the components of the system bottleneck:
But this expansion is a huge waste of resources. Take the example of what is shown: In a service, the load of one component has reached 90%, that is, it is time to expand the capabilities of the service. The other three components of the same service have not yet reached 20% of their processing power. Because the various components of the Monolith service are packaged in the same war package, adding an additional service instance can reduce the load on the component that needs to be scaled down to 45%, but it also makes the utilization of the other components even lower.
It can be said that all the inconvenience is due to a war package in the Monolith service that contains all the features of the service. The way to solve this problem is to microservice the schema pattern.
Microservice Schema Mode
To put it simply, the Microservice architecture pattern is to organize the entire Web application into a series of small Web services. These small Web services can be compiled and deployed independently, and communicate with each other through their exposed API interfaces. They work together to provide functionality to the user as a whole, but can scale independently. Take the example of the Wikipedia service architecture shown here:
As you can see, Wikipedia contains a range of services, such as data access service databases, search service searching, and so on. These services include an unequal number of service instances to ensure a high level of service to the user under different workloads. When a user's request arrives, they work together to complete a response to the user's request.
With Microservice schema mode, software developers can validate their changes by compiling and redeploying individual sub-services, eliminating the need to recompile the entire application, saving a lot of time. At the same time, because each sub-service is independent, the most appropriate implementation technology can be determined within each service, making it easier to develop these sub-services. Finally, if the current system does not have enough capacity, then we only need to find the sub-service that is the bottleneck of the system and expand the capacity of the sub-service:
Microservice Experience Talk
The above is the introduction of the Miscroservice architecture pattern, is not very simple? In fact, this is an evolving architecture pattern. In many discussions, the standard implementation of the model, as well as the many topics of best practice, have not been fully agreed upon. So what I am introducing here is a series of experiences that basically agree on the discussions in various forums. While you are implementing your own Microservice architecture model, you can learn from these experiences on the one hand, and adjust the implementation method of Microservice architecture pattern according to the requirements of the project itself.
Change your perspective.
Whether you are writing a service or writing a desktop application, we often first try to break down the functionality that needs to be implemented into a series of components and design the workflows and data flows needed to complete the business logic around those components. This design approach causes all components that implement business logic to run within the same process, and the implementation of each business logic runs within the same process:
But in the Microservice architecture model, we need a higher level of segmentation: before trying to split the functionality that needs to be implemented into a series of components, we first need to consider how to get the functionality we need to implement into a series of services that are independent of each other. For example, in an e-commerce website, support for the business process of purchasing a product can be done by three services: when the user browses the product, it uses the commodity browsing service, when the user adds the item to the shopping cart and generates the order, it uses the order service, and when the user makes payment online, It is used for payment services. Based on this segmentation approach, our application will run in three separate processes:
At the same time, the focus of these three services is not the same: in the commodity browsing service, the read operation of the database is much more than the write operation, so the optimization of the read operation will greatly improve the performance of the service, while the order service is mostly write operations, so we need to optimize the write performance of the order. The payment service involves the property of the user, so its security requirements will be higher. This discrepancy can lead to different technologies that are best suited to achieve these three services. Since these services are completely independent, it is entirely possible to determine the technologies that need to be used based on the needs of the sub-services, and no longer need to consider whether they are compatible with existing systems.
The advantage of using the most appropriate technology is that the code of the service becomes very clear, even in some cases, to a level of simplicity and elegance. In some discussions, some people even suggest that a service requires only 10 to 100 lines of code (they often use the shorthand loc, lines of code). Coupled with the fact that the service is independent and no longer mixed with other services, the correct use of the Microservice architecture model greatly improves the maintainability of the code and the speed with which the novice is getting started, as well as helping technicians to update and transform the technology set in their daily work.
However, the partitioning of the service is not the same as the partitioning between the components. The most important point is that the consumption of communication between services is very large in the same process. When designing a component, we need to consider that the interface given by the component can meet the current and future set of anticipated requirements as much as possible, which requires that the API provided by the component is forward compatible and has a number of other features, such as flexibility, extensibility, and so on. This often results in a finer granularity of the API provided by the component. When the program runs, calls to the API provided by the component are made in the current process and are very fast, so frequent calls to the fine-grained API do not have much problem. However, a cross-service invocation takes much longer than the in-process call time. If too many cross-service calls are required to process a request, the performance of the entire application becomes intolerable. So the API that we define when we perform the service split needs to be a coarse-grained API.
Let's take an e-commerce website as an example. When generating orders for users, e-commerce sites often need to list the main information of each commodity, the price of the goods, the range of concessions, and through the inventory system to check the inventory of the goods, so as to obtain the entire order content. If each communication with other services takes 100 milliseconds and the entire order contains 20 items, the system prepares the order for 8 seconds (100MS * 4 calls * 20 items). This is an unacceptable performance from the user's point of view. And as the number of items included in the order increases, the system's time to prepare orders increases linearly, making the system more intolerable.
The reason, in fact, is that the granularity of the API that is called to prepare the order is too fine. If the order system can take the main information of a commodity, the price, the preferential range and the stock information from the commodity service once, the efficiency will be increased four times times. If the order system does not need to send a request for each item in turn, but can retrieve all the required information through a one-time call to the service, the system will no longer be ready for the order to grow as the order grows. So in Microservice architecture mode, each service should provide coarse-grained APIs that can be used flexibly to reduce the consumption of various cross-service calls.
In addition to the granularity of the APIs provided by each service, the granularity of service segmentation is also a factor to consider in the service segmentation process. If the granularity of a service is too small, the granularity of the API it provides will not be high. A more general view is that, in the Microservice architecture pattern, a service needs to be able to perform specific business logic independently, at least for a crud operation of an independent resource. For example, in an e-commerce website, we need a service that can independently complete the reading of commodity-related information, such as the main information of the commodity, the price of the goods, and the preferential activities involved.
One exception to this is the handling of public functions. Imagine that in an application, we often need a rights management component to manage the individual permissions that a user has. The Rights management component often implements a common security model, such as ACLs (Access control list), RBAC (role-based access control), and so on. Each time a child service is accessed, these services need to check the permissions that the user has:
Did you find the problem? Yes, every call to a product system and order system requires the current user's permission from the permission system to determine whether the user can access specific information. If such a large number of public services, then the performance of the system will become very poor.
One way to solve this problem is to cache the next available information in each system, i.e. create a session for the user in those systems. Because each system may consist of multiple service instances, in order to be able to reuse the information stored in the session and reduce the number of requests to the public service, we need to use load balancing technology to allow the same service instance in the system to process the same user request. For more information about how to do this, see my other article, "Introduction to Enterprise Load balancing."
In addition to performance issues, public services have a logical dependency on each service. Let's continue our discussion through the example of a privilege system. When the composition of rights management exists in each service, we can determine whether the user can access a particular resource directly through the information of the incoming user and the resources that need to be accessed. That is, a Boolean type of data is actually returned from the Rights management component. But if permission management is no longer a component, but a service, then to avoid invoking the Rights Management Service every time, we need to record the user's permissions in the user's session. The next time a user accesses the service, we can determine whether or not it can access a specific resource by directly checking all the permissions that the user has. These permissions, which are logged in a user's session, often have a specific representation, such as a particular form of string, which means that it needs to be understood by both the service and the Rights Management Service, resulting in a coupling between the two services:
However, this approach enhances the dependency on the permissions system for the child service. As well as coupling between components, increased coupling can lead to a decrease in reuse of services.
So, how to split the service is actually the most tricky thing in the Microservice architecture pattern. In the segmentation process, the overall performance of the service is critical, and the independence of each service is the most important feature of all. Of course, the Microservice architecture model is still evolving, so I believe there will be more and more practical experience to be discovered by everyone, and then guide us to better division of services.
Shared Services
In the previous section, we have mentioned public services. In fact, this is one of the most tricky parts of the Microservice architecture pattern.
In fact, microservice architecture pattern implementations often require a series of public services to assist in the operation of the entire application. In addition to the Rights Management services we have just mentioned, we also need to be able to monitor the service status of individual service instances, add and remove upgrade management for service instances, and so on. These services are shared between service instances of each sub-service and can even be reused in other applications.
It's just that a lot of people have a misconception that Microservice architecture patterns make it easier to develop services. And the reality is the opposite. When developing applications using the Microservice architecture model, the efficiency is significantly lower than those developed through Monolith:
As you can see, the efficiency of developing applications using the Microservice architecture pattern is significantly lower than monolith in the first phase. However, with the increase of application scale, the development efficiency based on microservice architecture pattern will increase obviously, and the efficiency based on monolith pattern development will decrease gradually.
Why is it? This is because Microservice is an architectural pattern, not a specific technical solution. It does not divert all the difficulties in development, but only allows for a more appropriate technique to properly simplify the development of individual sub-services or to circumvent some of the difficulties that may be encountered in development. But in order to support the operation of each sub-service, we also need to create a series of public services. These public services need to be written at the same time as the first sub-service. This is one reason why Microservice architecture patterns are less efficient in the early stages of development.
However, the use of specific technologies does not bypass all the difficulties that can be encountered in development. Because in the Microservice architecture, each sub-service focuses on its own business logic, and all public functions are left to the public service, the public service needs to provide a sufficient amount of common functionality while maintaining the loose coupling of the various sub-services. Solutions that meet the requirements of all current and future sub-services to some extent. This is another reason why the Microservice architecture model will be less efficient in the early stages of development.
In the late stages of development, as the functionality applied in the monolith model becomes larger, adding a new feature affects many places in the application, so its development efficiency will become worse. Conversely, because the public services that are dependent on the various sub-services in the Microservice schema pattern have been completed, and the sub-service itself can choose to fit its own implementation technology, the implementation of the sub-service usually needs to focus on its own business logic. This is also the reason why the Microservice architecture pattern is more efficient in the later stage.
When we set up the application again through the Microservice architecture pattern, the efficiency disadvantage of its development will disappear, because we have created a public service at the time of the previous development based on the Microservice architecture pattern, so in this new application, We'll take these public services and change them:
As you can see, while we still need to take some time to make some changes to the public service, the resulting efficiency drop is no longer so obvious. In other words, even in the early days, we already have a high development efficiency.
And as the Microservice architecture pattern continues to pop, more and more users on the network will share their public service solutions. The performance degradation resulting from the first write of the application in Microservice architecture mode will gradually become smaller.
Model Matching
Ok. After introducing shared services, we can discuss another issue in the Microservice schema pattern: model matching. In Microservice, each service is independent of each other and is focused on its own business logic. Therefore, when looking at a thing, Microservice may have different perspectives, resulting in the corresponding model in each sub-service does not match.
For example, in an IaaS cloud, a user's role may be divided according to the responsibilities he has: the Cloud has a series of users for monitoring, to complete the operation of the cloud to monitor the overall performance (not including viewing user data, which is a security issue). At the same time the cloud users can be divided into account managers, tenant administrators, resource managers and ordinary users. In the application-as-a-service (aaas,application as a services) that runs on it, the partitioning of the user's responsibilities may be another way: The application architect is defined on the AaaS, and the operator is responsible for deploying and maintaining the application. When an application architect designs an application, it needs to have access to the resources on the IaaS cloud without the rights to assign resources, but the OPS person needs to have that permission to deploy and maintain the app.
In other words, the permissions delimitation in the IaaS cloud is not the same as the permission delineation in the AAAS service. In general, we often perform a matching of permissions at the time of business integration:
As you can see, because the AAAS service is running on the IaaS, the AAAS service needs to match its user role to the role defined by the IaaS in order to be able to manipulate the various resources contained in the IaaS. For example, an application architect needs to be able to define an application and need to know what resources are available on the IaaS, and to be able to specify exactly who can use them, so it needs to have the IaaS tenant Administrator, resource Administrator, and average user three roles. The OPS personnel on the AAAS only need to look at the resources they have on the IaaS during deployment and maintenance, so they need only the resource administrator and the average user.
But there are two bad places to do this: If the microservice contains only a few services, and the dependency between the services is not many, then this service matching can be resolved, but if the entire system between the various sub-services to communicate a lot, Then the role matching between the various sub-services becomes a nightmare:
The solution to this problem is to manage them using the public services we described in the previous section. In the case of providing a centralized public service, we no longer have to deal with so many model conversions:
In addition, simply matching a character is not really appropriate: As far as the application architect is concerned, it needs to look at the current existing resources without having to allocate the resources. So what it needs is read access to the resource. The OPS personnel need not only be able to read the resource information, but also need to allocate resources, so it needs to read and write permission of the resource. If the application architect is given read and write access to the resource at the IaaS layer just like above, then the application architect may have the wrong permissions to perform the wrong operation. The relatively appropriate way is to subdivide these permissions, that is, in the permissions to distinguish between read and write permissions:
Therefore, in a centralized public service, we need to use a more granular model. The fine-grained model requires a high degree of flexibility to be able to represent the corresponding model in each service without compromise.
I believe you can see now that although the Microservice architecture pattern simplifies the implementation of a single sub-service, it complicates the processing of the data. So, compared to the applications we've written in the past, the Microservice architecture pattern has a number of problems with data-related features.
One of the more common problems is maintaining data consistency across multiple sub-services. We know that in the service, the work of consistency is often done by the transaction. If you want to maintain data consistency between sub-services in the Microservice schema pattern implementation, we may need to use distributed transactions. But the distributed transaction itself is a very complex and difficult thing to do, so for now, this problem is actually very difficult to solve. But in turn, the transaction itself represents a strong logical coupling, so what we need to really rethink is whether the sub-services that need to use transactions to maintain data consistency should belong to the same service. Of course, we can draw on some of the practices of NoSQL databases in some way. For example, after a service has updated data, we use an asynchronous mechanism to maintain the consistency of the data, as if many NoSQL databases do not guarantee that the user's data is immediately readable.
Another common trouble is the problem of grain size. As we have said earlier, the efficiency of inter-service calls between the various sub-services of Microservice is very low. To reduce the number of inter-service calls, the granularity of the APIs provided by each sub-service needs to be as coarse as possible, but it needs to remain as flexible as possible. The best thing to do is to get all the information you want with a single service transfer.
Project Management
In addition to the range of technical factors discussed above, the development of the Microservice architecture model also has a series of project management challenges.
First, because the various sub-services in the Microservice architecture pattern may have different technology constructs, such as some sub-services are developed by Java, some are developed by Python, and they are not the same servlet containers, As a result, applications built by the Microservice architecture model may require very complex environment settings. This is a very difficult task for the traditional ops people. The developer responsible for the development of each sub-service is the expert on the operation and deployment of the service, relative to these operations personnel. As a result, the responsibilities for development and operations have changed in the Microservice Architecture model: Developers need not only be responsible for the preparation of child Service code, but also to consider the daily operations of the sub-service. OPS personnel need to give developers some operations-related advice, and in the overall direction to control the daily operation of the product.
The advantage of this is that the developer will have direct access to the production environment, can quickly track and solve the problem, and no longer need to pass through the customer and operations personnel reporting and other steps to start dealing with the problem, but also avoid the error in the reporting process. In addition, developers can more clearly understand how users are using the products they create, and create sub-services that are easier to use and manage.
But this can also lead to some difficulties in project management. First, both developers and managers need to understand and address a range of operations-related issues. This distracts their attention and makes development less efficient. Second, because a sub-service often contains a number of tasks related to front end, background, database, test, and even operations, the sub-service developers often need to understand most of the components of service development. This talent in the Chinese market is not uncommon, and therefore more sought-after. And because a developer needs to be exposed to too many features and techniques, there is often no way to delve deeper into them. The problem is that software developers spend more time analyzing and resolving problems when they encounter more difficult problems. If the problem is more serious, it will seriously affect the development progress of the entire group. In terms of project management, this is actually a very dangerous thing.
An ideal solution is to have an expert on each technology used by the current sub-service. But an all-stack developer, who also needs to be a technical expert on one hand, can imagine the cost of hiring that person.
In addition, we need to use a series of standardized development and testing processes when developing in accordance with the Microservice architecture model. The most natural fit with Microservice is now the most popular continuous Delivery, or known as DevOps. With the help of these automated processes, software developers can quickly complete an iteration: Once the code has been changed, the software developer can start compiling their own changes directly, running unit tests and functional tests. Next, the system will automatically deploy the code that was just compiled and perform integration testing across the system. After the integration test is complete, the quality manager or software developer will perform a single test on the system and perform a complex performance test after the test is completed and deployed after the performance test.
All of this is actually similar to the process used when using monolith development. The only difference is that this automated process becomes more important in development based on the Microservice architecture pattern. Because applications based on the Microservice architecture pattern often use different logic, deploying a complete environment can become very complex. Therefore, the deployment of these automated processes to the test environment greatly reduces the burden on software developers and is the basis for improving the productivity of software developers.
And because software developers need to execute application deployment at any time to test the changes they have just made, they need to be able to allocate the resources they need at any time, such as the compute resources, memory, and storage needed to deploy the application. This function is what the cloud business model provides. So when developing applications based on the Microservice architecture model, we try to carry out our ongoing development process based on certain clouds.
Microservice Implement
In this section, we will explain some of the methods that are commonly used to implement Microservice schema patterns.
The first question for everyone is, how should each sub-service in the Microservice architecture model work together to provide services to users? As we explained above, each sub-service in the Microservice architecture pattern should be independent, otherwise they will have a couple of problems: these sub-services are not independent of each other, need to use distributed transactions to maintain their data consistency, sub-service is not easy to reuse and so on. But if these sub-services are absolutely independent and do not even contain a little bit of logical coupling, they will not be able to collaborate. So the question that often arises in forum discussions is, where can there be coupling between these sub-services? What degree of coupling can occur?
The problem is actually very simple, that is, the UI. We know that there is some degree of coupling between the server and the client in a BS service. Both communicate through the APIs exposed by the service. Services based on the Microservice architecture pattern are no exception:
Since the UI running in the user's browser needs to interact with other sub-services, it can be used as a mediator to complete the interaction between the various sub-services. For example, when the product page is displayed, the page logic sends a request to the product service and the inventory service in parallel to obtain the product details and the current inventory of the product.
Therefore, in a service based on the Microservice architecture pattern, a front-end service is often present. The pages provided by the service communicate with each service. But it actually does not require communication with each sub-service:
You might say that in this case, there is no UI for each of our sub-services. The UI service not only needs to handle all the front-end business logic, but it may become another behemoth over time. In addition, if you want the entire platform to allow access to third-party services, this packaged UI service will become an obstacle to the overall platform extensibility.
Yes. If you need to solve this problem, then you need to try to learn from the service locator mode in your application. What we need at this point is a UI framework that allows the user to insert the UI provided by each child service in a particular way in the app, and allows you to discover a mechanism that has a specific feature-based API registered in the platform and allows you to invoke that API. I believe that as the Microservice architecture pattern continues to evolve, there will be more and more UI class libraries that support this extension.
The other pattern is message Broker. Simply put, message Broker is a transit platform for messages. The platform allows other components to register messages and allow other components to listen for messages. When a component is sent over a message broker, the other components that listen to the message update their state based on the information contained in the message.
Conversely, if your service needs to support mobile devices such as mobile phones, ipads, etc., we cannot allow these mobile devices to access sub-services one by one. This is because the bandwidth of these mobile devices is generally very small, and the user is often in a place where the signals are not very good, so sending requests to these sub-services one by one will quickly consume the limited bandwidth they have. In order to solve this problem, we often need to build a proxy service before these sub-services. The Proxy service splits the user request into requests for individual sub-services based on the business logic and summarizes the results returned by each sub-service as a response back to the user:
Of course, what is described above is only one of the most often mentioned in the current discussion of the forum to build an application based on the Microservice architecture pattern. Perhaps in the near future, you will see a variety of patterns that are designed to be more sophisticated.
After explaining how these sub-services should be presented to the user, let's explain how to create the public services required for each sub-service. As we have mentioned before, because a call to a public service is a cross-process call, it is inefficient compared to in-process calls. In this case, we need to avoid repeated calls to the public service as much as possible. To achieve this goal, we need to try to get the user to access the same child service instance and cache the information from the public service in that user's session.
So on each service instance of the same sub-service, we need to use the function of the sticky session of the load balancing service as much as possible and obtain a number of information in a public service invocation. For example, when viewing a user's permissions, we are not returning whether the user has specific permissions, but what permissions the user has. Of course, this not only needs to be considered from the aspect of Microservice architecture pattern, but also needs to take into account a series of problems such as security and maintainability.
To put it simply, we need to make the public service API more granular in terms of the other aspects, while also requiring some flexibility to avoid performance bottlenecks across services by reducing inter-service calls.
Now that we're talking about the granularity of the API, we need to talk about the APIs provided by each sub-service. As with public services, the APIs exposed by each sub-service should also have a coarser granularity and greater flexibility. In addition, we need to make the APIs exposed by these sub-services have the same style as possible, such as defining a series of restful APIs. In this case, the composition of the interaction with these services, such as the UI of the Web page, is acceptable for maintainability.
An empirical view is that the "open" in the Microservice architecture pattern is the internal implementation of each service, and the "closed" is the way in which each service communicates with each other.
If you need to build a service from scratch, you need to first consider how to partition these services, and start building the first service with a prototype of the various public services, and identify the protocols that are required to communicate between the services. As more and more sub-services are created, you need to gradually enrich the functionality provided by the various public services to become powerful, reusable services.
If you already have a monolith service and want to mitigate a range of issues with the current Monolith mode service by adopting the Microservice architecture pattern, you first need to create a separate service, and interact with the Monolith service through an adhesive layer. In this process, you may need to gradually expose the internal interface of the Monolith service for use by this new service. And this is the process of abstracting public services.
Next, you'll need to gradually peel off the public services in the Monolith service based on the interface you got in the previous step. In the stripping process, you need to remember a word in mind: coarse-grained, flexible API. And what the internal implementation really is, does not actually affect your peeling results.
Finally, the other service is stripped from the monolith. At this point, the most we need to consider is the service in the distinctive features of the various services, such as the requirements of resources and the entire Monolith service, or the use of and monolith difficult to compatible with the technology.
The last case is multiple service integration scenarios. In the gradual iterative process of products, we often encounter the need to integrate multiple products into a product to improve the overall competitiveness of the situation. This often occurs between profitable products and other non-profit products. This is the perfect opportunity to practice microservice architecture patterns. At this point we just need to expose the interfaces in a series of monolith services and create glue layers.
Microservice the advantages and disadvantages
Well, we've already covered a lot of empirical methods and knowledge about Microservice architecture patterns in the front. Well, let's review the range of strengths and weaknesses that Microservice has, so that you can fully measure the benefits and difficulties that the program can achieve before adopting the Microservice architecture model.
First, because each sub-service in the Microservice schema pattern can be executed independently of other services, it often has a better service boundary. This explicit service boundary brings a number of benefits: in the Microservice architecture pattern, the business logic required for each sub-service execution is relatively concentrated within the sub-service. The implementation code is therefore relatively easy to understand and easy to maintain. In addition, the structure, running flow and data model of each sub-service can be more close to the business logic represented by sub-service, so the development speed and maintainability of the code are greatly enhanced. At the same time, each sub-service can choose the most suitable technology to implement the business logic, which makes the development of each service easier. At the same time, in the advent of new and more suitable technology, we can easily replace the original implementation technology within each sub-service.
Independence also means increased scalability. In the Microservice architecture mode, each sub-service can be scaled independently according to its own load, such as scale-up or scale-out. Not only that, we can also prepare specific hardware devices for them to run on a more appropriate server, depending on the nature of the sub-service itself. At the same time, this independence can make each sub-service can be reused.
At the same time, this independence can also increase the fault tolerance of the whole service. For example, if a sub-service cannot continue to serve for a variety of reasons, other sub-services can still handle the user's request independently.
In addition, the independent deployment capability of each sub-service can greatly improve the operational efficiency of continuous delivery. After all, in this case, the software developer just needs to redeploy the changed sub-service.
Because each sub-service in the Microservice schema pattern is smaller than the monolith architecture in terms of both code volume and the resulting war package, there is a considerable advantage in IDE support for boot speed. At the same time, this small-granularity service can be done by a group of several people, without the need to collaborate with different teams from around the world, thus greatly reducing the cost of communication and improving the efficiency of development.
In turn, however, the independence of each sub-service in the Microservice architecture pattern can also lead to a series of problems. The most obvious is the need for more sub-services to cooperate with each other situation. Because these sub-services are different processes, maintaining data consistency between these processes, or adding a new user use case that spans the child service, is actually a very cumbersome task. and testing for the ability of these standalone services to work across the system requires a lot of integration testing to run. And if you need to quickly develop and iterate on these sub-services, then we need every developer to be able to use a range of automated tools professionally and efficiently. This is actually a not-so-low requirement.
In addition, based on performance considerations, the interfaces provided by each sub-service will be coarse-grained, but with a high degree of flexibility in the API. But this API has a more obvious flaw, that is, the more flexible the API, the more difficult it is to use. Therefore, for the users of the service, the difficulty of getting started is relatively increased.
In addition, how to standardize the communication protocol between each sub-service is also a very challenging thing. Because in Microservice schema mode, we often need to create a series of public services. These public services often expose a particular style of interface for other services to invoke. Therefore, we need to maintain consistency on these interfaces in order to be able to write the internal logic of each sub-service more naturally and expose the appropriate interfaces. But in turn, consistent interface styles often lead to a compromise of these standards by the natural implementation of individual services. So we often need to strike a balance between the two.
These balancing methods include standardizing the interfaces exposed by each service, integrating the child services in several fixed ways, and maintaining consistency in the format of the data model. These are, in fact, obstacles to our free preparation of individual sub-services. How strict a specification is actually required is done through experience accumulation, so this greatly increases the probability of failure using the Microservice schema pattern.
Reprint please specify the original address and marked reprint: http://www.cnblogs.com/loveis715/p/4644266.html
Commercial reprint please contact me in advance: silverfox715@sina.com