Hands-On Docker for Microservices with Python
上QQ阅读APP看书,第一时间看更新

Preparing and adapting by measuring usage

Obviously, any real-world system will be more complicated than our example. There's a limit to what a code analysis can discover just by looking at it carefully, and plans often don't survive contact with the real world.

Any division needs to be validated to ensure that it will have the expected result and that the effort will be worth it. So double-check that the system is working the way you think it is working.

The ability to know how a live system is working is called observability. The main tools for it are metrics and logs. The problem you'll find is that they will normally be configured to reflect external requests and give no information about internal modules. We will talk about the observability of systems in depth in Chapter 10, Monitoring Logs and Metrics. You can refer to it for more information and apply the techniques described there at this stage.

If your system is a web service, by default, it will have activated its access log. This will log each HTTP request that comes into the system and store the URL, result, and time when it happens. Check with your team where these logs are located, as they will provide good information on what URLs are being called.

This analysis, though, will probably give only information about what the external endpoints being called are, but won't say much about internal modules that will be split into different microservices according to our plan. Remember that the most important element for the long-term success of the move to microservices is to allow teams to be independent. If you split across modules that constantly need to be changed in unison, deployments won't be truly independent, and, after the transition, you'll be forced to work with two tightly coupled services.

Be careful, in particular, about making a microservice that's a dependency for every other service. Unless the service is extremely stable, that will make frequent updates likely when any other service requires a new feature.

To verify that the new microservices won't be tightly coupled, make the teams aware of the divisions and how often they have to change the interfaces surrounding them. Monitor these changes for a few weeks to be sure that the division lines are stable and don't require constant change. If the interface between microservices is very actively being changed, any feature will require multiple changes in several services, and that will slow the pace of delivering new features.

In our example, after analyzing the proposed architecture, we decide to simplify the design, as shown in this diagram:

Some changes have been decided after monitoring and talking with the teams:

  1. The teams don't have good knowledge of JavaScript dynamic programming. The change to the frontend, at the same time as making the move to microservices, is seen as too risky.
  2. The external mobile application, on the other hand, is seen as a strategic move for the company, making the externally accessible API a desirable move.
  3. Analyzing the logs, it seems like the search functionality is not often used. The growth in the number of searches is small, and splitting search into its own service will require coordination with the Thoughts Backend, as it's an area of active development, with new fields being added. It is decided to keep search under the Thoughts Backend, as both work with the same thoughts.
  4. The Users Backend has been received well. It will allow improving the security of authentication by having clear ownership of who's responsible for patching security vulnerabilities and improving the services. The rest of the microservices will have to work independently with verification by the Users Backend, which means the team responsible for this microservice will need to create and maintain a package with information on how to validate a request.

Once we've decided on the final state, we still have to decide how are we going to move from one state to another.