Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Raft

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

Различные реализации этого алгоритма используются в etcd (т.е. и в Kubernetes тоже), Docker swarm, Consul, Kafka (там называется KRaft), Hazelcast, RethinkDB, Aeron. У него довольно много реализаций. Например, команды HashiСorp, RabbitMQ и Redis делали его реализации, не связанные с основными продуктами, но с оглядкой на них.

Ссылка

Порядок запуска тестов

Юнит-тесты на то и “юнит”, что они изолированы от всего и независимы от всего. Они должны себя вести одинаково в любое время дня, в любой временной зоне, в любой день, в любой год. И разумеется, порядок их запуска не должен иметь значения.

Но только не в мире Spring. При запуске тестов средствами Spring, контекст приложения, созданный в тесте, кэшируется и может быть переиспользован в одном из следующих тестов. Казалось бы, хорошая оптимизация: не нужно каждый раз дорого создавать контекст, все тесты прогоняются быстрее. Но из-за этого надо пристально следить за тем, чтобы контекст оставался чистым. Особенно, если есть какие-нибудь синглтоны или статические классы.

Так-то в любых плюс-минус интеграционных тестах надо следить за тем, чтобы удалить все ненужное и почистить за собой. Но Spring добавляет немного безумия в эту схему: многое начинает еще зависеть от того, когда в контексте появились ссылки на используемые объекты и когда контексты переключаются между собой. И тут порядок запуска тестов начинает иметь значение: от него зависит переключение контекстов. По умолчанию тесты запускаются в порядке файловой системы — очень весело потом выяснять причину упавшего на билд-сервере теста.

И до этого были flaky-тесты в проекте, но обычно их можно было лениво решить через @DirtiesContext и отложить выяснение корневой проблемы на потом. Но на прошлой неделе наступили на грабли посерьезнее, и даже эта анноташка не помогала. Проблема в итоге обнаружилась в движках Camunda (их было два: для интеграционного теста и для теста логики и проверки покрытия), которые перетирали друг друга. Решилось все назначением отдельного имени для второго движка, но осадочек остался: даже чтобы воспроизвести проблему и локализовать ее, потребовалось много времени.

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

Ссылка

Статическая типизация

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

Ссылка

Прозрачность и обратная связь

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

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

Без прозрачности любые изменения похожи на игру в рулетку — что-то меняем в надежде на улучшение результата. Чтобы не делать это вслепую (сюда можно вставить модное “data-driven”), нужно понимать систему, что гораздо проще, если она прозрачна и измеряема. На одной экспертизе, увы, далеко не уедешь, да и знания имеют тенденцию устаревать.

Обратная связь может быть как одним из инструментов измерения, так и инструментом корректировки. И работающая обратная связь сама по себе приводит к большей прозрачности, если она реализована через людей: если предложение сработало, то это должно быть измеримо (иначе следующая ОС будет “вернуть все как было”), а если нет — то должно быть внятное объяснение, почему. Отрицательный результат ОС тоже развивает систему: повышается экспертиза тех, кто давал эту ОС. Как следствие получается, что обратная связь должна быть и на сам процесс обратной связи, т.е. это рекурсивная структура.

Разумеется “работающая” тут неспроста: наличие ОС само по себе не сделает систему лучше.

Ссылка

Шпаргалка по отладке проблем kubernetes

Странноватая блок-схема по решению проблем, но в целом содержит полезную информацию уровня “куда еще стоит посмотреть” и типовые команды для просмотра информации о состоянии кластера. Бонусом идет краткое описание того, как устроен кластер.

В блок-схеме меня позабавили пункты “Unknown state” и “Consult StackOverflow”, да и довольно много информации видно в стандартном дашборде. Но есть и полезное: например, команда kubectl logs <pod-name> --previous, которая выводит логи предыдущего экземпляра контейнера, пригодится для отладки проблем, когда приложение падает почти сразу после старта.

Ссылка

OWASP наглядно

В продолжение темы про OWASP — можно почувствовать себя кулхацкером скрипт-кидди и посмотреть, как работают OWASP Top-10 “вживую”: https://application.security/free/owasp-top-10. На сайте представлены интерактивные примеры, где подробно разжевывают каждый шаг по эксплуатации уязвимости.

Ссылка

Timeout для команды

Перед любой командой можно приписать timeout Xs, и она будет завершена после указанного времени, если сама не успела завершиться. Например

timeout 5s yes "I WILL NOT WASTE CHALK"

Причем если команда завершилась по таймауту, то будет специальный код возврата (124), а если успела выполнится сама — ее обычный код. Можно еще менять сигнал с TERM на другой, например на HUP или KILL.

Ссылка

Балансировка в клиенте Elasticsearch

Выбор сервера осуществляется по round robin. Если выбранный сервер не ответил, то он кладется в бан-лист на минуту, если при следующем запросе не ответил еще раз — примерно на полторы, с увеличением интервала в 2^(failedAttempts/2) раз вплоть до 30 минут. Если сервер ответил, то он исключается из черного списка. Если живых серверов нет, то пробуем самый недавний из черного списка: если и он не отвечает, то все плохо и кидаем исключение.

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

Ссылка

Контексты Painless

В районе версии 6.5 ребята из Elasticsearch что-то сообразили и сделали документацию по контекстам Painless. В ней можно посмотреть, какие переменные доступны в скриптах Painless в зависимости от того, какая операция выполняется — reindex, update by query, скриптованный поиск и т.д. Очень не хватало этого, когда работали с 2-5 версиями и писали всякие миграции на этом “замечательном” языке.

Ссылка