Научная статья на тему 'ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ CRDT ДЛЯ РАЗРАБОТКИ КЛИЕНТ-СЕРВЕРНЫХ ПРИЛОЖЕНИЙ'

ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ CRDT ДЛЯ РАЗРАБОТКИ КЛИЕНТ-СЕРВЕРНЫХ ПРИЛОЖЕНИЙ Текст научной статьи по специальности «Компьютерные и информационные науки»

182
26
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
CRDT / распределенные системы / типы данных / репликация / eventual consistency / клиент-серверные приложения. / CRDT / distrubutes systems / data types / replication / eventual consistency / client-server applications.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Кальянов Никита Александрович

Был проведён подробный анализ практической возможности внедрения CRDT в клиент-серверное приложение интернет-магазина. Разработаны детализированные архитектурные диаграммы развёртывания и практическая реализация на языке Python. Были протестированы и верифицированы полезные свойства CRDT с использованием фреймворка для тестирования и верификации распределенных систем (язык Clojure).

i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Кальянов Никита Александрович

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

CRDT USAGE IN THE DEVELOPMENT OF CLIENT-SERVER APPLICATIONS: PRACTICAL APPLICATION

A detailed analysis of the practical possibility of implementing CRM in the client-server application of the online store was carried out. Detailed architectural deployment diagrams and practical implementation in Python have been developed. The useful properties of CRDT were tested and verified using the framework for testing and verifying distributed systems (Clojure programming language).

Текст научной работы на тему «ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ CRDT ДЛЯ РАЗРАБОТКИ КЛИЕНТ-СЕРВЕРНЫХ ПРИЛОЖЕНИЙ»

XIIIМеждународная научно-практическая конференция УДК 004

Кальянов Никита Александрович Kalyanov Nikita Alexandrovich

Студент Student

Тольяттинский государственный университет

Togliatti State University

ПРАКТИЧЕСКОЕ ПРИМЕНЕНИЕ CRDT ДЛЯ РАЗРАБОТКИ КЛИЕНТ-СЕРВЕРНЫХ ПРИЛОЖЕНИЙ

CRDT USAGE IN THE DEVELOPMENT OF CLIENT-SERVER APPLICATIONS: PRACTICAL APPLICATION

Аннотация. Был проведён подробный анализ практической возможности внедрения CRDT в клиент-серверное приложение интернет-магазина. Разработаны детализированные архитектурные диаграммы развёртывания и практическая реализация на языке Python. Были протестированы и верифицированы полезные свойства CRDT с использованием фреймворка для тестирования и верификации распределенных систем (язык Clojure).

Abstract. A detailed analysis of the practical possibility of implementing CRM in the client-server application of the online store was carried out. Detailed architectural deployment diagrams and practical implementation in Python have been developed. The useful properties of CRDT were tested and verified using the framework for testing and verifying distributed systems (Clojure programming language).

Ключевые слова. CRDT, распределенные системы, типы данных, репликация, eventual consistency, клиент-серверные приложения.

Key words. CRDT, distrubutes systems, data types, replication, eventual consistency, client-server applications.

Введение

Данное исследование рассматривает возможности практического применения CRDT в клиент-серверных приложениях. В частности, прорабатывается конкретный практический пример внедрения CRDT для клиент-серверного приложения интернет-магазина. Разработана

«Инновационные аспекты развития науки и техники» практическая реализация, и на её основе верифицируются полезные свойства CRDT и оцениваются преимущества.

Практическое применение CRDT на примере корзины товаров интернет-магазина

CRDT представляют собой класс алгоритмов, обладающих свойствами отсутствия конфликтов при репликации (что отражено в названии) и eventual consistency[1]. Однако, изучать класс алгоритмов целиком достаточно сложно. В связи с этим было проведено исследование и верификация свойств CRDT на конкретном примере корзины товаров интернет-магазина.

Анализ заинтересованных сторон и преимуществ При анализе внедрения CRDT было выявлено три заинтересованные стороны (stakeholders). Описание каждой из выявленных заинтересованных сторон и их цели представлено в таблице (табл. 1).

Таблица 1. Цели заинтересованных сторон при внедрении СЯ^Т.

Источник: анализ автора.

Заинтересованная сторона Цели заинтересованной стороны

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

Разработчики и администраторы приложения - максимально упростить разработку и поддержку приложения - снизить число возникающих аварий/багов

Компания-разработчик приложения в целом - повысить бизнес-метрики (например, выручку)

XIIIМеждународная научно-практическая конференция Внедрение СКОТ в клиент-серверное веб-приложение интернет-

магазина позволит достичь целей всех трех заинтересованных сторон.

Соответствие преимуществ внедрения СКОТ (по сравнению с

разработкой альтернативного решения или отсутствием решения для

синхронизации вообще) и достигаемых каждым преимуществом целей

заинтересованных сторон приведено в таблице (Табл. 2).

Таблица 2. Реализация целей заинтересованных сторон при

внедрении CRDT. Источник: анализ автора.

Преимущество Для Для разработчиков и Для бизнеса

пользователей администраторов

приложения

Поддержка 1. Более - 1. Рост вовлечения

одновременного удобная пользователей

использования с синхронизация 2. Повышение

нескольких с поддержкой конкурентноспособности

устройств параллельного приложения

добавления

товаров в

корзину с

нескольких

устройств и

без

постоянного

подключения

к сети

2. Отсутствует

возможность

потери

добавленного

товара

Устойчивость к 1. Отсутствует - 1. Возможен рост

обрывам возможность выручки за счёт

соединения потери отсутствия возможности

единожды пропадания

добавленного добавленного товара из

товара корзины

Продолжение Таблицы 1

Надёжный - 1. Проверенная 1. Снижение затрат на

алгоритм реализация, меньше поддержку приложения

вероятность 2. Возможность

возникновения перенаправить усилия

багов чем при команды на разработку

альтернативной нового функционала для

реализации потенциального

2. Проще увеличения выручки

масштабирование

приложения

Данное представление позволяет наглядно оценить как прямые, так и косвенные преимущества внедрения CRDT.

Пример внедрения

Рассмотрим типичное клиент-серверное приложение интернет-магазина. По критериям практической распространённости рассматриваем монолитное self-hosted приложение с использованием Базы Данных и без использования SSR. В соответствии с проведённым в [2, с. 48-52] анализом, для данного типа приложения и данной архитектуры наиболее подходящей реализацией CRDT является Observed-Removed Set (OR-Set)[3] в виде соответствующих модулей (клиентского и серверного). Разработанная архитектура развёртывания представлена ниже (рис. 1).

Browser Browser

:MainLoop CartSyncronizer

Frontend serv|^ Load Balancer^ App Server DB ^

Proxy Proxy CartSyncronizer :QueryExecutor

execute callback

HTTP Request

HTTP Response

<

HTTP Request

^ HTTP Response

HTTP Request

^ HTTP Response <....................

Рис. 1. Архитектура развертывания СЯБТ для клиент-серверного приложения интернет-магазина.

В архитектурной диаграмме подробно рассматриваются детали развертывания, включая внешние и внутренние сервера, балансировщики нагрузки, сетевую топологию и взаимодействие клиентской и серверной части приложения. Для наглядности указаны возможные ОКБ-имена хостов и конкретные виды клиентов.

Для более полного понимания архитектуры развёртывания рассмотрим полный «путь» синхронизации корзины пользователя от внесённого пользователем приложения изменения в браузере до синхронизации состояния корзины на сервере (рис. 2).

Клиентские модули СИРТ Серверный модуль СРЮТ

( ¡OS Арр J

К

api.shop-online.example.com

Resources server (Frontend)

Server-Side Application

A"

DB

Внутренняя сеть организации

Рис.2. Путь синхронизации пользовательской корзины от клиента до сервера. Источник: анализ автора

На первом шаге пользователь добавляет или удаляет элемент из корзины через браузерный интерфейс. Браузер регистрирует это событие и передаёт управление обработчику. Обработчик события (модуль CRDT) локально сохраняет изменения и инициирует синхронизацию корзины с сервером через отправку HTTP-запроса. В теле запроса отправляется текущее состояние корзины пользователя. Запрос проходит через прокси и балансировщик нагрузки и доходит до серверной части приложения. Серверная часть приложения обрабатывает запрос с помощью серверного модуля CRDT, полученное от клиента состояние корзины объединяется с текущим серверным состоянием (merge) и сохраняется в Базу Данных для обеспечения персистентности данных. Затем сервер возвращает полученное после объединения итоговое состояние корзины в теле HTTP ответа. Ответ проходит прокси-сервера в обратном порядке и доходит до отправителя. Клиентский модуль CRDT объединяет полученное в теле ответа состояние корзины со своим текущим локальным состоянием пользовательской корзины и считает полученное состояние новым актуальным состоянием. После этого обработчик события завершает работу и возвращает управление в главный цикл событий (Eventloop).

Также была разработана диаграмма классов для данного внедрения CRDT (рис. 3).

Рис. 3. Диаграмма классов для модулей СЯБТ для клиент-серверного приложения интернет-магазина

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Элемент корзины моделируется как класс с полями для идентификатора выбранного товара, его имени, цены и количества выбранных товаров этого вида.

Алгоритмы CRDT реализует класс ORSet, используя внутреннее представление корзины как множества кортежей из пар «уникальный идентификатор элемента», «Элемент корзины».

Для синхронизации корзины важно уметь объединять два произвольных состояния корзины и для этой задачи был выделен класс BaseCartSyncronizer который хранит текущее состояние корзины и может объединить своё состояние с состоянием корзины, переданным в аргумент метода merge. У этого класса есть два класса-наследника — клиентский и серверный синхронизаторы соответственно. Клиентский

«Инновационные аспекты развития науки и техники» синхронизатор расширяет базовый интерфейс и добавляет

возможность синхронизировать состояние корзины с сервером.

Серверный синхронизатор добавляет возможность сохранить

состояние корзины в Базу Данных.

Именно такая предложенная схема классов позволяет удобно моделировать задачу синхронизации корзины, разделять ответственность между классами и снижать дублирование кода.

Для полученной стуктуры классов была разработана реализация клиентской и серверной части на псевдо-коде. Используется язык, напоминающий Java, но с дополнительными ключевыми словами для улучшения читаемости. Используемые методы названы общепринятыми названиями.

Псевдо-код синхронизации корзины на стороне клиента приведён на рисунке ниже (рис. 4).

1 class ClientCartSyncronizer {

2 method getFromServerQ do

let response = doRequest(Host: thls.serverHost, Payload: this.set); 4 this.merge(response.deserlallze());

done

7

8 let syncronlzer = CllentCartSyncronlzer("shop-onllne.example.com");

9

10onLoad() do

11 currentCart = syncronlzer. getFromServerQ;

12 done

13

14 onTlner(60) do

syncronlzer.getFronServer();

16 done

17

18onEvent() do

If (event.type == "add") then

20 syncronlzer.getSet().add(event. data);

21 else If (event.type == "remove") then

22 syncronlzer.getSet().remove(event.data);

23 done

25 syncronlzer. getFromServerQ;

26 done

I

Рис. 4. Реализация клиентского модуля СЯБТ для приложения интернет-магазина на псевдокоде.

XIII Международная научно-практическая конференция В данной реализации на строчках 1-6 приведена синхронизация

локального состояния с серверным состояние через HTTP запрос. На

строчках 10-26 приведены основные обработчики. Обработчик onLoad

обрабатывает событие загрузки страницы и при загрузке подгружает с

сервера актуальное состояние корзины. Обработчик onTimer

периодически синхронизирует состояние с сервером безусловно (даже

без пользовательских действий). Данный обработчик нужен чтобы на

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

и отправленные на сервер. Обработчик onEvent обрабатывает

пользовательское действие, добавляет или удаляет элемент из

локальной корзины и синхронизирует состояние с сервером.

Приведённая реализация отличается простотой, а также

производительностью. В данной реализации не требуется блокировка

на период синхронизации состояния с сервером, то есть не обязательно

ждать получения ответа сервера. Пользователь может продолжать

изменять корзину и во время асинхронной синхронизации с сервером.

Это становится возможным благодаря свойствам CRDT (merge всегда

проходит без конфликтов и потери данных).

Псевдо-код синхронизации корзины на стороне сервера приведён

на рисунке ниже (рис. 5).

1 dbHost = "db.internal.example.con";

2

3 class ServerCartSyncronizer {

4 method saveToDb(userld) do

executeQuery(

6 Host: dbHost,

7 Query: "UPDATE carts SET contents = %s WHERE user_id = %s", QueryParams: [this.set, userld]

9 );

10 done

12

13 method getUserSyncronizer(userld) do

14 let currentCart = executeQuery(

15 Host: dbHost,

Query: "SELECT contents FROM carts WHERE user_id = %s",

17 QueryParams: [userld]

18 );

19

20 return ServerCartSyncronizer(currentCart);

21 done

23 @Path("/syncronizeCart")

24 method processSyncronizeCartRequest(request) do

let syncronizer = getUserSyncronizer(request.getUserldO);

26 syncronizer.merge(request.body.deserialize());

27 syncronizer.saveToDB();

28 return nakeResponse(syncronizer.getSetO);

29 done

30 I

Рис. 5. Реализация серверного модуля СЯБТ для приложения интернет-магазина на псевдокоде.

В данной реализации на строчках 4-10 приведен пример обновления корзины в Базе Данных (через SQL-запрос). На строчках 14-20 приведена инициализация класса ServerCartSyncromzer с данными из Базы Данных (по сути выгрузка данных из БД в оперативную память). На строчках 23-28 приведен пример реализации обработчика запросов с клиентской части. Сервер обрабатывает запросы на /syncronizeCart, использует данные о пользователе, отправившем запрос чтобы выгрузить из БД текущую корзину этого пользователя. Затем выгруженная корзина объединяется с корзиной, которая пришла в запросе. Полученная объединённая корзина сохраняется обратно в Базу Данных, а также возвращается в теле ответа клиенту.

Такая реализация позволяет не держать все корзины в памяти, а выгружать их из Базы Данных по необходимости. При этом несколько копий серверной части приложения могут работать параллельно, так

XIIIМеждународная научно-практическая конференция как обычно в Базу Данных встроена надёжная синхронизация запросов.

Стоит отметить что в данной реализации необходима информация о

пользователе, от лица которого был отправлен запрос на

синхронизацию корзины. Обычно эту информацию можно получить с

помощью используемого в приложении механизма аутентификации

(куки, JWT-токен в заголовках запроса и так далее). Эта деталь

реализации связана с тем, что один сервер обрабатывает запросы

произвольного количества клиентов и каждый клиент должен

синхронизировать только свою корзину. Таким образом возникает

классическая задача хранения сессии клиента, которая решена во

многих популярных фреймворках для разработки веб-приложений. Тем

не менее, выносить подобные детали реализации в диаграммы

предыдущего раздела было бы нецелесообразно.

Практическая реализация

На основе спроектированной в предыдущем разделе архитектуры была разработана практическая реализация описанного выше CRDT (OR-Set для корзины интернет-магазина) на языке программирования Python. Реализация состоит из клиентской и серверной части, а также общих модулей. Серверная часть представляет собой HTTP-сервер, использующий базу данных PostgreSQL а также поддерживающий внутреннее состояние в оперативной памяти. Клиентская часть принимает команды по протоколу TCP и отправляет соответствующие запросы на сервер, а также обновляет своё внутреннее состояние в памяти. Такой подход позволяет удобно автоматизировать взаимодействие с клиентом без использования средств браузерной автоматизации. В качестве формата передачи данных используется JSON. Исходный код доступен в репозитории https://github.com/nikitakalyanov/crdt-cart по лицензии Eclipse Public License 2.0.

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Верификация и тестирование

Для анализа практических преимуществ CRDT а также тестирования разработанной реализации использовался фреймворк Jepsen[4]. Jepsen — специализированный фреймворк для тестирования и верификации корректности распределенных систем с поддержкой fault injection (искусственно вызываемые сетевые проблемы) и многопоточности. Фреймворк хорошо зарекомендовал себя, в частности с его помощью было найдено несколько concurrency-багов в таких популярных программных продуктах как Redis, PostgreSQL, MongoDB, Kafka, RabbitMQ, etcd, Zookeeper и многих других[5]. Фреймворк написан на языке программирования Clojure (современный диалект Lisp, исполняется на виртуальной машине Java (JVM)) и применяет функциональное программирование.

Для тестирования было развёрнуто 5 виртуальных узлов с использованием технологии LXC (Linux Containers) на дистрибутиве Linux Debian (релиз Buster). На каждом узле были запущены и клиентская и серверная части. Кроме того, для распределения нагрузки а также большего соответствия реальным практическим развёртываниям клиентские части отправляли запросы на серверные части не напрямую, а через балансировщик нагрузки. В качестве балансировщика нагрузки использовался NGINX. В качестве базы данных использовался PostgreSQL развёрнутый в Docker-контейнере. Все скрипты для развёртывания и исходный код теста в виде Clojure-пакета доступны в репозитории

https://github.com/nikitakalyanov/jepsen.crdtcart по лицензии Eclipse ublic License 2.0.

Был реализован Jepsen-тест для тестирования и верификации полученной реализации. Тест запускается на 5 узлах. На каждом из узлов запускается случайный набор операций добавления и удаления товаров из корзины. Во время выполнения операций производится

XIIIМеждународная научно-практическая конференция многократное случайное разделение узлов на сетевом уровне (т.е. узлы из группы 1 не могут связаться с узлами из группы 2 и наоборот) для имитации сетевых проблем и временно отключающихся клиентов. Затем производится восстановление сетевой связности и ожидание синхронизации всех узлов. После этого производится чтение результирующей корзины товаров. Фактически считанное состояние корзины валидируется с использованием модели корзины. Для каждой операции обрабатывается ожидаемый результат операции вплоть до финального состояния. Затем результат обработки истории операций с точки зрения модели сравнивается с фактическим результатом чтения. Параметры теста могут указываться динамически при запуске.

Было проведено несколько запусков тестирования с постепенным возрастанием «сложности» (многопоточность, число узлов) и длительности. Для отладки самого теста использовался пробный запуск на одном узле без многопоточности длительностью 60 секунд (Приложение 1). Во время запуска также применялась генерация сетевых проблем. Данный запуск прошёл успешно (т.е. содержимое корзины соответствует ожидаемому, кроме того, все операции чтения и записи завершились успешно).

На втором этапе тест запускался на пяти узлах и длился 120 секунд. Тест прошёл успешно.

Как известно, в практических развертываниях клиент-серверных приложений один сервер обрабатывает запросы нескольких клиентов (конкретное число зависит от конфигурации и числа пользователей). Для того, чтобы получить максимально приближенный к реальным условиям тест использовалась многопоточность. На каждом узле запускалось 10 потоков тестирования, таким образом общее число потоков составляло 50. Длительность тестирования составляла 120 секунд. Тест прошёл успешно.

По результатам тестирования можно сделать следующие выводы:

1. CRDT-алгоритмы относительно просты в реализации.

2. При своей относительной простоте CRDT обладают высокой надёжностью: устойчивы к временно отключающимся клиентам а также сетевым проблемам которые могут возникать в реальных развёртываниях.

3. CRDT хорошо выдерживают нагрузки, типичные для реальных клиент-серверных приложений (относительно небольшое число запросов для конкретной корзины одного пользователя, но большое общее число клиентских запросов для одного сервера).

4. CRDT действительно достигают итогового консистентного состояния при условии разрешения сетевых проблем и могут корректно реализовывать семантику множества (Set).

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

Библиографический список:

1. Shapiro M. И другие. Conflict-free replicated data types //Symposium on Self-Stabilizing Systems. - Springer, Berlin, Heidelberg,

2011. - С. 386-400.

2. Кальянов Н.А. Анализ применения CRDT для разработки клиент-серверных приложений // Инновационные аспекты развития: сборник статей IX Международной научно-практической конференции. Саратов, 2021. - 272. С. 33-56.

3. Bieniusa A. и другие, An optimized conflict-free replicated set [Research Report] RR-8083, Inria - Centre Paris-Rocquencourt; INRIA.

2012, стр. 3.

XIIIМеждународная научно-практическая конференция

4. Jepsen. A framework for distributed systems verification, with fault injection, [Электронный ресурс]: официальный репозиторий Jepsen. Режим доступа: https://github.com/jepsen-io/jepsen (дата обращения: 05.09.2021)

5. Kyle Kingsbury. Jepsen. Analyses, [Электронный ресурс]: официальный сайт Jepsen. Режим доступа: http://jepsen.io/analyses (дата обращения: 05.09.2021)

Приложение 1

OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.

05:01:11.491 [main] INFO jepsen.cli - Test options: {:ssh-private-key

"/home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem",

:concurrency 1,

:leave-db-running? false,

:logging-json? false,

:ssh

{:dummy? false, :username "root", :password "root", :strict-host-key-checking false, :private-key-path

"/home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem"},

:argv

("test"

-n"

"n1"

"--ssh-private-key"

"/home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem"), :nodes ["n1"], :test-count 1, :time-limit 60}

INFO [2021-06-07 05:01:11,526] jepsen test runner - jepsen.core Test version 0dd17f427ea7e7a603a0d91f012ac65ffd17559b (plus uncommitted changes)

XIIIМеждународная научно-практическая конференция INFO [2021-06-07 05:01:11,527] jepsen test runner - jepsen.core

Command line:

lein run test -n n1 --ssh-private-key /home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem

INFO [2021-06-07 05:01:11,593] jepsen test runner - jepsen.core Running test:

{:remote #jepsen.control.SSHRemote{: session nil} :ssh-private-key "/home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem"

:concurrency 1 :db

#object[jepsen.db$reify_3444 "0x753e4eb5"

"jepsen.db$reify_3444@753e4eb5"]

:leave-db-running? false :name "noop" :logging-json? false :start-time

#object[org.joda.time.DateTime "0x1e295f7f "2021-06-07T05:01:11.000+03:00"] :net

#object[jepsen.net$reify_9085 "0x4b762988"

"j epsen.net$reify_9085 @4b762988"]

:client #jepsen.crdtcart.Client{:node nil} :barrier

#obj ect[java.util .concurrent.CyclicBarrier "0x24f2608b"

"java.util.concurrent.CyclicBarrier@24f2608b"] :pure-generators true :ssh

{:dummy? false,

«Инновационные аспекты развития науки и техники» :username "root", :password "root", :strict-host-key-checking false,

:private-key-path "/home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem"}

:checker

#object[jepsen.checker$compose$reify_8597

"0x12a9e864"

"jepsen.checker$compose$reify_8597@12a9e864"]

:argv ("test" "-n" "n1"

"--ssh-private-key"

"/home/nkalyanov/jepsen-repo/jepsen/docker/test-key.pem") :nemesis

#object[jepsen.nemesis$partitioner$reify_9233

"0x462f8fe9"

"jepsen.nemesis$partitioner$reify_9233@462f8fe9"]

:active-histories

#object[clojure.lang.Atom "0x6cf3b3d7" {:status :ready, :val #{}}] :nodes ["n1"] :test-count 1 :generator

((jepsen.generator. Synchronize {:gen (jepsen.generator.TimeLimit {:limit 15000000000, : cutoff nil,

:gen (jepsen.generator.Any

{: gens [(jepsen. generator.OnThreads

XIII Международная научно-практическая конференция {:f #{:nemesis}, :gen ({:type :sleep, :value 5} {:type :info, :f :start} {:type :sleep, :value 5} {:type :info, :f :stop} {:type :sleep, :value 5} {:type :info, :f :start} {:type :sleep, :value 5} {:type :info, :f :stop}

(jepsen.generator.OnThreads

{:f #object[clojure.core$complement$fn_5654

"0x1002d1c8"

"clojure.core$complement$fn_5654@1002d1c8"],

:gen (jepsen.generator.Stagger {:dt 2000000000, :next-time nil, :gen (jepsen.generator.Mix {:i 2,

:gens [#object[jepsen.crdtcart$r "0x38a27ace"

"jepsen.crdtcart$r@38a27ace"] #object[jepsen.crdtcart$add "0x41289e88"

"jepsen.crdtcart$add@41289e88"] #obj ect[jepsen. crdtcart$rm "0x7e8783b0"

"jepsen.crdtcart$rm@7e8783b0"]]})})})]})})})

«Инновационные аспекты развития науки и техники» (jepsen.generator. Synchronize

{:gen {:type :log, :value "stopping network problems"}}) (jepsen.generator. Synchronize {:gen (jepsen.generator.OnThreads {:f #{:nemesis}, :gen (jepsen.generator.Limit

{:remaining 1, :gen {:type :info, :f :stop}})})}) (jepsen.generator. Synchronize

{:gen {:type :log, :value "Waiting for syncronisation"}}) (jepsen.generator.Synchronize {:gen {:type :sleep, :value 1}}) (jepsen.generator. Synchronize {:gen (jepsen.generator.OnThreads

{:f #object[clojure.core$complement$fn_5654

"0x788d9139"

"clojure.core$complement$fn_5654@788d9139"],

:gen (jepsen.generator.Limit

{:remaining 1, :gen {:type :invoke, :f :read, :value

nil}})})})) :os

#object[jepsen.os$reify_2489 "0x53d2f0ec"

"jepsen.os$reify_2489@53d2f0ec"]

:time-limit 60}

INFO [2021-06-07 05:01:11,874] jepsen test runner - jepsen.db Tearing down DB

INFO [2021-06-07 05:01:11,876] jepsen test runner - jepsen.db Setting up DB

INFO [2021-06-07 05:01:11,877] jepsen test runner - jepsen.core Relative time begins now

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

XIII Международная научно-практическая конференция INFO [2021-06-07 05:01:12,237] jepsen worker 0 - jepsen.util 0

:invoke :remove {"product_id" 3, "product_name" "test 3",

"price" 3, "quantity" 1}

INFO [2021-06-07 05:01:12,247] jepsen worker 0 - jepsen.util 0

:ok :remove {"product_id" 3, "product_name" "test 3", "price"

3, "quantity" 1}

INFO [2021-06-07 05:01:14,051] jepsen worker 0 - jepsen.util 0 :invoke :add {"product_id" 4, "product_name" "test 4", "price"

4, "quantity" 1}

INFO [2021-06-07 05:01:14,066] jepsen worker 0 - jepsen.util 0 :ok :add {"product_id" 4, "product_name" "test 4", "price" 4, "quantity" 1}

INFO [2021-06-07 05:01:15,140] jepsen worker 0 - jepsen.util 0 :invoke :read nil

INFO [2021-06-07 05:01:15,165] jepsen worker 0 - jepsen.util 0 :ok :read #{{"product_id" 4, "product_name" "test 4", "price" 4, "quantity" 1}}

INFO [2021-06-07 05:01:17,028] jepsen worker 0 - jepsen.util 0 :invoke :add {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}

INFO [2021-06-07 05:01:17,040] jepsen worker 0 - jepsen.util 0 :ok :add {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}

INFO [2021-06-07 05:01:17,235] jepsen worker nemesis - jepsen.util :nemesis :info :start nil

INFO [2021-06-07 05:01:17,244] jepsen worker nemesis - jepsen.util :nemesis :info :start [:isolated {"n1" #{}}]

INFO [2021-06-07 05:01:18,423] jepsen worker 0 - jepsen.util 0 :invoke :remove {"product_id" 3, "product_name" "test 3", "price" 3, "quantity" 1}

«Инновационные аспекты развития науки и техники» INFO [2021-06-07 05:01:18,433] jepsen worker 0 - jepsen.util 0

:ok :remove {"product_id" 3, "product_name" "test 3", "price"

3, "quantity" 1}

INFO [2021-06-07 05:01:18,840] jepsen worker 0 - jepsen.util 0 :invoke :read nil

INFO [2021-06-07 05:01:18,846] jepsen worker 0 - jepsen.util 0 :ok :read #{{"product_id" 4, "product_name" "test 4", "price" 4, "quantity" 1} {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}}

INFO [2021-06-07 05:01:20,500] jepsen worker 0 - jepsen.util 0 :invoke :remove {"product_id" 1, "product_name" "test", "price" 1, "quantity" 1}

INFO [2021-06-07 05:01:20,510] jepsen worker 0 - jepsen.util 0 :ok :remove {"product_id" 1, "product_name" "test", "price" 1, "quantity" 1}

INFO [2021-06-07 05:01:21,869] jepsen worker 0 - jepsen.util 0 :invoke :read nil

INFO [2021-06-07 05:01:21,873] jepsen worker 0 - jepsen.util 0 :ok :read #{{"product_id" 4, "product_name" "test 4", "price" 4, "quantity" 1} {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}}

INFO [2021-06-07 05:01:22,247] jepsen worker nemesis - jepsen.util :nemesis :info :stop nil

INFO [2021-06-07 05:01:22,408] jepsen worker 0 - jepsen.util 0 :invoke :add {"product_id" 3, "product_name" "test 3", "price" 3, "quantity" 1}

INFO [2021-06-07 05:01:22,421] jepsen worker 0 - jepsen.util 0 :ok :add {"product_id" 3, "product_name" "test 3", "price" 3, "quantity" 1}

XIIIМеждународная научно-практическая конференция INFO [2021-06-07 05:01:22,457] jepsen worker nemesis - jepsen.util

:nemesis :info :stop :network-healed

INFO [2021-06-07 05:01:24,209] jepsen worker 0 - jepsen.util 0

:invoke :remove {"product_id" 4, "product_name" "test 4",

"price" 4, "quantity" 1}

INFO [2021-06-07 05:01:24,218] jepsen worker 0 - jepsen.util 0

:ok :remove {"product_id" 4, "product_name" "test 4", "price"

4, "quantity" 1}

INFO [2021-06-07 05:01:24,420] jepsen worker 0 - jepsen.util 0 :invoke :remove {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}

INFO [2021-06-07 05:01:24,437] jepsen worker 0 - jepsen.util 0 :ok :remove {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}

INFO [2021-06-07 05:01:24,758] jepsen worker 0 - jepsen.util 0 :invoke :remove {"product_id" 1, "product_name" "test", "price" 1, "quantity" 1}

INFO [2021-06-07 05:01:24,772] jepsen worker 0 - jepsen.util 0 :ok :remove {"product_id" 1, "product_name" "test", "price" 1, "quantity" 1}

INFO [2021-06-07 05:01:26,616] jepsen worker 0 - jepsen.util 0 :invoke :read nil

INFO [2021-06-07 05:01:26,620] jepsen worker 0 - jepsen.util 0 :ok :read #{{"product_id" 3, "product_name" "test 3", "price" 3, "quantity" 1}}

INFO [2021-06-07 05:01:27,115] jepsen worker 0 - jepsen.util 0 :invoke :add {"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2}

«Инновационные аспекты развития науки и техники» INFO [2021-06-07 05:01:27,126] jepsen worker 0 - jepsen.util 0

:ok :add {"product_id" 2, "product_name" "test 2", "price" 2,

"quantity" 2}

INFO [2021-06-07 05:01:27,460] jepsen worker 0 -jepsen.generator.interpreter stopping network problems

INFO [2021-06-07 05:01:27,462] jepsen worker nemesis - jepsen.util :nemesis :info :stop nil

INFO [2021-06-07 05:01:27,670] jepsen worker nemesis - jepsen.util :nemesis :info :stop :network-healed

INFO [2021-06-07 05:01:27,671] jepsen worker nemesis -jepsen.generator.interpreter Waiting for syncronisation

INFO [2021-06-07 05:01:28,673] jepsen worker 0 - jepsen.util 0 :invoke :read nil

INFO [2021-06-07 05:01:28,677] jepsen worker 0 - jepsen.util 0 :ok :read #{{"product_id" 2, "product_name" "test 2", "price" 2, "quantity" 2} {"product_id" 3, "product_name" "test 3", "price" 3, "quantity" 1}}

INFO [2021-06-07 05:01:28,900] jepsen test runner - jepsen.core Run complete, writing

INFO [2021-06-07 05:01:28,949] jepsen test runner - jepsen.core Analyzing...

INFO [2021-06-07 05:01:29,102] jepsen test runner - jepsen.core Analysis complete

INFO [2021-06-07 05:01:29,106] jepsen results - jepsen.store Wrote /home/nkalyanov/jepsen-crdt-

cart/jepsen.crdtcart/store/noop/20210607T050111.000+0300/results.edn INFO [2021-06-07 05:01:29,128] jepsen test runner - jepsen.core

{:perf

{:latency-graph {:valid? true}, :rate-graph {:valid? true},

XIII Международная научно-практическая конференция :valid? true}, :set

{:ok-count 2, :valid? true, :lost-count 0, :lost "#{}", :is-expected true, :ok-removed "#{4}", :acknowledged-count 3, :stale-count 2, :stale "#{2..3}", :recovered "#{}", :ok "#{2..3}", :expected #{3 2}, :ok-removed-count 1, :attempt-count 3, :unexpected "#{}", :unexpected-count 0, :recovered-count 0}, :timeline {:valid? true}, :valid? true}

Everything looks good! ^

i Надоели баннеры? Вы всегда можете отключить рекламу.