Building blocks of distributed applications. Zero approximation

Building blocks of distributed applications. Zero approximation

The world does not stand still. Progress creates new technological challenges. In accordance with the changed requirements, the architecture of information systems should also evolve. Today we will talk about event-driven architecture, concurrency, concurrency, asynchrony, and how you can live peacefully with all this in Erlang.

Introduction

Depending on the size of the system being designed and the requirements for it, we, the developers, choose the way to exchange information in the system. In most cases, to organize the interaction of services, a scheme with a broker, for example, based on RabbitMQ or kafka, can be a working option. But sometimes the flow of events, SLA and the level of control over the system are such that ready-made messaging is not suitable for us. Of course, you can complicate the system a little by taking responsibility for the transport layer and cluster formation, for example using ZeroMQ or nanomsg. But if the system has enough bandwidth and capabilities of a standard Erlang cluster, then the issue of introducing an additional entity requires detailed study and economic justification.

The topic of reactive distributed applications is quite extensive. To keep within the format of the article, the subject of today's discussion will be only homogeneous environments built on the basis of Erlang / Elixir. The Erlang/OTP ecosystem allows you to implement a reactive architecture with the least effort. But in any case, we need a messaging layer.

Theoretical basis

Design begins with the definition of goals and constraints. The main goal is not in the area of ​​development for the sake of development. We need to get a secure and scalable tool on the basis of which we can create, and most importantly, develop modern applications of various levels: from single-server, serving a small audience, which can later develop into clusters of up to 50-60 nodes, ending with cluster federations. Thus, the main goal is to maximize profits by reducing the cost of developing and owning the final system.

We single out 4 main requirements for the final system:

  • Π‘event orientation.
    The system is always ready to let the flow of events through itself and perform the necessary actions;
  • Мscalability.
    Individual blocks can be scaled both vertically and horizontally. The entire system must be capable of infinite horizontal growth;
  • Оfail-safety.
    All layers and all services must be able to automatically fail over;
  • Π“guaranteed response time.
    Time is valuable and users should not wait too long.

Remember the old fairy tale about β€œThe little engine that could”, aka β€œThe little engine that could”? In order for the designed system to successfully leave the prototype stage and be progressive, its foundation must meet the minimum requirements SMOG.

To messaging as an infrastructure tool and the basis for all services, one more point is added: ease of use for programmers.

Event Oriented

For an application to grow from a single server to a cluster, its architecture must be loosely coupled. This requirement is met by the asynchronous model. In it, the sender and receiver take care of the information load of the message and do not worry about transmission and routing within the system.

Scalability

System scalability and efficiency stand side by side. Application components must be able to utilize all available resources. The more efficiently we can utilize capacity and the better our processing methods, the less money we spend on equipment.

Within a single machine, Erlang creates a highly competitive environment. The balance between concurrency and parallelism can be set by choosing the number of operating system threads available to the Erlang VM and the number of schedulers utilizing these threads.
Erlang processes are stateless and operate in non-blocking mode. This provides comparatively low latency and higher throughput than traditional block sync applications. The Erlang scheduler takes care of a fair distribution of CPU and IO, and the absence of blocking allows the application to respond even during peak loads or failures.

At the cluster level, the problem with recycling also exists. It is important that all machines in the cluster are evenly loaded, and the network is not overloaded. Imagine the situation: user traffic lands on incoming balancers (haproxy, nginx, etc), they distribute processing requests as evenly as possible between the set of available backends. Within the framework of the application, the service that implements the required interface is only the last mile and will need to request a number of other services in order to respond to the initial request. Internal requests also require routing and balancing.
To effectively manage data flows, messaging must provide developers with an interface to manage routing and load balancing. Thanks to this, developers will be able, using microservice patterns (aggregator, proxy, chain, branch, etc), to solve both standard tasks and rarely occurring ones.

From a business perspective, scalability is one of the risk management tools. The main thing is to satisfy the needs of customers, using the equipment optimally:

  • With the increase in equipment power as a result of progress. It will not be idle due to software imperfections. Erlang scales well vertically and will always be able to utilize all the CPU cores and available memory;
  • In cloud environments, we can manage the amount of equipment depending on the current or predicted load and guarantee SLA.

fault tolerance

Let's consider two axioms: "Rejections are unacceptable" and "Rejections will always be." For businesses, software failure is a loss of money, and worse, a loss of reputation. Balancing between possible losses and the cost of developing fault-tolerant software, a compromise can often be found.

In the short term, a fault-tolerant architecture saves money on buying ready-made clustering solutions. They are expensive, and they also have errors.
In the long term, a fault-tolerant architecture pays off many times over the costs of its use at all stages of development.
Messaging inside the code base at the development stage allows you to work out in detail the interaction of components within the system. This simplifies the task of responding and managing failures, since all critical components handle failures, and the resulting system knows how to automatically return to normal after a failure by design.

Responsiveness

Regardless of failures, the application must respond to requests and meet the SLA. The reality is that people do not want to wait, so the business must adjust accordingly. More and more applications are expected to be highly responsive.
Responsive apps run in near real time. Erlang VM operates in soft real time. For some areas, such as stock trading, medicine, industrial equipment management, hard real time is important.
Responsive systems improve UX and are good for business.

Preliminary result

While planning this article, I wanted to share my experience of creating a messaging broker and building complex systems based on it. But the theoretical and motivational part turned out to be quite extensive.
In the second part of the article, I will talk about the nuances of implementing exchange points, messaging patterns and their application.
In the third part, we will consider general issues of organizing services, routing and balancing. Let's talk about the practical side of scalability and fault tolerance of systems.

The end of the first part.

Photo @lucabravo.

Source: habr.com

Add a comment