{"id":31124,"date":"2019-10-31T21:39:36","date_gmt":"2019-10-31T18:39:36","guid":{"rendered":"https:\/\/prohoster.info\/blog\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie\/"},"modified":"2019-10-31T21:39:36","modified_gmt":"2019-10-31T18:39:36","slug":"stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","title":{"rendered":"Building Blocks of Distributed Applications. A Second Approach","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Announcement<\/strong><\/p>\n<p><\/p>\n<p><em>Colleagues, I plan to release another series of articles on the design of mass service systems in mid-summer: \"Experiment VTrade\" \u2014 an attempt to write a framework for trading systems. The series will cover the theory and practice of building an exchange, auction, and store. At the end of the article, I invite you to vote for the topics that interest you the most.<br \/>\n<\/em><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Building Blocks of Distributed Applications. A Second Approach\" src=\"\/wp-content\/uploads\/2019\/04\/358996733e805327b587176f4f992aea.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>This is the concluding article in the series on distributed reactive applications in Erlang\/Elixir. In <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446028\/\">first article)<\/a><\/noindex> you can find the theoretical foundations of reactive architecture. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446108\/\">The second article<\/a><\/noindex> illustrates the main patterns and mechanisms for building such systems.<\/p>\n<p><\/p>\n<p>Today, we will raise questions about the development of the codebase and the projects as a whole. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"organizaciya-servisov\">Service Organization<\/h2>\n<p><\/p>\n<p>In real life, when developing a service, it is often necessary to combine several interaction patterns in one controller. For example, the users service, which handles user profile management tasks for the project, should respond to req-resp requests and notify about profile updates via pub-sub. This case is quite simple: there is one controller behind messaging, implementing the service logic and publishing updates.<\/p>\n<p><\/p>\n<p>The situation becomes more complicated when we need to implement a fault-tolerant distributed service. Let\u2019s imagine that the requirements for users have changed: <\/p>\n<p><\/p>\n<ol>\n<li>now the service must handle requests on 5 nodes in the cluster, <\/li>\n<li>be capable of performing background processing tasks, <\/li>\n<li>and also be able to dynamically manage subscription lists for profile updates.<\/li>\n<\/ol>\n<p><\/p>\n<p><em>Note:<\/em> We are not addressing the issue of consistent data storage and replication. Let\u2019s assume that these issues were resolved earlier, and there already exists a reliable and scalable storage layer in the system, and handlers have mechanisms for interacting with it.<\/p>\n<p><\/p>\n<p>The formal description of the users service has become more complicated. From a programmer\u2019s perspective, due to the use of messaging, changes are minimal. To meet the first requirement, we need to set up load balancing at the req-resp exchange point. <\/p>\n<p><\/p>\n<p>The need for processing background tasks often arises. In users, this may include verifying user documents, processing uploaded multimedia, or syncing data with social networks. These tasks need to be distributed within the cluster and monitored for progress. Therefore, we have two options: either use the task distribution template from the previous article, or, if it doesn't fit, write a custom task scheduler that will manage the pool of handlers in the necessary way. <\/p>\n<p><\/p>\n<p>Point 3 requires extending the pub-sub template. To implement this, after creating the pub-sub exchange point, we need to additionally launch the controller of this point within our service. Thus, we essentially extract the logic of subscription and unsubscription handling from the messaging layer to the implementation in users.<\/p>\n<p><\/p>\n<p>As a result, the decomposition of the task showed that in order to meet the requirements, we need to start 5 instances of the service on different nodes and create an additional entity \u2013 a pub-sub controller responsible for subscriptions.<br \/>\nLaunching 5 handlers does not require changing the service code. The only additional action is configuring the load balancing rules at the exchange point, which we will discuss shortly.<br \/>\nAdditionally, there is a further complication: the pub-sub controller and the custom task scheduler must operate as a single instance. Again, the messaging service, being fundamental, must provide a leader selection mechanism.<\/p>\n<p><\/p>\n<h3 id=\"vybor-lidera\">Leader Selection<\/h3>\n<p><\/p>\n<p>In distributed systems, leader selection is the procedure for appointing a single process responsible for scheduling distributed processing of some load. <\/p>\n<p><\/p>\n<p>In systems resistant to centralization, universal algorithms and consensus-based algorithms, such as Paxos or Raft, are applied.<br \/>\nSince messaging acts as a broker and central element, it is aware of all the service controllers \u2013 candidates for leadership. Messaging can appoint a leader without conducting a vote.<\/p>\n<p><\/p>\n<p>All services receive a system message after starting up and connecting to the exchange point <code>#'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers}<\/code>. In the event that <code>LeaderPid<\/code> matches the <code>pid<\/code> current process, it is appointed as the leader, and the list <code>Servers<\/code> includes all nodes and their parameters.<br \/>\nWhen a new node is added and an active node is disabled in the cluster, all service controllers receive <code>#'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts}<\/code> and <code>#'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts}<\/code> respectively.<\/p>\n<p><\/p>\n<p>As a result, all components are aware of all changes, and there is guaranteed to be one leader in the cluster at all times.<\/p>\n<p><\/p>\n<h2 id=\"posredniki\">Mediators<\/h2>\n<p><\/p>\n<p>To implement complex distributed processing tasks and optimize existing architecture, it is convenient to use mediators.<br \/>\nTo avoid changing the service code and to handle additional processing, routing, or logging of messages, a proxy handler can be introduced in front of the service to manage all additional tasks.<\/p>\n<p><\/p>\n<p>A classic example of pub-sub optimization is a distributed application with a business core generating update events, such as a market price change, and an access layer \u2014 N servers providing a websocket API for web clients.<br \/>\nIf handled directly, client servicing would look like this:<\/p>\n<p><\/p>\n<ul>\n<li>the client establishes connections with the platform. On the server side, where traffic is terminated, a process is initiated to service this connection.<\/li>\n<li>within the servicing process, authorization and subscription to updates occur. The process calls the subscribe method for the topics.<\/li>\n<li>after the event is generated in the core, it is delivered to the processes servicing the connections.<\/li>\n<\/ul>\n<p><\/p>\n<p>Let\u2019s say we have 50,000 subscribers for the topic 'news'. Subscribers are evenly distributed across 5 servers. As a result, each update arriving at the exchange point would be replicated 50,000 times: 10,000 times on each server, according to the number of subscribers on it. Not a very efficient scheme, is it?<br \/>\nTo improve the situation, we introduce a proxy that has the same name as the exchange point. The global name registry should be able to return the nearest process by name; this is important.<\/p>\n<p><\/p>\n<p>We will run this proxy on the access layer servers, and all our websocket API servicing processes will subscribe to it instead of the original pub-sub exchange point in the core. The proxy subscribes to the core only in the case of unique subscriptions and replicates the incoming message to all its subscribers.<br \/>\nAs a result, there will be 5 messages sent between the core and access servers instead of 50,000.<\/p>\n<p><\/p>\n<h2 id=\"marshrutizaciya-i-balansirovka\">Routing and balancing<\/h2>\n<p><\/p>\n<h3 id=\"req-resp\">Req-Resp<\/h3>\n<p><\/p>\n<p>In the current implementation of messaging, there are 7 request distribution strategies:<\/p>\n<p><\/p>\n<ul>\n<li><code>default<\/code>The request is sent to all controllers.<\/li>\n<li><code>round-robin<\/code>Requests are iterated and distributed cyclically among controllers.<\/li>\n<li><code>consensus<\/code>Controllers servicing the service are divided into a leader and followers. Requests are sent only to the leader.<\/li>\n<li><code>consensus &amp; round-robin<\/code>There is a leader in the group, but requests are distributed among all members.<\/li>\n<li><code>sticky<\/code>A hash function is computed and assigned to a specific handler. Subsequent requests with this signature go to the same handler.<\/li>\n<li><code>sticky-fun<\/code>During the initialization of the exchange point, a hash calculation function is additionally passed for <code>sticky<\/code> balancing.<\/li>\n<li><code>fun<\/code>Similar to sticky-fun, but it additionally allows redirecting, rejecting, or preprocessing. <\/li>\n<\/ul>\n<p><\/p>\n<p>The distribution strategy is set at the initialization of the exchange point.<\/p>\n<p><\/p>\n<p>In addition to balancing, messaging allows tagging entities. Let's consider the types of tags in the system:<\/p>\n<p><\/p>\n<ul>\n<li>Connection tag. This allows us to understand through which connection events came. It is used when the controller process connects to one exchange point but with different routing keys. <\/li>\n<li>Service tag. This allows grouping handlers for one service and expanding routing and balancing capabilities. For the req-resp pattern, routing is linear. We send a request to the exchange point, and it then forwards it to the service. But if we need to split handlers into logical groups, the division is done using tags. When specifying a tag, the request will be directed to a specific group of controllers.<\/li>\n<li>Request tag. This allows distinguishing responses. Since our system is asynchronous, to process responses from the service, it's necessary to specify a RequestTag when sending a request. This way, we can understand which request's response has arrived.<\/li>\n<\/ul>\n<p><\/p>\n<h3 id=\"pub-sub\">Pub-sub<\/h3>\n<p><\/p>\n<p>For pub-sub, it's a bit simpler. We have an exchange point to which messages are published. The exchange point distributes messages among subscribers, who have subscribed to the routing keys they need (one could say this is similar to topics).<\/p>\n<p><\/p>\n<h2 id=\"masshtabiruemost-i-otkazoustoychivost\">Scalability and fault tolerance<\/h2>\n<p><\/p>\n<p>The overall scalability of the system depends on the degree of scalability of its layers and components:<\/p>\n<p><\/p>\n<ul>\n<li>Services scale by adding additional nodes with handlers of this service to the cluster. During practical operation, one can choose the optimal load balancing policy.<\/li>\n<li>The messaging service within a separate cluster generally scales either by offloading particularly busy exchange points to separate nodes in the cluster or by adding proxy processes to high-load areas of the cluster.<\/li>\n<li>The scalability of the entire system as a characteristic depends on the flexibility of the architecture and the ability to combine separate clusters into a single logical entity.<\/li>\n<\/ul>\n<p><\/p>\n<p>The simplicity and speed of scaling often determine the success of a project. Messaging in its current implementation grows alongside the application. Even if we lack a cluster of 50-60 machines, we can resort to federation. Unfortunately, the topic of federation is beyond the scope of this article.<\/p>\n<p><\/p>\n<h2 id=\"rezervirovanie\">Failover<\/h2>\n<p><\/p>\n<p>In our discussion of load balancing, we already talked about service controller redundancy. However, messaging must also be redundant. In the event of a node or machine failure, messaging must automatically recover, and in the shortest possible time.<\/p>\n<p><\/p>\n<p>In my projects, I use additional nodes that pick up the load in case of a failure. Erlang has a standard implementation of distributed mode for OTP applications. The Distributed mode handles recovery in case of failure by starting the crashed application on another pre-launched node. The process is transparent; after a failure, the application automatically moves to the failover node. More information about this functionality can be read. <noindex><a rel=\"nofollow\" href=\"http:\/\/erlang.org\/doc\/design_principles\/distributed_applications.html\">here<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"proizvoditelnost\">Performance<\/h2>\n<p><\/p>\n<p>Let's at least roughly compare the performance of RabbitMQ and our custom messaging.<br \/>\nI found <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.openstack.org\/developer\/performance-docs\/test_results\/mq\/rabbitmq\/cmsm\/index.html\">official results<\/a><\/noindex> of RabbitMQ testing from the OpenStack team.<\/p>\n<p><\/p>\n<p>In section 6.14.1.2.1.2.2 of the original document, the result of RPC CAST is presented:<br \/>\n<img decoding=\"async\" alt=\"Building Blocks of Distributed Applications. A Second Approach\" src=\"\/wp-content\/uploads\/2019\/04\/95f615d241d70a4523fe3c400179b8e6.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Preliminary, we will not make any additional settings to the OS kernel or Erlang VM. Testing conditions:<\/p>\n<p><\/p>\n<ul>\n<li>erl opts: +A1 +sbtu.<\/li>\n<li>The test within a single Erlang node runs on a laptop with an old mobile i7.<\/li>\n<li>Cluster tests are conducted on servers with a 10G network.<\/li>\n<li>The code runs in Docker containers. The network is in NAT mode.<\/li>\n<\/ul>\n<p><\/p>\n<p>Test code:<\/p>\n<p><\/p>\n<pre><code class=\"erlang\">req_resp_bench(_) -&gt;\n  W = perftest:comprehensive(10000,\n    fun() -&gt;\n      messaging:request(?EXCHANGE, default, ping, self()),\n      receive\n        #'$msg'{message = pong} -&gt; ok\n      after 5000 -&gt;\n        throw(timeout)\n      end\n    end\n  ),\n  true = lists:any(fun(E) -&gt; E &gt;= 30000 end, W),\n  ok.<\/code><\/pre>\n<p><\/p>\n<p><em>Scenario 1:<\/em> The test is run on a laptop with an old mobile i7 processor. The test, messaging, and service are running on the same node in a single docker container:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Sequential 10000 cycles in ~0 seconds (26987 cycles\/s)\nSequential 20000 cycles in ~1 seconds (26915 cycles\/s)\nSequential 100000 cycles in ~4 seconds (26957 cycles\/s)\nParallel 2 100000 cycles in ~2 seconds (44240 cycles\/s)\nParallel 4 100000 cycles in ~2 seconds (53459 cycles\/s)\nParallel 10 100000 cycles in ~2 seconds (52283 cycles\/s)\nParallel 100 100000 cycles in ~3 seconds (49317 cycles\/s)<\/code><\/pre>\n<p><\/p>\n<p><em>Scenario 2<\/em>: 3 nodes running on different machines under docker (NAT).<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">Sequential 10000 cycles in ~1 seconds (8684 cycles\/s)\nSequential 20000 cycles in ~2 seconds (8424 cycles\/s)\nSequential 100000 cycles in ~12 seconds (8655 cycles\/s)\nParallel 2 100000 cycles in ~7 seconds (15160 cycles\/s)\nParallel 4 100000 cycles in ~5 seconds (19133 cycles\/s)\nParallel 10 100000 cycles in ~4 seconds (24399 cycles\/s)\nParallel 100 100000 cycles in ~3 seconds (34517 cycles\/s)<\/code><\/pre>\n<p><\/p>\n<p>In all cases, CPU utilization did not exceed 250%<\/p>\n<p><\/p>\n<h2 id=\"itogi\">Summary<\/h2>\n<p><\/p>\n<p>I hope this cycle does not come off as a stream of consciousness and that my experience will provide real value to both researchers in distributed systems and practitioners who are at the beginning of their journey in building distributed architectures for their business systems, especially those who are interested in Erlang\/Elixir but are uncertain whether it is worth pursuing...<\/p>\n<p><\/p>\n<p>Photo <noindex><a rel=\"nofollow\" href=\"https:\/\/unsplash.com\/photos\/Q4bmoSPJM18\">@chuttersnap<\/a><\/noindex><\/p>\n<p class=\"for_users_only_msg\">Only registered users can participate in the survey. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Please log in<\/a><\/noindex>, please.<\/p>\n<h2 class=\"default-block__polling-title\">What topics should I cover in greater detail within the 'VTrade Experiment' cycle?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Theory: Markets, orders, and their timeframes: DAY, GTD, GTC, IOC, FOK, MOO, MOC, LOO, LOC<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Order book. Theory and practice of implementing the book with groupings<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Trading visualization: Ticks, bars, resolutions. How to store and how to correlate<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Back office. Planning and development. Staff monitoring and incident investigation<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    API. Let's discuss what interfaces are needed and how to implement them<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Data storage: PostgreSQL, Timescale, Tarantool in trading systems<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Reactivity in trading systems<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Other. I will write in the comments<\/p>\n<\/li>\n<\/ul>\n<p>    6 users voted. 4 users abstained.<br \/>\n<br \/>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/446344\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u0412 \u0446\u0438\u043a\u043b\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043d\u0430 \u0442\u0435\u043e\u0440\u0438\u044f \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0431\u0438\u0440\u0436\u0438, \u0430\u0443\u043a\u0446\u0438\u043e\u043d\u0430 \u0438 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430. \u0412 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u0442\u044c \u0437\u0430 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0432\u0430\u043c \u0442\u0435\u043c\u044b. \u042d\u0442\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0446\u0438\u043a\u043b\u0430 \u043f\u043e \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":23092,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-31124","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0421\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0412\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:39:36+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:39:36+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Building blocks of distributed applications. Second approximation | ProHoster","description":"Announcement Colleagues, in mid-summer I plan to release another cycle of articles on the design of mass service systems: \"VTrade Experiment\" \u2014 an attempt to write a framework for trading.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0421\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0412\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435 | ProHoster","og:description":"\u0410\u043d\u043e\u043d\u0441 \u041a\u043e\u043b\u043b\u0435\u0433\u0438, \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043b\u0435\u0442\u0430 \u044f \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u044e \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u0446\u0438\u043a\u043b \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0441\u0438\u0441\u0442\u0435\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u044f: \u201c\u042d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442 VTrade\u201d \u2014 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0445.","og:url":"https:\/\/prohoster.info\/en\/blog\/administrirovanie\/stroitelnye-bloki-raspredelennyh-prilozhenij-vtoroe-priblizhenie","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:39:36+00:00","article:modified_time":"2019-10-31T18:39:36+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"31124","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 04:39:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:22:34","updated":"2026-01-21 04:39:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/31124","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=31124"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/31124\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/23092"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=31124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=31124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=31124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}