
Distributed systems. Design patterns. Book Review
- Transfer
Hello colleagues. Today we publish a translation of the next review from Ben Neidel's site - this site will certainly be of interest to you in the original. This time we’ll talk about the book “ Distributed Systems. Design Patterns ”, which complements the book “ Master Kubernetes ” that was published at the beginning of this year and, in essence, is an analogue of GoF for the design of distributed systems.

Enjoy reading.
Over the weekend, I read the book Distributed Systems. Design Patterns, by Brendan Burns. I really liked the book, although, I must admit, I expected to find a little different material in it. So, in the description of the book containers are mentioned only in passing. At the same time, although the patterns described in the book are applicable not only for containerization, almost all the patterns described here are given in the container context, and after that they are considered in the Kubernetes deployment pipeline. It turned out by the way. I am just starting to get acquainted with container-oriented development and deployment, and discussing architectural patterns from such a “container” point of view was a revelation to me. This approach helped me to get a good understanding of how in the microservice landscape small services are correctly distinguished, each of which has a specific opportunity.
The author of the book, Brendan Burns, is the co-founder of the open source project Kubernetes. Therefore, it is not surprising that all of its application examples are built around the deployment of containers based on Kubernetes configuration files. At the time of reading the book, I was a little versed in Docker and knew nothing about Kubernetes. Thus, I tried to figure out the “purpose” of Kubernetes configuration files by simply reading them. However, I believe that the book will be more useful if the reader has at least some experience with Kubernetes.
Reading the book, I could not get rid of the associations with the work " Integration Templates for Enterprise Applications»Gregor Hope and Bobby Wolfe. Many of the patterns discussed by Burns are very similar to the message queue patterns discussed by Hope and Wolfe. In fact, I must say that many patterns are even referred to in both books the same way (for example, Scatter / Gather). This is logical, since the theme of both books is the partition of complex monolithic systems into a set of small, tightly tailored reusable services. I think it can even be argued that Burns outlines specific approaches that will be useful in implementing the Producer services and Consumer services involved in the functioning of message-based workflows, the same ones that are described in the book “Enterprise Application Integration Templates”.
Again, I believe that the parallels traced between these two books testify to the power of design patterns. Both in how well they lead us to proven solutions, and in the fact that design patterns facilitate technical communication, as they allow us to reason in a common language.
At the same time, one of the approaches I liked most is described in the book “Distributed Systems. Design Patterns ”is precisely related to the consumption of the message queue. Burns advises not to force the work container to pull messages directly from the system (similar to how it is done in Amazon's Simple Queue Service (SQS) system), but to create an “ambassador” (Ambassador pattern). Such an “ambassador” container will be deployed along with the working container and provide a generalized API for manipulating queues. The Ambassador container allows you to abstract implementation details related to the permanent storage of elements in the message queue, so that the working container is completely independent of any specific technological solutions.
“The Ambassador of the Container-Source of the Work Queue” is just one example from a cross-cutting topic that runs through the book as a red thread: use sets of small containers so that each individual container can focus as much as possible on a specific task and turn out to be as reusable as possible. Burns explores this concept at the individual container level, talking about parameterizing containers using command line arguments and environment variables. Then he goes up one level, talks about the multi-container side-car and ambassador patterns in a single-node context. Finally, he shows how to create a powerful microservice architecture using multi-container patterns.
I think that Burns was able to perfectly articulate the "dream" of the entire microservice landscape:
(p. 79-80 in Russian translation)
I am talking about a "dream" because, as Burns himself admits, it is difficult to design a microservice system and design its architecture. And monitoring and debugging such a system is much more complicated than monitoring and debugging a monolithic analogue. Just with this I can easily agree. According to my own limited experience working with microservices, I confirm that shared services quickly become highly connected, and “reliable contracts” between services quickly turn into a moving target, undergoing more and more new changes.
In conclusion, I would like to touch on the FaaS concept - “functions as services”. Systems like Amazon's Lambda Service make me feel mixed. In an extremely abstract sense, I like such systems, but I have no idea how they manifest themselves in a particular application. Burns touches on FaaS in Part II on “Patterns of Designing Serving Systems,” but unfortunately it doesn’t fully clarify the Faas problem for me.
I really liked that Burns recommends using FaaS to solve only a subset of the known issues:
(p. 135 in Russian translation)
Moreover, many thanks to him for mentioning the difficulties that arise when using FaaS:
(p. 136-137 in Russian translation)
Again, I was surprised by the fact that most FaaS systems are not too good for solving problems that require active processing:
(p. 139-140 in the Russian translation)
As a result, I still did not understand: when is it better to use “functions as services”? I note that Burns briefly describes working with event-oriented short-term tasks that do not load the processor much, such as two-factor authentication (2FA). However, given that we are talking about small short-term tasks with low costs, the question arises: why should they be scaled independently? Why not just include these features in another container service that is closely related to the first?
I hope to better deal with these issues when I get to using FaaS technologies in practice.
Apart from some confusion with FaaS, I really liked the book. It is read quickly, easily perceived. It once again reminds us of the enormous potential of weakening the connection between components at all levels of application development. Finally, it will now be much easier for me to keep up a conversation with my colleagues on topics such as “Sidecar containers.”

Enjoy reading.
Over the weekend, I read the book Distributed Systems. Design Patterns, by Brendan Burns. I really liked the book, although, I must admit, I expected to find a little different material in it. So, in the description of the book containers are mentioned only in passing. At the same time, although the patterns described in the book are applicable not only for containerization, almost all the patterns described here are given in the container context, and after that they are considered in the Kubernetes deployment pipeline. It turned out by the way. I am just starting to get acquainted with container-oriented development and deployment, and discussing architectural patterns from such a “container” point of view was a revelation to me. This approach helped me to get a good understanding of how in the microservice landscape small services are correctly distinguished, each of which has a specific opportunity.
The author of the book, Brendan Burns, is the co-founder of the open source project Kubernetes. Therefore, it is not surprising that all of its application examples are built around the deployment of containers based on Kubernetes configuration files. At the time of reading the book, I was a little versed in Docker and knew nothing about Kubernetes. Thus, I tried to figure out the “purpose” of Kubernetes configuration files by simply reading them. However, I believe that the book will be more useful if the reader has at least some experience with Kubernetes.
Reading the book, I could not get rid of the associations with the work " Integration Templates for Enterprise Applications»Gregor Hope and Bobby Wolfe. Many of the patterns discussed by Burns are very similar to the message queue patterns discussed by Hope and Wolfe. In fact, I must say that many patterns are even referred to in both books the same way (for example, Scatter / Gather). This is logical, since the theme of both books is the partition of complex monolithic systems into a set of small, tightly tailored reusable services. I think it can even be argued that Burns outlines specific approaches that will be useful in implementing the Producer services and Consumer services involved in the functioning of message-based workflows, the same ones that are described in the book “Enterprise Application Integration Templates”.
Again, I believe that the parallels traced between these two books testify to the power of design patterns. Both in how well they lead us to proven solutions, and in the fact that design patterns facilitate technical communication, as they allow us to reason in a common language.
At the same time, one of the approaches I liked most is described in the book “Distributed Systems. Design Patterns ”is precisely related to the consumption of the message queue. Burns advises not to force the work container to pull messages directly from the system (similar to how it is done in Amazon's Simple Queue Service (SQS) system), but to create an “ambassador” (Ambassador pattern). Such an “ambassador” container will be deployed along with the working container and provide a generalized API for manipulating queues. The Ambassador container allows you to abstract implementation details related to the permanent storage of elements in the message queue, so that the working container is completely independent of any specific technological solutions.
“The Ambassador of the Container-Source of the Work Queue” is just one example from a cross-cutting topic that runs through the book as a red thread: use sets of small containers so that each individual container can focus as much as possible on a specific task and turn out to be as reusable as possible. Burns explores this concept at the individual container level, talking about parameterizing containers using command line arguments and environment variables. Then he goes up one level, talks about the multi-container side-car and ambassador patterns in a single-node context. Finally, he shows how to create a powerful microservice architecture using multi-container patterns.
I think that Burns was able to perfectly articulate the "dream" of the entire microservice landscape:
The microservice approach has many advantages, many of which are related to reliability and flexibility. Microservices divide the application into small parts, each of which is responsible for the provision of a specific service. By narrowing the scope of services, each service is able to develop and maintain a team that can be fed with two pizzas.
Reducing the size of the team also reduces the cost of maintaining its activities.
In addition, the emergence of a formal interface between microservices weakens the interdependence of teams and establishes a reliable contract between services. Such a formal contract reduces the need for close synchronization of teams, since the team that provides the API understands the extent to which it is necessary to ensure compatibility, and the team that consumes the API can count on stable service without worrying about the details of implementing the consumed service. Such a decomposition allows teams to independently control the pace of development and the schedule for the release of new versions, which gives them the opportunity to iterate, thereby improving the service code.
Finally, dividing into microservices increases scalability. Since each component is allocated to a separate service, it can be scaled independently of the others
(p. 79-80 in Russian translation)
I am talking about a "dream" because, as Burns himself admits, it is difficult to design a microservice system and design its architecture. And monitoring and debugging such a system is much more complicated than monitoring and debugging a monolithic analogue. Just with this I can easily agree. According to my own limited experience working with microservices, I confirm that shared services quickly become highly connected, and “reliable contracts” between services quickly turn into a moving target, undergoing more and more new changes.
In conclusion, I would like to touch on the FaaS concept - “functions as services”. Systems like Amazon's Lambda Service make me feel mixed. In an extremely abstract sense, I like such systems, but I have no idea how they manifest themselves in a particular application. Burns touches on FaaS in Part II on “Patterns of Designing Serving Systems,” but unfortunately it doesn’t fully clarify the Faas problem for me.
I really liked that Burns recommends using FaaS to solve only a subset of the known issues:
As with other tools for developing distributed systems, you may want to use a particular solution (for example, event-oriented processing) as a universal tool. The truth is that a particular solution usually solves particular problems. In a certain context, it will prove to be a powerful tool, but pulling it by the ears to solve common problems creates complex, fragile architectures.
(p. 135 in Russian translation)
Moreover, many thanks to him for mentioning the difficulties that arise when using FaaS:
As mentioned in the previous section, system development using the FaaS approach forces you to make system components loosely coupled. Each function is independent by definition. All interaction is carried out over the network. Function instances do not have their own memory; therefore, they require shared storage to store state. Forced weakening of the connectivity of system elements can increase the flexibility and speed of service development, but at the same time can significantly complicate its support.
In particular, it is quite difficult to see the comprehensive structure of the service, to determine how the functions are integrated with each other, to understand what and why went wrong in the event of a failure. In addition, the query-oriented and serverless nature of functions means that some problems will be difficult to detect.
(p. 136-137 in Russian translation)
Again, I was surprised by the fact that most FaaS systems are not too good for solving problems that require active processing:
... in addition, due to serverless implementation of services, the execution time of a function instance is usually limited. This means that the FaaS approach is usually not suitable for applications that require lengthy background data processing. (P. 138 in Russian translation)
Finally, I was pleased with the remark that FaaS become economically inexpedient if it is impossible to ensure a long uninterrupted operation of the processor:
But if you have so many requests that the function is constantly active, you probably overpay for the number of processed requests .
... as the service grows, the number of processed requests grows to such a level that the processor is constantly busy processing them. At this point, the fee for the number of requests begins to become unprofitable. The cost per unit of CPU time of cloud virtual machines decreases as cores are added, as well as by reserving resources and discounts for long-term use. The cost of paying for the number of requests usually increases with the number of requests.
(p. 139-140 in the Russian translation)
As a result, I still did not understand: when is it better to use “functions as services”? I note that Burns briefly describes working with event-oriented short-term tasks that do not load the processor much, such as two-factor authentication (2FA). However, given that we are talking about small short-term tasks with low costs, the question arises: why should they be scaled independently? Why not just include these features in another container service that is closely related to the first?
I hope to better deal with these issues when I get to using FaaS technologies in practice.
Apart from some confusion with FaaS, I really liked the book. It is read quickly, easily perceived. It once again reminds us of the enormous potential of weakening the connection between components at all levels of application development. Finally, it will now be much easier for me to keep up a conversation with my colleagues on topics such as “Sidecar containers.”