Pull to refresh

Comments 24

Спасибо! Интересная библиотека, нужно будет попробовать.
Можно ли динамически добавлять новые узлы в кластер? И что происходит при split brain?
Динамическое добавление пока не поддерживается. Планирую добавить в следующей версии, благо сам протокол raft это позволяет. При разделении кластера — в случае если в одном из подкластеров больше половины нод — этот подкластер будет работать. Если во всех подкластерах меньше половины машин — коммиты транзакций происходить не будут (хотя они по прежнему будут добавлятся в лог старого лидера). Как только кластер восстановится — произойдет выбор нового лидера (предпочтение будет отдано ноде с логом наибольшей длины) и попытка закоммитить имеющиеся транзакции.
Скажите, пожалуйста, какие ограничения этот класс накладывает на экземпляры своих классов в плане сериализации? Все ли данные, которые содержатся в экземпляре, должны быть сериализуемы pickle?

Верно ли, что изменения передаются в виде вызовов таких же методов на остальных нодах? Если какой-либо вызов какого-либо replicated метода инициализирует свойство экземпляра из внешнего объекта или из результата вызова системной функции, то содержимое на каждой ноде может получиться разным? К примеру, если метод записывает в свойство текущий timestamp.
Все ли данные, которые содержатся в экземпляре, должны быть сериализуемы pickle?

Именно так. Аргументы методов так же должны быть сериализуемы.
Верно ли, что изменения передаются в виде вызовов таких же методов на остальных нодах? Если какой-либо вызов какого-либо replicated метода инициализирует свойство экземпляра из внешнего объекта или из результата вызова системной функции, то содержимое на каждой ноде может получиться разным? К примеру, если метод записывает в свойство текущий timestamp.

Совершенно верно. В статье в примере distributed lock описана эта особенность. Timestamp-ы необходимо передавать в виде аргументов методам, точно так же как и сиды для рандома и прочее.
А zero-deployment есть?
Или после изменения кода класса каждый раз нужно рестартовать все кластера и деплоить его на них?
Если нету, то в топку. Лучше на GRID GAIN сидеть буду.
А вот если есть…
zero-deployment нет, но идея интересная. Хотя я не очень представляю как именно это реализовать. Если на части машин будет одна версия класса, а на части машин — другая — во время применения журнала операций состояния классов разойдутся. Возможно у вас есть какие-то идеи?
Можно попробовать сперва раздать всем нодам новую версию класса, а затем в едином локе перейти на нее. Это, наверно, наложит ещё ряд ограничений на логику, которую можно размещать в методах таких классов, но, если подумать… Вот у нас есть объект. Он постоянно синхронизируется со своими зеркалами. В какой-то момент прилетела новая реализация, она откомпилировалась (да, надо делать какую-то систему передачи кода и да, это, конечно, небезопасно без должного шифрования и подписей) и наше локальное зеркало отправило всем сигнал готовности. Когда достаточная часть сети будет готова перейти на новую версию, проходит единый импульс, который заставит пиры десериализовать уже объекты свежей версии.
Да, довольно много интересных проблем выплывает. Тут и систему зависимостей надо какую-то, хотя, возможно, и опциональную, поскольку в некоторых тривиальных случаях можно делать деплой «без оглядки». Чертовски интересная тема. Хочу поучаствовать.
Насколько я понимаю тему, есть 2 концепта:
  • Erlang, Akka — distributed actors (для realtime)
  • Apache Ignite/GridGain — distributed closures (для map reduce)

zero deployment жизненно необходим для map reduce
тогда программист всегда может спросить у кластера сколько есть машин, как они загружены и т.д., а потом сказать на какой машине какой класс должен быть выполнен. При этом класс автоматически деплоится на одну или несколько машин выполняется и высылает результаты обратно.
При этом он может общаться с другими классами посылкой сообщений.
Все это программист может делать вручную, а может переложить на фреймворк.
Это все шикарно реализовано у Grid Gain. Причем они внедрили так называемые
SPI — интерфейсы позволяющие заменять например транспорт между нодами

Distributed closures дает возможность писать такой вот код:
Ignite ignite = Ignition.ignite();
// Print out hello message on all cluster nodes.
ignite.compute().broadcast(() -> System.out.println(«Hello Node!»));
в результате Hello Node! бедет напечатано на всех нодах
или скажем
ignite.compute().broadcastToLessLoaded(() -> System.out.println(«Hello Node!»));
напечатает Hello Node! на наименее загруженной ноде
В некоторых приложениях и такая (с рестартами) схема вполне подойдёт. Если наши воркеры мелкие и достаточно изолированные, хотя и требуют немного распределенных данных; если воркеры получают небольшие задания от балансера и система толерантна к падению воркеров, то можно поступить так:
— отправка свежей версии воркерам происходит такой же репликацией как и все остальное;
— получив свежую версию и проверив все подписи воркер тупо падает, запустив деплой свежей версии.
— обновленные воркеры не могут получать задания, пока их не станет большинство
— как-то так=)
обновленные воркеры не могут получать задания, пока их не станет большинство

В текущем виде они вполне себе успешно получат задания, но из за того что логика старых и новых воркеров разная — в лучшем случае старые воркеры покрешатся из за того что дернется к примеру не существующий метод — в худшем — разъедутся данные из за отличий в реализации таких-же методов.
Ну строго говоря да. Однако, можно придумать ситуации и задачи, когда гетерогенные по версии воркеры вполне могли бы сосуществовать. Например, если это, скажем, мессенджер, то, если не затронуты какие-то методы ядра, вполне можно пережить вызовы несуществующих методов. Просто сработает соответствующая деградация с сообщением, что, мол, ваш собеседник использует более свежую версию и вы не можете видеть некоторые его сообщения (например с волшебными стикерами).
Хотя я, всё же, считаю все эти деградации от лукавого. Надо просто запретить работу нового кода, пока не сложатся обстоятельства для консистентного и штатного перехода всей сетью.
Супер интересная библиотека, спасибо! Пара вопросов, если позволите:

  • Raft-кластер имеет одного лидера, в который идет вся запись. Верно ли я понимаю, что для распределения нагрузки предлагается создать несколько кластеров на разных портах?
  • Расскажите, пожалуйста, как вы тестировали вашу реализацию Raft? Доступны ли где-то исходники этих тестов?
Raft-кластер имеет одного лидера, в который идет вся запись. Верно ли я понимаю, что для распределения нагрузки предлагается создать несколько кластеров на разных портах?

Да, хороший вариант.
Расскажите, пожалуйста, как вы тестировали вашу реализацию Raft? Доступны ли где-то исходники этих тестов?

У нас есть несколько основных сценариев, среди которых падение и выбор лидера, log compaction, передача большого лога (50мб) и прочие. Исходники тестов здесь. Так же есть планы тестировать саму логику raft отдельно от сети и остальной обвязки, но для этого нужен небольшой рефакторинг.
Это очень похоже на то, что описано в статье: Реплицируемый объект. Только там я использовал С++ и другой алгоритм консенсуса.

Хотел спросить: а отличаются ли операции чтения от операций записи? Все ли операции проходят через raft?
Это очень похоже на то, что описано в статье: Реплицируемый объект. Только там я использовал С++ и другой алгоритм консенсуса.

Отчасти я вашей статьёй и вдохновился :) Начал искать нечто подобное для питона и не нашёл. Кстати, вы уже дописали replobj? Опубликовали исходники? Бегло глянул вашу статью про masterless консенсус — выглядит интересно. Это ваш собственный алогритм? Какая у него лицензия?
а отличаются ли операции чтения от операций записи? Все ли операции проходят через raft?

Через raft проходят только операции записи, чтение происходит напрямую. Все методы изменяющие состояние помечаются декоратором replicated.
Отчасти я вашей статьёй и вдохновился


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


Предлагаю поискать для других языков, чтобы убедиться, что такой подход никто не использует. По крайней мере, я ничего такого не нашел, когда начал этим заниматься.
Кстати, вы уже дописали replobj?


Вот здесь описан алгоритм:
Masterless Consensus Algorithm

Здесь код:
https://github.com/gridem/ReplobPrototype

Для верификации консенсуса использовал DAVE:
https://github.com/gridem/DAVE
Бегло глянул вашу статью про masterless консенсус — выглядит интересно. Это ваш собственный алогритм? Какая у него лицензия?


Да, собственный. Лицензия — Apache 2.0
Интересный продукт получился.
Правда я бегло просмотрел код и не нашёл намёка на шифрование.Планируете ли добавить?
Да, шифрование и авторизация — нужная фича, в одной из следующих версий обязательно добавим. Сейчас у нас оно запускается во внутренней сети, поэтому сразу и не сделали.

Очень интересно!
А двойное подчеркивание __counter и __data это корпоративная культура кода?
Почему одного подчеркивания не хватило что бы просто намекнуть?

Это общепринятый способ создания private членов класса в питоне. К таким полям не получится обратится извне на прямую.

Ясно.
Мы же все знаем, что можно к ним обратиться если захотеть и бывает что они да же мешает )
Отсюда и появился вопрос из-за любопытства, зачем использовать двойное подчеркивание и добиваться мнимой инкапсуляции.
Думал что это корпоративный стиль.

мы же все понимаем, что абсолютной приватности не существует ни в одном языке. Можно пошариться по памяти и поисправлять байтики, но это не мешает нам использовать private в java :)

Это верно )
Вот тут BDFL раскрывает тему немного "we're all adults here"


Просто давно не видел двойного подчеркивания, ковыряясь в исходниках крупных и не очень python open source проектов.
Вот интересно было применяется ли в wargaming двойное подчеркивание и это как то обоснованно.

Sign up to leave a comment.