Switch lang: Русский \ English

"Cloud Parallel Virtual machine - CPVM" Project


Терминология

  • Фрагмент (fragment) - фрагмент исполнямого кода. Можеть быть исходным кодом или скомпилированым бинарником.
  • Исполнитель (fragment executor) - некий програмный компонент, способный исполнять определенные типы фрагментов. Один исполнитель может одновременно брать на себя выполнение нескольких фрагментов.
  • Program order - порядок операций чтения и записи явным образом определнный в исходном коде фрагмента.
  • DAM (Data Access Marker) - последовтельность байтов неограниченного размера (теоритически), по которой можно однозначно установить program order. Лексикографически больший DAM означает более позднюю операцию чтения или записи.

Общая структура кластера

cluster

  • Aeron MediaDriver - локальный брокер сообщений (UDP, SHM)
  • CPVM node - компонент Runtime, основной связующий элемент системы. Каждый узел Runtime может выполнять 2 функции:
    • Application Server (AppServer) - реализация внешнего HTTP API
    • CPVM module - основная бизнес-логика системы: планировщик задач, управление воркерами, балансировка нагрузки, устранение кофнликтов TVM итд
  • CPVM worker - компонент Runtime, отвечающий за исполнение фрагментов
  • TVM - Transation Value Manager. "In memory" хранилище с определением "конфликтов" параллельного доступа. Инстансы TVM нужно размещать как можно ближе к нодам CPVM, т.к. между ними происходит синхронный (в пределах исполнения фрагмента) обмен данными. Задержки обмена сообщениями между CPVM и TVM - основная причина низкой производительности "транзакционных" фрагментов.
  • IO_service - слой stateless сервисов, вспомогательная система для TVM, которая выполняет IO операции. Выделен в отдельную сущность для масштабирования.
  • FragSeq (FragmentSequence) - обрабатывает отчеты TVM об обнаруженных зависимостях и формирует ЯПФ/LPF (ярусно-параллельная форма).
  • A_Storage - основное хранилище данных и метаинформации системы. Выполняет функции:
    • хранилище кода, фрагментов (CB - Code Base).
    • хранилище метаинформации для PTS
    • хранилище логов выполнения
    • хранилище структуры данных системы FragSeq - ЯПФ/LPF
    • хранилище информации для биллинга (PaaS).
    • информация фронтенда, требуемая LK (в личном кабинете)
  • Сonsul node - координация вышеперечисленных сервисов

Структура кластера Runtime

Кластер CPVM состоит из множества "CPVM node", попарно соединенных в произвольную топологию. Ограничений на количество связей между узлами нет, топология может и, скорее всего, должна быть полносвязной (балансировка нагрузки лучше всего работает в полносвязной топологии).
Узлы CPVM не имеют четко обозначеных "ролей", каждый узел может выполнять любой функционал из арсенала достпных модулей.

![cpvm master_quorum](/galleries/page_images/cpvm master_quorum.png)

Zero-downtime обновление кластера Runtime (vm5)

Требования: Reverse-proxy для группы AppServer как минимум один запущенный AppServer и еще одна произволная нода (c AppServer или без).

  1. Имеется запущенный кластер рантайма, где все узлы имеют старую версию. Лучшая стратегия - "канареечные" обновления, когда единовременно обновляется только часть кластера.
  2. Выбираем узлы для остановки. Помещаем на них бинарные файлы новой версии рантайма.
  3. Посылаем им команду POST /managment/update, указывая в параметрах путь к обновленной версии рантайма.
  4. Выбранные узлы перестают принимать новые задачи. Когда все задачи выполняются, runtime node запускает специальный процесс-updater и останавливает все свои процессы. Как только процесс-updater фиксирует полную остановку старой версии рантайма, он запускает новую, после чего завершается.
  5. Следить за ходом выполнения сего действа можно через GET /managment/status (указывается нужный nodeid).
  6. Ноды новых версий могут автоматически соединится с нодами старых версий (если адреса не поменялись), но почти никак не будут взаимодействовать если произошли изменения в протоколе. В Runtime нет такого понятия как "версия протокола", вместо этого есть автоматические "snapshot"-ы протокола rpc-интерфейсов (фича ajrpc2). Ноды не выясняют кто из них новее или старше, а просто детектируют частичную или полную несовместимость (неэквивалентность снапшотов) и отказываются взаимодейтсвовать. Это позволяет не поддерживать совместимость всех протоколов рантайма, и ломать схему взаимодействия при каждом обновлении без каких-либо последствий.
  7. Новые ноды рантайма гарантировано вступают в работу как только появляется хотя бы один AppServer новой версии.

Балансировка нагрузки

Нода получает задачу выполнить некоторую задачу (фрагмент). В процессе исполнения фрагмент может одновременно запускать множество других фрагментов. Если они требуют много ресурсов, нода отдаёт их другим узлам.

Алгоритм (10.2016)

Часть первая. Оперативное рапределение задач.

  1. Ноде дается задание выполнить фрагмент
  2. Если нода имеет свободные ресурсы, то фрагмент запускется локально.
  3. Если текущих ресурсов недостаточно для выполнения фрагмента, то выполняется перенаправление задачи на дргуие ноды. Если задачу перенаправить некуда, она складывается в локальную очередь. Важные моменты:
    • Определние требуемых ресурсов не учитывает предпологаемую нагрузку запускаемых фрагментов. С точки зрения рантайма они все равны.
    • Задачи перенапрваляются на ноды с наименьшей (с точки зрения текущей ноды) нагрузкой.

Часть вторая. Фоновое перераспредление задач по принципу work-stealing.

  1. Каждая нода рассылает своим соседям информацию о своей нагрузке (heartbeat). Интервал отправки heartbeat меняется в зависимости от нагрузки ноды, отправляющей этот heartbeat. Чем больше нагрука тем больше интервал.
  2. Если ноде приходит heartbeat, она сравнивает свою нагрузку с нагрузкой ноды, которая прислала heartbeat.
  3. Если нагрузка удаленной ноды меньше, то часть задач из локальной очереди перенаправляется на нее.
    • Количество перебрасываемых задач определяется по разнице суммы показателей:
      • количетсво запущенных задач
      • количество задач в очереди

Важные свойства

  • Нагрузка будет распределяться при любых топологиях
  • Нагрузка может рапределятся очень медленно в неполносвязных топологиях (зависит от того, на какую ноду ушла корневая задача).

Supervision

Для достижения отказоустойчивости Runtime применяет подход схожий с supervision (actors). Каждый узел являтся чьим-то "супервизором", в нашей терминологии - "родителем" (parent). Родительская нода поручает выполнение некой задачи (исполнение фрагмента) "исполнителю"/child-ноде. Любая нода одновременно может быть родителем и исполнителем для разных задач. Родитель следит за здоровьем узла-исполнителя, если тот умирает - перезапускает исполнение фрагмента на другом узле (поручает задачу другому узлу). Исполнитель не следит за здоровьем родителя. Если родтель оказывается недоступен в момент отправки ему результата, он просто отбрасывается.

Принцип работы покажем на простом примере:

  • Исполнитель теряет связь с родителем.
  • Родитель детектирует недоступность исполнителя и запускает задачу на другом узле.
  • Связь быстро восстановилась, старый исполнитель закончил выполнять задачу и отправил результат родителю.
  • Родитель приняв результат считает задачу завершенной, посылает сигнал на остановку всем исполнителям, которым он успел отправить ту же задачу.

В подобной ситуации корректность не теряется, т.к. есть возможность перезапускать фрагменты неограниченное количество раз. Такой подход открывает путь к спекулятивному retry, когда исполнитель может оптравить исполнение одной и той-же задачи на разные узлы, не дожидаясь отказа какого-то из них (жертвуем КПД кластера ради скорости). Каждая задача имеет уникальный в пределах всех кластеров идентификатор (transaction ID + стартовый DAM). Это позволяет принимать результаты выполнения задач от любых исполнителей, даже тех, которые не находятся в родственной связи с неким родителем (родителю просто плевать кто ее выполнил). В отдельных случаях это позволяет посылать результаты выполнения по любым доступным маршрутам:

  • Если был потерян прямой канал связи с родителем, есть вероятность, что существует "непрямой" канал связи.
  • Если родтель упал, родитель родителя перезапустил его задачу на другом узле, и этот другой узел уже отправил задачу на исполнение, то результат придет ему почти сразу.

При балансировке нагрузки, узлы, которых назначили исполнителями, могут быть слишком загружены на момент назначения, поэтому отдают задачу кому-то еще. При этом они уведомляют родителя, что более не являются исполнителем. Это уведомление может не дойти до родителя, и тогда у него будет устаревшая информация о том кто исполнитель. Родитель увидит недоступность этого "ненастоящего" исполнителя и попытается перезапустить задачу в другом месте - тут нас вновь выручает семантика системы, позволяющая перезапускать много и без ограничений и принимать результаты от кого угодно.

Failover

У всех узлов есть родитель?

В vm4 нет - там для слежения за здоровьем родителей форимруется родительский комитет из мнимум 3 узлов. Они реализуют выбор лидера (raft-like) и лидер становится "корневым" родителем. В процессе работы лидер может упасть, произойдут перевыборы и транзакция перезапустится.

В vm5 немного другая схема - там родители есть у всех. AppServer перед отправкой клиенту подтверждения о старте задачи формирует искусственное кольцо из родителей неограниченного размера (минимум 2).

cpvm_parent_ring

Worker API

TODO

Алгоритм запусков и перезапусков (08.2016)

Группы вызовов

Группа вызовов - синхронно исполняемая группа вызвов подфрагментов, внутри которой порядок исполнения определяется рантаймом.

Синхронность означает, что фрагмент, который запросил исполнение группы подфрагментов, не может продолжать исполнение, пока runtime не отчитается об успешном исполнении этой группы.

Объединяя вызовы подфрагментов в группы, фрагмент высказывает желание выполнить эту группу в одном ярусе. Реальные ярусы определяет runtime. Объединение фрагментов в группы позволяет устанавливать внутри фрагменов "точки отката". Иначе говоря, появляется возможность не перезапускать весь фрагмент целиком в случае конфликтов между подфрагментами, а перезапускать лишь ограниченный набор фрагментов внутри группы. Группы вызовов уменьшают потенциальный параллелизм, явно разделяя все множество асинхронных вызовов подфрагментов на ярусы.

Программист должен стараться делать так, чтобы группы удовлетворяли следующим условиям:

  • группа вызовов должна иметь большой потенциальный параллелизм
  • группы вызовов должны быть часто или обязательно конфликутющими, чтобы оправдать явное разделения на ярусы.

Фрагмент может вызвать другой фрагмент двумя спобобами:

  • call - синхронный вызвов. Равносилен запуску группы (яруса) из одного фрагмента.
  • call_async - асинхронный вызов. Реальный вызов подфрагмента может не произойти в момент вызова call_async(). На самом деле последовательные вызвовы call_async() формируют группу вызовов.

Группа вызвов считается завершенной и "сбрасывается" (отправляется рантайму на исполнение) если исполнение фрагмента достигает точки "сброса группы". Этой точкой может быть:

  • Явный вызвов исполнения группы: execute_async_group().
  • Любая операция tvm. Группа исполняется ДО выполнения операции.
  • Синхронный вызвов фрагмента: call(). Группа исполняется ДО вызова call.
  • Конец исполнения фрагмента.

Из этих правил следует вывод, что некторые фрагменты не могут исполнится параллельно, даже если они полностью независимы:

    call_async('f1')
    tvm_write('vid', 12345)
    call_async('f2')

Фрагменты f1, f2 никогда не будут исполнятся параллельно. Эту проблему можно решить отключением точек сброса перед любой tvm-операцией, но тогда будет существовать вероятность конфликта с родителем. Вполне вероятно, подобное поведение следует сделать опциональным для каждого фрагмента в отдельности.

Фрагменты внутри группы необязательно начнут исполнение именно в момент вызова execute_async_group():

  • Runtime может принять решение исполнять некоторые фрагменты группы, до того как сама группа окончательно сформируется (до момента вызова execute_async_group). Это может происходить в случае, если часть фраментов уже содержащихся в незаконченной группе образуют законченный ярус (предположительно). Логика определения законченного яруса по неполной группе не реализована, но теоритически возможна (планы).
  • Runtime может отложить исполнение группы фрагментов.

Жизненный цикл фрагмента

Завершенный фрагмент - это фрагмент, который runtime исключает из всех индексов исполняющихся фрагментов и рапортует инициатору исполнения о статусе завершения. Реальное исполнение фрагмента (исполнение кода) может продолжаться бесконечно (в случае исполнения внутри потоков). Фрагмент считается успешно завершенным только если успешно завершены все его подфрагменты, втч те которые исполняются асинхронно. Фрагмент завершается со статусом "CONFLICT" если произошел конфликт, который фрагмент не может разрулить самостоятельно. Это происходит только в случае конфликта одного из подфрагментов (втч глубоко вложенных) с фрагментом, исполняющимся вне ветки текущего фрагмента. В этом случае общая часть DAM конфликтующих фрагментов не будет совпадать с DAM текущего фрагмента.

Реальная остановка фрагмента (исполнение кода) может произойти если фрагмент вызвает любое системное API. В противном случае остановка может не случится вообще, если фрагмент завис и исполняется в потоке, а не в отдельном процессе.

При локальном запуске фрагмента (не путать с перезапуском!) нода делает следующее:

  • Создает задачу запуска фрагмента, по завершению которой, нода отчитывается инициатору запуска о результате выполнения фрагмента. Задача ассоциируется с ключом исполнения, который представляет собой пару (transactionId, dam). Ключ исполнения однозначно идентифицирует запущенный экземпляр фрагмента в пределах всего кластера.
  • Создает поток для исполнения фрагмента, передает ему параметры и привязывает его к только что созданной задаче.
  • Завершение исполнения потока фрагмента не озанчает что фрагмент завершился. Завершение фрагмента - это завершение задачи. Завершение исполнения потока означает, что наступает этап обработки результата исполнения экземпляра фрагмента. Если в процессе выполнения не возникло ошибок и конфликтов - задача завершается со статусом ОК.

Перезапуск фрагментов

Перезапуск инициируется только в случае когда один из подфрагментов завершился со статусом CONFLICT и текущий фрагент может разрулить конфликт самостоятельно (см. п. "Жизненный цикл фрагмента").

При конфликте в группе фрагмент делает tvm rollback для ветки фрагментов исполняющихся в текущей группе. Далее нода делает запрос на перезапуск группы фрагментов. При перезапуске группа фрагментов сохраняет натуральный порядок исполнения.

Возможная ситауция конфликта с родителем:

  • перезапускается root
  • фрагменты отчитавшиеся о выполнении OK перезапускаются заново

"Схема запуска"

Алгоритм перезапуска фрагмента
  1. Если ключ запуска не зарегестрирован в индексах текущих локальных задач, нода прокидывает просьбу о перезапуске той ноде, из которой пришел запрос на запуск текущего фрагмента, далее переход к шагу 1. В противном случае идем далее.
  2. Фрагменту посылается сигнал остановки.
  3. Экземпляр запущенного фрагмента отвязывается от текущей задачи.
  4. Запускается новый экземпляр фрагмента с новым DAM и привязывется к задаче.

Порядок запуска определяется с помощью:

  • FragSeq LPF - информация о допустимости выполнения в одном ярусе (ЯПФ)
  • частичного или полного отключения параллельности (call_async превращается в call). На первых этапах работы системы отсутствует информация о конфликтах и FragSeq будет выдавать неопределенный результат.

Типы исполнителей фрагмнетов (executor types)

Каждый фрагмент может поддерживать несколько типов исполнителей (задается в метаданных фрагмента):

  • LuaC (референсная реализация интерпретатора Lua 5.3)
  • LuaJit (высокопроизводительный трассирующий jit-компилятор Lua)
  • LuaJ (JVM-реализация Lua 5.1)
  • VmLuaJ (aналогично LuaJ, но запуск производится внутри процесса Runtime node)
  • CPython (референсная реализация интерпретатора Python 3.6)

InVm-исполнители (VmLuaJ) не могут исполнять недоверенные фрагменты (не прошедшие стадию PTS-верификации), т.к. запускаются без какой-либо изоляции и возможности экстренной остановки.

Характеристики производительности Lua-исполнителей:

Задержка запуска фрагмента, по возрастанию:

  • интерпретация в контексте JVM (LuaJ, disabled jit)
  • jit-based исполнение в контексте JVM (LuaJ, enabled jit)
  • интерпретация вне контеска JVM (LuaC)
  • jit-based исполнение вне контекста JVM (LuaJit)

Пропускная способность, по возрастанию:

  • (LuaJ, disabled jit) / LuaC. Требует замеров (предположительно, разница не существенна)
  • (LuaJ, enabled jit)
  • LuaJit

Запуск Runtime node и AppServer (vm4)

Пример запуска одного рантайма с включенным AppServer:

java \
-ea \
-jar runtime.jar \
-n $NODEID \
-h localhost \
-p 40124 \
--tag "test-node" \
--log FILE \
--cbtype KV \
--kv-address "localhost:10000" \
--luapath ./lua-libs \
--appserver "localhost:5678" \
--enable-test-user "true" \

Аргументы: "nodeid" (-n) - должен быть уникальным в пределах всего кластера. Без уникальности ноды с таким же id могут выйти из строя. "tag" - если задан, будет отображаться в логах для сообщений из основного event-loop ноды, в противном случае будет отображатся nodeId. "log" * FILE - вывод файл с автоматической ротацией (старые логи будут сжиматься в gz и ложится в logs/) * CONSOLE - вывод в консоль * CONSOLE_AND_FILE - все вместе "kv-address" - адреса KV-сервисов (CB, RuntimeStorage, Logs) "luapath" - если нужно подуснуть какие-то кастомные lua-библиотеки "appserver" - запуск AppServer на указанном адресе * "enable-test-user" - все AppServer-запросы без кук воспринимаются как запросы тестового пользователя "$TEST_USER"

Вывод после старта:

Спойлер (кликните для показа/скрытия)

    2017-08-29 07-58-29 [test-node]: CPVM 1.1.619 (82a273670fe87e105600269e7c3b70b144dbcb12) debug mode
    2017-08-29 07-58-29 [test-node]: ID = 161815
    2017-08-29 07-58-29 [test-node]: aeron: try launch embedded driver
    2017-08-29 07-58-29 [test-node]: aeron: active driver detected
    2017-08-29 07-58-29 [test-node]: aeron: IPC listen -> 105660
    2017-08-29 07-58-29 [test-node]: aeron: UDP listen -> 127.0.0.1:40124 / 105660
    2017-08-29 07-58-29 [test-node]: aeron: IPC listen -> 105670
    2017-08-29 07-58-29 [test-node]: aeron: UDP listen -> 127.0.0.1:40134 / 12
    2017-08-29 07-58-29 [test-node]: HTTP server started at http://127.0.0.1:5678/
    2017-08-29 07-58-29 [test-node]: HTTP routes:
        GET    /account/me/
        GET    /account/{otherUserId}
        POST   /auth/login
        POST   /auth/logout
        POST   /auth/signup
        GET    /cb/fragments
        POST   /cb/fragments/{frId}
        GET    /cb/fragments/{frId}/bytecode
        POST   /cb/fragments/{frId}/bytecode
        GET    /cb/fragments/{frId}/meta
        POST   /cb/fragments/{frId}/meta
        GET    /cb/fragments/{frId}/source
        POST   /cb/fragments/{frId}/source
        GET    /cb/users/{otherUserId}/fragments
        POST   /managment/setupTopology
        POST   /managment/terminate
        POST   /vm/start
        POST   /vm/stop
        GET    /vm/transactions/
        GET    /vm/transactions/{trId}/lpf/byFragment/{frId}
        GET    /vm/transactions/{trId}/statistics
        GET    /vm/transactions/{trId}/status
        GET    /vm/version
    2017-08-29 07-58-29 [test-node]: using KV codebase
    2017-08-29 07-58-29 [test-node]: optimal parallelism: 8
    2017-08-29 07-58-29 [test-node]: new remote interface: ru.acapella.runtime.api.internal.BaseNodeApi
    2017-08-29 07-58-29 [test-node]: new remote interface: ru.acapella.runtime.HeartbeatAPI
    2017-08-29 07-58-29 [test-node]: new remote interface: ru.acapella.runtime.api.internal.FragmentRunAPI
    2017-08-29 07-58-29 [test-node]: new remote interface: ru.acapella.runtime.FailoverApi
    2017-08-29 07-58-29 [test-node]: ready
    2017-08-29 07-58-29 [test-node]: aeron: try connect: ipc(75536)

Вывод HTTP server started at http://127.0.0.1:5678/ значит AppServer готов к работе.

  1. Если Runtime поднимается для теста можно использовать параметр --enable-test-user, который позволяет обращается ко всему API без авторизации.
  2. Иначе необходимо зарегистрировать пользвателя:
    curl -H "Content-Type: application/json" -d '{"username":"PainInTheAss","password":"33fnDF9unfwEFz1Fdsf87","email":"killthemall@gmail.com","firstName":"Max","lastName":"Payne"}' -X POST http://localhost:5678/auth/signup 
  1. Авторизация. В хедер Authorization ложим пароль в base64.
    curl -d "username=PainInTheAss" --header "Authorization: MzNmbkRGRjl1bmZ3RUZ6MUZkc2Y4Nw==" -X POST "http://localhost:5678/auth/login"

    {"token":"7b03fedaa44f4a5688f49edd7d285033"}
  1. Соединяем ноды с адресами "host:40124", "host:40125", "host:40126":
    curl -H "Content-Type: application/json" -d '[["host:40124", "host:40125"], ["host:40124", "host:40126"], ["host:40125", "host:40126"]]' -X POST http://localhost:5678/managment/setupTopology

В логах должно отобразится:

    2017-08-29 08-39-07 [node1]: connected to node2
    2017-08-29 08-39-07 [node1]: connected to node3

    2017-08-29 08-39-07 [node2]: connected to node1
    2017-08-29 08-39-08 [node2]: connected to node3

    2017-08-29 08-39-07 [node3]: connected to node1
    2017-08-29 08-39-08 [node3]: connected to node2
  1. Запуск простого фрагмента через cli-launcher.

TODO описание машины и фрагмента

Сначала запустим mult_root.lua с параметром 50 в "транзакционном" режиме, без параллельности, что соответсвует пресету "transactional":

    /usr/bin/python3.6 main.py --address localhost:5678 --fname mult_root --preset transactional
    Using 'transactional' preset
    Uploading 'mult_2_py'
    Uploading 'mult_2'
    Uploading 'mult_1_py'
    Uploading 'mult_root_py'
    Uploading 'mult_1'
    Uploading 'mult_root'
    Start fragment: mult_root
    Transaction started: 84ef24ca75849e6
    Transaction completed

    Execution time:
        Without overheads (worker):  43 ms
        Total (worker):              0:01:03.252343
        Total (node):                0:01:03.252890
    Transaction timestamps: 
        Start:          13:15:28.563000 [2017-08-30]
        End:            13:16:31.816000 [2017-08-30]
    Counters: 
        Total conflicts:   0
        Total restarts:    0
        Async calls:       0
        Sync calls:        71
        TVM reads:         690902
        TVM writes:        14703
    TVM traffic: 
        TVM bytes read:    1.01 MB
        TVM bytes write:   76.54 KB

Включим параллельность изменив пресет на "acapella":

    /usr/bin/python3.6 main.py --address localhost:5678 --fname mult_root --preset acapella
    Using 'acapella' preset
    Uploading 'mult_2_py'
    Uploading 'mult_2'
    Uploading 'mult_1_py'
    Uploading 'mult_root_py'
    Uploading 'mult_1'
    Uploading 'mult_root'
    Start fragment: mult_root
    Transaction started: 33f965fc70634260
    Transaction completed

    Execution time:
        Without overheads (worker):  57 ms
        Total (worker):              59 ms
        Total (node):                0:00:35.805273
    Transaction timestamps: 
        Start:          13:17:20.565000 [2017-08-30]
        End:            13:17:56.371000 [2017-08-30]
    Counters: 
        Total conflicts:   0
        Total restarts:    0
        Async calls:       71
        Sync calls:        0
        TVM reads:         690902
        TVM writes:        14703
    TVM traffic: 
        TVM bytes read:    1.02 MB
        TVM bytes write:   76.71 KB

Общее время исполнения падает:

    Total (node):                0:01:02.690510
    Total (node):                0:00:35.805273
  1. Масштабирование

Запускаем mult_root.lua с параметром 30 на кластере с одной нодой node2 (одна машина, 4 ядра (8 HT)):

    /usr/bin/python3.6 main.py --address localhost:5678 --fname mult_root --preset acapella
    Using 'acapella' preset
    Uploading 'mult_2_py'
    Uploading 'mult_2'
    Uploading 'mult_1_py'
    Uploading 'mult_root_py'
    Uploading 'mult_1'
    Uploading 'mult_root'
    Start fragment: mult_root
    Transaction started: 23a1c3cd264343e7
    Transaction completed

    Execution time:
        Without overheads (worker):  12 ms
        Total (worker):              16 ms
        Total (node):                0:00:08.753459
    Transaction timestamps: 
        Start:          10:46:11.108000 [2017-08-31]
        End:            10:46:19.021000 [2017-08-31]
    Counters: 
        Total conflicts:   0
        Total restarts:    0
        Async calls:       47
        Sync calls:        0
        TVM reads:         470113
        TVM writes:        94695
    TVM traffic: 
        TVM bytes read:    549.97 KB
        TVM bytes write:   20.86 KB

Запустим еще одну ноду node1 на второй машине, c аналогичной конфгурацией, 4 ядра (8 HT)). Соединим их:

    2017-08-31 10-48-32 [node2]: connected to node1 udp(192.168.1.19:40123 [105659]) (131081)

    2017-08-31 10-48-32 [node1]: connected to node2 udp(192.168.1.20:40124 [105660]) (131082)

Запустим тест еще раз:

    /usr/bin/python3.6 main.py --address localhost:5678 --fname mult_root --preset acapella
    Using 'acapella' preset
    Uploading 'mult_2_py'
    Uploading 'mult_2'
    Uploading 'mult_1_py'
    Uploading 'mult_root_py'
    Uploading 'mult_1'
    Uploading 'mult_root'
    Start fragment: mult_root
    Transaction started: 23a1c3cd264343e7
    Transaction completed

    Execution time:
        Without overheads (worker):  11 ms
        Total (worker):              19 ms
        Total (node):                0:00:05.223781
    Transaction timestamps: 
        Start:          10-49-05.570000 [2017-08-31]
        End:            10-49-10.798000 [2017-08-31]
    Counters: 
        Total conflicts:   0
        Total restarts:    0
        Async calls:       47
        Sync calls:        0
        TVM reads:         470113
        TVM writes:        94695
    TVM traffic: 
        TVM bytes read:    543.65 KB
        TVM bytes write:   19.99 KB

Общее время исполнения падает:

    Total (node):                0:00:08.753459
    Total (node):                0:00:05.223781

В логах обоих узлов можно наблюдать распределение задач:

Спойлер (кликните для показа/скрытия)

    2017-08-31 10-49-05 [node2]: existing fragment version: 111669149696
    2017-08-31 10-49-05 [node2]: uploading fragment: mult_2_py(27)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: mult_2_py(27)
    2017-08-31 10-49-05 [node2]: try upload fragment: mult_2
    2017-08-31 10-49-05 [node2]: existing fragment version: 111669149696
    2017-08-31 10-49-05 [node2]: uploading fragment: mult_2(27)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: mult_2(27)
    2017-08-31 10-49-05 [node2]: try upload fragment: mult_1_py
    2017-08-31 10-49-05 [node2]: existing fragment version: 111669149696
    2017-08-31 10-49-05 [node2]: uploading fragment: mult_1_py(27)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: mult_1_py(27)
    2017-08-31 10-49-05 [node2]: try upload fragment: mult_root_py
    2017-08-31 10-49-05 [node2]: existing fragment version: 111669149696
    2017-08-31 10-49-05 [node2]: uploading fragment: mult_root_py(27)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: mult_root_py(27)
    2017-08-31 10-49-05 [node2]: try upload fragment: mult_1
    2017-08-31 10-49-05 [node2]: existing fragment version: 111669149696
    2017-08-31 10-49-05 [node2]: uploading fragment: mult_1(27)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: mult_1(27)
    2017-08-31 10-49-05 [node2]: try upload fragment: mult_root
    2017-08-31 10-49-05 [node2]: existing fragment version: 111669149696
    2017-08-31 10-49-05 [node2]: uploading fragment: mult_root(27)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: mult_root(27)
    2017-08-31 10-49-05 [node2]: try upload fragment: fr0
    2017-08-31 10-49-05 [node2]: existing fragment version: 38654705664
    2017-08-31 10-49-05 [node2]: uploading fragment: fr0(10)
    2017-08-31 10-49-05 [node2]: uploading fragment finished: fr0(10)
    2017-08-31 10-49-05 [node2]: RRF: {mult_root(HEAD), 516d7d23f078447f-0.0}
    2017-08-31 10-49-05 [node2]: request prototype mult_root(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-05 [node2]: transaction status updated: 516d7d23f078447f -> running
    2017-08-31 10-49-05 [node2]: request fragment 'mult_root(27)' from CodeBase
    2017-08-31 10-49-05 [node2]: prototype cached: mult_root(27)
    2017-08-31 10-49-05 [node2]: start fragment: {mult_root(27), 516d7d23f078447f-0.0}
    2017-08-31 10-49-05 [worker4294967297]: start new thread: Thread[ForkJoinPool-1-worker-25,5,main]
    2017-08-31 10-49-05 [worker4294967297]: compile fragment: mult_root(27)
    2017-08-31 10-49-05 [worker4294967297]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-05 [worker4294967298]: start new thread: Thread[ForkJoinPool-1-worker-18,5,main]
    2017-08-31 10-49-06 [node2]: RRFFF: {mult_root -> mult_1(HEAD), 516d7d23f078447f-0.4.0}
    2017-08-31 10-49-06 [node2]: request prototype mult_1(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-06 [node2]: request fragment 'mult_1(27)' from CodeBase
    2017-08-31 10-49-06 [node2]: prototype cached: mult_1(27)
    2017-08-31 10-49-06 [node2]: start fragment: {mult_root -> mult_1(27), 516d7d23f078447f-0.4.0}
    2017-08-31 10-49-06 [worker4294967297]: compile fragment: mult_1(27)
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.139.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.140.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.141.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.142.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.143.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.144.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.145.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.146.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.147.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.148.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.149.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.150.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.151.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.152.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.153.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.154.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.155.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.156.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.157.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.158.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.159.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.160.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.161.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.162.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.163.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.164.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.165.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.166.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.167.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.168.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.169.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.170.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.171.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.172.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.173.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.174.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.175.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.176.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.177.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.178.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.179.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.180.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.181.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.182.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.183.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.184.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.185.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.186.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.187.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: RRFFF: {mult_1 -> mult_2(HEAD), 516d7d23f078447f-0.4.255x19.188.0}
    2017-08-31 10-49-07 [node2]: request prototype mult_2(HEAD). transaction: 516d7d23f078447f
    2017-08-31 10-49-07 [node2]: new shared stream: [transactions, 516d7d23f078447f, logs, log]
    2017-08-31 10-49-07 [node2]: register: SharedStream(transactions/516d7d23f078447f/logs/log)
    2017-08-31 10-49-07 [node2]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node2]: prototype cached: mult_2(27)
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.139.0}
    2017-08-31 10-49-07 [worker4294967298]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [worker4294967298]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.153.0}
    2017-08-31 10-49-07 [worker4294967299]: start new thread: Thread[ForkJoinPool-1-worker-11,5,main]
    2017-08-31 10-49-07 [worker4294967299]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.154.0}
    2017-08-31 10-49-07 [worker4294967300]: start new thread: Thread[ForkJoinPool-1-worker-4,5,main]
    2017-08-31 10-49-07 [worker4294967300]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.155.0}
    2017-08-31 10-49-07 [worker4294967301]: start new thread: Thread[ForkJoinPool-1-worker-29,5,main]
    2017-08-31 10-49-07 [worker4294967301]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.156.0}
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.157.0}
    2017-08-31 10-49-07 [worker4294967302]: start new thread: Thread[ForkJoinPool-1-worker-22,5,main]
    2017-08-31 10-49-07 [worker4294967304]: start new thread: Thread[ForkJoinPool-1-worker-8,5,main]
    2017-08-31 10-49-07 [worker4294967302]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967304]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.158.0}
    2017-08-31 10-49-07 [worker4294967303]: start new thread: Thread[ForkJoinPool-1-worker-15,5,main]
    2017-08-31 10-49-07 [worker4294967303]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967305]: start new thread: Thread[ForkJoinPool-1-worker-1,5,main]
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.159.0}
    2017-08-31 10-49-07 [worker4294967305]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.160.0}
    2017-08-31 10-49-07 [worker4294967306]: start new thread: Thread[ForkJoinPool-1-worker-26,5,main]
    2017-08-31 10-49-07 [worker4294967306]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.161.0}
    2017-08-31 10-49-07 [worker4294967307]: start new thread: Thread[ForkJoinPool-1-worker-19,5,main]
    2017-08-31 10-49-07 [worker4294967307]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.162.0}
    2017-08-31 10-49-07 [worker4294967308]: start new thread: Thread[ForkJoinPool-1-worker-12,5,main]
    2017-08-31 10-49-07 [worker4294967308]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.163.0}
    2017-08-31 10-49-07 [worker4294967309]: start new thread: Thread[ForkJoinPool-1-worker-5,5,main]
    2017-08-31 10-49-07 [worker4294967309]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.164.0}
    2017-08-31 10-49-07 [worker4294967310]: start new thread: Thread[ForkJoinPool-1-worker-30,5,main]
    2017-08-31 10-49-07 [worker4294967310]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.165.0}
    2017-08-31 10-49-07 [worker4294967311]: start new thread: Thread[ForkJoinPool-1-worker-23,5,main]
    2017-08-31 10-49-07 [worker4294967311]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.166.0}
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.167.0}
    2017-08-31 10-49-07 [worker4294967312]: start new thread: Thread[ForkJoinPool-1-worker-16,5,main]
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.168.0}
    2017-08-31 10-49-07 [worker4294967313]: start new thread: Thread[ForkJoinPool-1-worker-9,5,main]
    2017-08-31 10-49-07 [worker4294967312]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967315]: start new thread: Thread[ForkJoinPool-1-worker-27,5,main]
    2017-08-31 10-49-07 [worker4294967314]: start new thread: Thread[ForkJoinPool-1-worker-2,5,main]
    2017-08-31 10-49-07 [worker4294967315]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.169.0}
    2017-08-31 10-49-07 [worker4294967314]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.170.0}
    2017-08-31 10-49-07 [worker4294967313]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967316]: start new thread: Thread[ForkJoinPool-1-worker-20,5,main]
    2017-08-31 10-49-07 [worker4294967316]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967317]: start new thread: Thread[ForkJoinPool-1-worker-13,5,main]
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.140.0}
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.171.0}
    2017-08-31 10-49-07 [worker4294967318]: start new thread: Thread[ForkJoinPool-1-worker-6,5,main]
    2017-08-31 10-49-07 [worker4294967318]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.172.0}
    2017-08-31 10-49-07 [worker4294967319]: start new thread: Thread[ForkJoinPool-1-worker-31,5,main]
    2017-08-31 10-49-07 [worker4294967317]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967319]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967320]: start new thread: Thread[ForkJoinPool-1-worker-24,5,main]
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.173.0}
    2017-08-31 10-49-07 [worker4294967320]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.174.0}
    2017-08-31 10-49-07 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.175.0}
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.176.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.177.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.178.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.141.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.179.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.180.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.181.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.182.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.183.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.184.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.185.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.186.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.187.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.142.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.188.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.143.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.144.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.145.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.146.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.147.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.148.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.149.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.150.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.151.0} to 131081
    2017-08-31 10-49-07 [node2]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0} to 131081
    2017-08-31 10-49-07 [node2]: SharedStream(transactions/516d7d23f078447f/logs/log): sync 23 bytes
    2017-08-31 10-49-07 [node2]: reserveArea(tryReuse = null). Batch -> 10
    2017-08-31 10-49-07 [node2]: SharedStream(transactions/516d7d23f078447f/logs/log): reserved -> 0..10
    2017-08-31 10-49-07 [node2]: SharedStream(transactions/516d7d23f078447f/logs/log): (0..10) is expired
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.157.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.166.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.162.0}
    2017-08-31 10-49-09 [node2]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0}
    2017-08-31 10-49-09 [node2]: request cycle: mult_2(27)[516d7d23f078447f-0.4.255x19.152.0]
    2017-08-31 10-49-09 [node2]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.161.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.171.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.167.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.173.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.154.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.159.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.153.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.158.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.160.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.169.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.165.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.140.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.168.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.139.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.163.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.155.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.164.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.172.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.156.0}
    2017-08-31 10-49-09 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.170.0}
    2017-08-31 10-49-10 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.175.0}
    2017-08-31 10-49-10 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.174.0}
    2017-08-31 10-49-10 [node2]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0}
    2017-08-31 10-49-10 [node2]: job completed: {mult_root -> mult_1(27), 516d7d23f078447f-0.4.0}
    2017-08-31 10-49-10 [node2]: job completed: {mult_root(27), 516d7d23f078447f-0.0}
    2017-08-31 10-49-10 [node2]: tr executed: {mult_root(27), 516d7d23f078447f-0.0} FragmentRunResult{status=OK, errorString='null', conflicts=null}
    2017-08-31 10-49-10 [node2]: SharedStream(transactions/516d7d23f078447f/logs/log): request termination
    2017-08-31 10-49-10 [node2]: SharedStream(users/transactions/516d7d23f078447f/logs/registry/exclusiveLogs): request termination
    2017-08-31 10-49-10 [node2]: SharedStream(users/transactions/516d7d23f078447f/logs/registry/exclusiveLogs): terminated
    2017-08-31 10-49-10 [node2]: SharedStream(transactions/516d7d23f078447f/logs/log): terminated
    2017-08-31 10-49-10 [node2]: transaction status updated: 516d7d23f078447f -> finished

Обозначения:

  • start fragment: ... - локальный запуск исполнения фрагмента
  • RRF: ... - Request Run Fragment - кто-то запросил исполнение фрагмента
  • RRFFF: ... - Request Run Fragment From Fragment - запуск подфрагмента
  • mult_1 -> mult_2(27) - идентификатор запуска фрагмента mult_2 версии 27 из mult_1
  • mult_2(HEAD) - последняя версия фрагмента mult_2
  • 516d7d23f078447f-0.4.255x19.186.0 - глобальный идентификатор запуска фрагмента. Первая часть "516d7d23f078447f" - transaction ID, вторая часть "0.4.255x19.186.0" - DAM в сокращенной форме ("255x19" означает повторение 255 19 раз подряд)

За счет того, что запускаемые задачи довольно тяжелые, нагрузка распределилась почти поровну:

Спойлер (кликните для показа/скрытия)

    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.176.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.176.0}
    2017-08-31 10-49-07 [worker4294967297]: start new thread: Thread[ForkJoinPool-1-worker-25,5,main]
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.177.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [worker4294967297]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.177.0}
    2017-08-31 10-49-07 [worker4294967298]: start new thread: Thread[ForkJoinPool-1-worker-18,5,main]
    2017-08-31 10-49-07 [worker4294967298]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.178.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.178.0}
    2017-08-31 10-49-07 [worker4294967299]: start new thread: Thread[ForkJoinPool-1-worker-11,5,main]
    2017-08-31 10-49-07 [worker4294967299]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.141.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.141.0}
    2017-08-31 10-49-07 [worker4294967300]: start new thread: Thread[ForkJoinPool-1-worker-4,5,main]
    2017-08-31 10-49-07 [worker4294967300]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.179.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.179.0}
    2017-08-31 10-49-07 [worker4294967301]: start new thread: Thread[ForkJoinPool-1-worker-29,5,main]
    2017-08-31 10-49-07 [worker4294967301]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.180.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.180.0}
    2017-08-31 10-49-07 [worker4294967302]: start new thread: Thread[ForkJoinPool-1-worker-22,5,main]
    2017-08-31 10-49-07 [worker4294967302]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.181.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.181.0}
    2017-08-31 10-49-07 [worker4294967303]: start new thread: Thread[ForkJoinPool-1-worker-15,5,main]
    2017-08-31 10-49-07 [worker4294967303]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.182.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.182.0}
    2017-08-31 10-49-07 [worker4294967304]: start new thread: Thread[ForkJoinPool-1-worker-8,5,main]
    2017-08-31 10-49-07 [worker4294967304]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.183.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.183.0}
    2017-08-31 10-49-07 [worker4294967305]: start new thread: Thread[ForkJoinPool-1-worker-1,5,main]
    2017-08-31 10-49-07 [worker4294967305]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.184.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.184.0}
    2017-08-31 10-49-07 [worker4294967306]: start new thread: Thread[ForkJoinPool-1-worker-26,5,main]
    2017-08-31 10-49-07 [worker4294967306]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.185.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.185.0}
    2017-08-31 10-49-07 [worker4294967307]: start new thread: Thread[ForkJoinPool-1-worker-19,5,main]
    2017-08-31 10-49-07 [worker4294967307]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.186.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.186.0}
    2017-08-31 10-49-07 [worker4294967308]: start new thread: Thread[ForkJoinPool-1-worker-12,5,main]
    2017-08-31 10-49-07 [worker4294967308]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.187.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.187.0}
    2017-08-31 10-49-07 [worker4294967309]: start new thread: Thread[ForkJoinPool-1-worker-5,5,main]
    2017-08-31 10-49-07 [worker4294967309]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.142.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.142.0}
    2017-08-31 10-49-07 [worker4294967310]: start new thread: Thread[ForkJoinPool-1-worker-30,5,main]
    2017-08-31 10-49-07 [worker4294967310]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.188.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.188.0}
    2017-08-31 10-49-07 [worker4294967311]: start new thread: Thread[ForkJoinPool-1-worker-23,5,main]
    2017-08-31 10-49-07 [worker4294967311]: compile fragment: mult_2(27)
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.143.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.143.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.144.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.144.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.145.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.145.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.146.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.146.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.147.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.147.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.148.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.148.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.149.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.149.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.150.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.150.0}
    2017-08-31 10-49-07 [worker4294967313]: start new thread: Thread[ForkJoinPool-1-worker-9,5,main]
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.151.0}
    2017-08-31 10-49-07 [node1]: request fragment 'mult_2(27)' from CodeBase
    2017-08-31 10-49-07 [node1]: start fragment: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.151.0}
    2017-08-31 10-49-07 [node1]: RRF: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0}
    2017-08-31 10-49-07 [worker4294967305]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node1]: no suitable nodes for: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0}
    2017-08-31 10-49-07 [worker4294967312]: start new thread: Thread[ForkJoinPool-1-worker-16,5,main]
    2017-08-31 10-49-07 [worker4294967314]: start new thread: Thread[ForkJoinPool-1-worker-2,5,main]
    2017-08-31 10-49-07 [worker4294967313]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967312]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967302]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967309]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967301]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967304]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967303]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967298]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967315]: start new thread: Thread[ForkJoinPool-1-worker-27,5,main]
    2017-08-31 10-49-07 [worker4294967300]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967311]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967314]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967316]: start new thread: Thread[ForkJoinPool-1-worker-20,5,main]
    2017-08-31 10-49-07 [worker4294967299]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967310]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967297]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967306]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967308]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967307]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967318]: start new thread: Thread[ForkJoinPool-1-worker-13,5,main]
    2017-08-31 10-49-07 [worker4294967317]: start new thread: Thread[ForkJoinPool-1-worker-6,5,main]
    2017-08-31 10-49-07 [worker4294967315]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967319]: start new thread: Thread[ForkJoinPool-1-worker-31,5,main]
    2017-08-31 10-49-07 [worker4294967318]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967319]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967316]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [worker4294967317]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-07 [node1]: prototype cached: mult_2(27)
    2017-08-31 10-49-07 [worker4294967320]: start new thread: Thread[ForkJoinPool-1-worker-24,5,main]
    2017-08-31 10-49-07 [worker4294967320]: new TVM client: 127.0.0.1:6379
    2017-08-31 10-49-09 [node1]: RRF {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.152.0} to 131082 (rebalance)
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.186.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.177.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.180.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.151.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.147.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.176.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.182.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.184.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.146.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.178.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.181.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.150.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.183.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.187.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.148.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.142.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.185.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.188.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.143.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.144.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.141.0}
    2017-08-31 10-49-09 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.179.0}
    2017-08-31 10-49-10 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.149.0}
    2017-08-31 10-49-10 [node1]: job completed: {mult_1 -> mult_2(27), 516d7d23f078447f-0.4.255x19.145.0}
  1. Failover.

Запустим 3 узла: node1/node2/node3 (node id: 131081, 131082, 13103), на каждом включим AppServer. Оптравим запрос на старт длинной транзакции на node2. При включенном параметре запуска failover на всех нодах с AppServer можно будет увидеть следующее:

    2017-08-30 11-30-48 [node1]: failover initialized: failover(8954e80fab9e4be1, n=3){131081, {131083, 131082}}

    2017-08-30 11-30-48 [node2]: failover initialized: failover(8954e80fab9e4be1, n=3){131082, {131081, 131083}}

    2017-08-30 11-30-48 [node3]: failover initialized: failover(8954e80fab9e4be1, n=3){131083, {131081, 131082}}

После убийства node2, ноды иницируют перевыборы и выйгрывает node1, которая перезапускает транзакцию:

    2017-08-30 11-30-50 [node1]: entry node131082 is dead. Start election: failover(8954e80fab9e4be1, n=2){131081, {131083, 131082}}
    2017-08-30 11-30-50 [node1]: election succeed. Restart transaction
    2017-08-30 11-30-50 [node1]: restart transaction: 8954e80fab9e4be1

    2017-08-30 11-30-50 [node3]: entry node131082 is dead. Start election: failover(8954e80fab9e4be1, n=2){131083, {131081, 131082}}
    2017-08-30 11-30-50 [node3]: election failed. 

Raw Fragment API

Синхронный запуск фрагмента. Исполнение текущего фрагмента блокируется до завершения исполнения вызываемого подфрагмента.

    ap.call(fragmentId, contextTVMs, resultTVMs)

Асинхронный запуск другого фрагмента. Может вызывать конфликты, в результате чего вся транзакция завершается. Перезапуски пока не работают.

    ap.call_async(fragmentId, contextTVMs, resultTVMs)

TVM чтение/запись работает для int, bool и str, float:

    ap.tvm_get(valueId)
    ap.tvm_set(valueId, value)

Для TVM-таблиц (ключи также могут быть int, bool и str, float):

    ap.tvm_table_get(valueId, key)
    ap.tvm_table_set(valueId, key, value)

Получение длины таблицы:

    ap.tvm_length(valueId)

Создание ячейки со значением nil без указания valueId (он будет сгенерирован):

    local valueId = ap.tvm_new()

Ожидание завершения всех запущенных через call_async подфрагментов в текущем фрагменте:

    ap.await_all()

создание IO-ячейки:

    ap.new_io("<json с параметрами IO-ресурса", url)

возвращает идентификатор ячейки TVM привязанной к IO рекурсу, например ключу A_Storage или Cloud FS ресурсу типа файл.

IO commit - применение всех изменений:

    ap.commit()

Аргументы запуска:

    local arg1 = ap.args[1]
    local arg2 = ap.args[2]

Ассерты для тестов, error_message необязателен:

    ap.assert(condition, error_message)

AppServer HTTP API

  • POST /auth/login
  • POST /auth/logout
  • POST /auth/signup
  • GET /cb/fragments
  • POST /cb/fragments/{frId}
  • GET /cb/fragments/{frId}/bytecode
  • POST /cb/fragments/{frId}/bytecode
  • GET /cb/fragments/{frId}/meta
  • POST /cb/fragments/{frId}/meta
  • GET /cb/fragments/{frId}/source
  • POST /cb/fragments/{frId}/source
  • GET /cb/users/{otherUserId}/fragments
  • POST /managment/setupTopology
  • POST /managment/terminate
  • GET /vm/logs/
  • DELETE /vm/logs/{logId}
  • DELETE /vm/logs/{logId}
  • GET /vm/logs/{logId}
  • POST /vm/start
  • POST /vm/stop
  • GET /vm/transactions/
  • DELETE /vm/transactions/{trId}/fragments/{frId}/executions/{dam}/logs/{logId}
  • GET /vm/transactions/{trId}/fragments/{frId}/executions/{dam}/logs/{logId}
  • DELETE /vm/transactions/{trId}/fragments/{frId}/logs/{logId}
  • GET /vm/transactions/{trId}/fragments/{frId}/logs/{logId}
  • GET /vm/transactions/{trId}/logs/
  • DELETE /vm/transactions/{trId}/logs/{logId}
  • GET /vm/transactions/{trId}/logs/{logId}
  • GET /vm/transactions/{trId}/lpf/byFragment/{frId}
  • GET /vm/transactions/{trId}/statistics
  • GET /vm/transactions/{trId}/status
  • GET /vm/version

vm5

  • POST /managment/finish
  • POST /managment/update
  • POST /managment/status

TODO подробное описание

Комментарии

Comments powered by Disqus
Перейти к главному содержимому