Как стать автором
Обновить
67
0
Антон Виноградов @randoom

Java developer

Отправить сообщение

Оно живое? 

Определенно.

Используется в Kafka и Ignite.

Я на этом чуде ускорил crash recovery с десятков секунд до десятков миллисекунд на кластерах в 100+ узлов.

 Архитектура и код вашего проекта мне неизвестны,

Apache Ignite.

https://ignite.apache.org/

https://github.com/apache/ignite

по каким-то причинам у вас это значит не работает.

Оно не НЕ работает, вопрос в необычном (для меня) подходе.

У нас есть тесты где мы останавливаем/фильтруем/изменяем сообщения например, потому что тестируем какой нить конкретный фэйловер.

При этом, тормозим мы их, реализуя "тормозитор" для конкретного теста/кейса, который тормозит только нужные сообщения или нужное число сообщений или сообщения на конкретный узел. Тоесть мы создаем именно те проблемы которые нужны тесту переопределяя необходимые компонены тестовыми имплементациями, а не располагаем проблемы по коду кроекта (с включением их через матрицу на CI).

Еще есть тесты на Ducktape - где мы "портим" окружение, но тут у нас подходы похожи.

Отсюда мой вопрос - почему был выбран этот вариант и чем он профитнее варианта создавать сложности именно в рамках конретного теста/кейса.

ERRINJ вставляем в тех местах, где нужно симулировать сбой. 

Кажется что сбой может произойти между любыми двумя строчками же. При этом сбой может быть очень разным (задержка сети, диска, памяти, etc). Имея регрессию в тысячи тестов мы, потенциально, покрываем этот момент.

Располагая же инъекции ошибок по коду - невозможно ведь вставить их везде, между всеми строками, или код ошибок будет составлять 99.999% кода проекта.

И мой вопрос здесь именно в том - как вы ухитряетесь делать мало таких вставок и эффективно ловить проблемы.

то это повлияет только на работу потока, который работает с WAL.

Поэтому в этом плане поведение детерминированное.

Не готов поверить что нет влияния одного на другое.

Когда ломается что-то, оно обязательно цепанет что-то еще, если копнуть.

У нас, например, 60к тестов и очень часто вообще несвязанные компоненты аффектятся при багфиксах. Там гонка, тут контеншен, где-то вообще пул кончился, тут вообще читаем с локальной копии (оказывается), а здесь через сеть зацепило и тд.

Про Ducktape-like не понял, что имеется ввиду.

https://ducktape-docs.readthedocs.io/en/latest/

Это, скажем так, альтернативный Jepsen вариант тестирования отказами и не только, где сценарии могут быть любыми, не только проверка ACID.

------

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

Насколько профитны такие тесты по отношению к "честным внедрениям сбоев со стороны тестового окружения"?

Вопросы все еще актуальны, очень интересно.

Супер, но тогда я вижу небольшую проблему.

Дело даже не в том

  • что "продакшен код загрязнен тeстовым" или

  • что "тестируется не то что в продакшене", а немного другой алгоритм (привет сайдэффекты! - в моей практике были случаи когда волатайл чтение помогало тестовому коду не падать, но этого чтения не было в продакшен коде :))

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

Проблема же может случиться между любыми двумя строчками, а если говорим о многопоточке - то от сочетания сайдэффектов/рассинхрона между множеством потоков.

Насколько профитны такие тесты по отношению к "честным внедрениям сбоев со стороны тестового окружения"?

Есть ли Jepsen/Ducktape-like что-то в проекте?

Если посмотрите на пример такого патча

Суровые мерж-комментарии однако :)

то думаю все вопросы отпадут

К сожалению нет. Моего знания С и Lua явно недостаточно для понимания всех нюансов фикса.

Из того что вижу (скорректируйте где ошибся)

1) В продакшен код (в кору) добавляются методы вида `ERROR_INJECT(XXX, ...`

2) Срабатывают такие методы если в сценарии сказать `_(XXX, ERRINJ_BOOL, {.bparam = true})\`, видимо это настраивается на CI, так как по дефолту - false.

3) Итого тестовый код перемешан с рабочим, но отделен семантически через `ERROR_INJECT(...`.

Так все-же, что на картинке?

Кто и как вносит изменения в код, и когда?

тем самым тестируем не тот код

Да, это именно то - что подтолкнуло меня к вопросу.

Не понял, что такое гитовые патчи.

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

код из статьи напоминающий git patch
код из статьи напоминающий git patch

Если все так - то при рефакторинге все рискует поехать, как этот риск закрываете?

Привет, правильно я понял что error injections реализован через гитовые патчи кода?

Если да, то почему не через тестовые имплементации интерфейсов (если это применимо для LUA)?

Или, скажем, не через через фреймворки врапперы диска и прочих систем (как например сделано в Кафке - https://cwiki.apache.org/confluence/display/KAFKA/Fault+Injection)?

Сотрудники Сбертеха активно контрибьютят в Apache Ignite.
Причем, делают это с личных аккаунтов и форков (форк компании есть, но не используется) под своими реальными именами.
Таким образом, коллеги имеют возможность делать вклад с сохранением авторства, в отличие от того, как это заведено в некоторых компаниях, когда с одного аккаунта в день публикуются сотни тысяч строк обезличенного кода.
Примеры проектов где есть наш (моих коллег и мой) вклад:
github.com/apache/ignite
github.com/apache/kafka

Несколько публикаций, отвечающих на большинсво вопросов об Open Source в СБТ.
habr.com/ru/company/jugru/blog/418777 (Лидер Open Source в Сбертехе рассказывает подробнее, как у нас это устроено)
habr.com/ru/company/sberbank/blog/425043 (Зачем делать Open Sourcе на примере Apache Ignite + СБТ)
habr.com/ru/company/sberbank/blog/418997 (Конкретные примеры наших контрибьюшенов в Apache Ignite)
Да, речь не идет о таких проектах.
Я имел в виду Ignite и аналогичные ему проекты, где github лишь зеркало с кодом, а обсуждение происходит на дев-листе в сообществе.
А также проекты-хобби, где нет ничего кроме кода.
Исключительно в хорошем!
Вот пример того что «пилим» конкретно мы: habr.com/company/sberbank/blog/418997
Этот комментарий удалит НЛО :)
Кажется, я не совсем удачно выразился.
Почти каждая из этих книг — монументальный труд, на вдумчивое изучение которого потребуются многие месяцы. Тем не менее, если вы изучите «по диагонали» хотя бы несколько из них — вы получите очень релевантные нашему опыту знания, которые невозможно будет скрыть на интервью :)
По поводу того же Кормена: доказательство мастер-теоремы на практике, конечно, вряд ли пригодится, но полученные представления о способах оценки сложности алгоритмов будут очень кстати.
А что с ними не так?
Java Concurrency in Practice — точно — обязательна к прочтению :)
Это, скорее, список книг — которые стоит прочитать перед собеседованием в GridGain :)
Подробнее как это работает я планирую рассказать в следующей статье, но, вкратце:

Допустим, есть 10 локальных экземпляров IgniteAtomicSequence (по одном у и тому же имени, т.к. привязанные к одному глобальному состоянию).

При создании каждого экземпляра ему выделается, допустим, 100 идентификаторов.
Итого, первому дают номера с 0 по 99, второму с 100 до 199 и т.д.

Глобально хранится информация что было выдано 1000 идентификаторов, т.е. не сколько реально было запрошено, а сколько доступно к выдаче (или уже было выдано) на всех локальных экземплярах.

И, когда, какой то из локальных экземпляров выдает все свои 100 — он запрашивает новые 100 и глобально фиксируется что было выдано не X, а X+100 (например 1000 -> 1100).
Для каждого следующего случая окончания диапазона ситуация повторяется.

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

Размер кластера не имеет значения, т.к. состояние будет хранится всего на 2-х node (Primary и Backup).
Важно лишь — сколько будет запросов на изменение состояния в рамках одного кластера в единицу времени.
Если диапазон значений, выделяемых на одну node, большой — то запросов будет мало, как следствие — не будет контеншена на глобальном изменении состояния IgniteAtomicSequence и получение нового диапазона будет занимать минимум времени.

Итого, размер кластера не важен, а увеличение числа «клиентов» всегда можно компенсировать увеличением диапазона выделяемых значений.
Да, конечно, как вариант, вы можете использовать IgniteAtomicLong и выполнять операцию только если после инкремента получили число не превышающее заданное.
А раз в минуту/час/день сбрасывать его значение в ноль из отдельного потока.
Да, продолжим с 1000 банкоматов.
С каждого из них может поступить запрос на перевод денег, но заранее известно что можно совершать не более 20 переводов одновременно (ограничение в договоре с платежной системой).
Представим также, что сервер у нас не один, а 10 и к каждому из них приписано по 100 банкоматов.

вариант

semaphore.acquire();
doPayment(acc1, acc2, amount);
semaphore.release();

позволит ограничить нагрузку на платежную систему в соответствии с условиями договора в рамках всей системы.
Я говорю не про вычисления, а именно про операции над данными.
А операции бывают разные,
Например, возьмем, все те же, 1000 банкоматов и раз в час нужно разыграть приз — первый кто оплатит на сумму больше тысячи — победитель.
Подвох в том, что человек должен узнать что он победитель сразу после завершения операции,
Возможны ли подобные гарантии/способы синхронизации на описанных технологиях?
Все перечисленные системы накладывают ряд ограничений связанных с парадигмой Map Reduce.
В случае же с набором, описанным в статье, таких ограничений нет.
Я бы, даже, сказал что это совершенно разные подходы к решению совершенно разных задач :)

Например, у вас есть сервер и 1000 бакноматов, вам нужно чтобы все они дождались инициализации сервера.
Очень простое, с точки зрения дизайна, решение (в одну строку!):
Вы можете на каждом из них ждать latch.await(), а на сервере сделать latch.countDown().
1
23 ...

Информация

В рейтинге
Не участвует
Откуда
Россия
Работает в
Зарегистрирован
Активность