Chaos engineering

Последнее, что хочется увидеть во время дебага кода — это хаос. Но что если этот хаос управляемый и запущен руками самого разработчика? Зачем умышленно устраивать турбулентность в слаженной работе своего приложения, как добиться душевного спокойствия при релизе важных фич и где точно вам пригодится практика хаос-инженерии, читайте в разговоре ведущих подкаста AppsCast с Павлом Осиповым PavelOsipov.

ux2a-7hlcywounaw27j7qihz6gg.jpeg
Алексей Кудрявцев: Всем привет! Сегодня у нас в гостях Павел Осипов из Облака Mail.ru, с которым мы поговорим о chaos engineering.

Павел Осипов: Всем привет! Я лет шесть руковожу разработкой Облака Mail.ru. За это время мы накопили много практик эконом-тестирования и одна из них — chaos engineering. Такая практика позволяет проводить серию контролируемых экспериментов по выявлению работоспособности вашей системы в условиях враждебного окружения. По итогам этих опытов вы получаете полезные инсайты. Например, вы вряд ли регулярно смотрите, как ведет себя система в условиях нестабильной сети. Если ваш пользователь часто ездит в метро или отдыхает в условиях гостиничного вайфая, сеть не так стабильна как на рабочем месте программиста. После каждого своего отпуска на море я привожу целый «портфель» логов о том, что пошло не так с приложением.

Лично мне разведение ручного хаоса позволяет получить дополнительную дозу уверенности, что все будет идти хорошо, даже если вовне приложения все плохо.


Есть ситуации, когда я доверяю ручному хаосу больше, чем автоматическим тестам.

Зрим в корень хаоса


Алексей Кудрявцев: Откуда корни такой практики?

Павел Осипов: Это серверная практика, где проблем в разы больше. Мы привыкли к понятию технического долга, а на Западе есть еще dark debt — скрытый долг, который неизбежно возникает в сложных системах. В отличие от технического долга, где мы осознанно заимствуем время себя будущего у себя настоящего, скрытый долг невидим на этапе создания системы. Он возникает на стыке компонентов или hardware и software и может повлечь за собой каскад проблем: что-то ломается на одном компоненте, накладывается на другой, и вот система лежит целиком.

Например, в 2016 году из-за каскадного отключения баз данных 2,5 часа лежал Facebook. Тогда система, которая проверяла валидность конфигурационных файлов, начала их по ошибке удалять, причем не только в кэширующей подсистеме, но и в той базе данных, которая была первичным источником.

Мне очень нравится интервью с Олегом Анастасьевым из Одноклассников о проведении учений по предотвращению инфраструктурных аварий. У них три дата-центра, которые должны быть в боеготовности 24/7, но раз в квартал случается какой-нибудь отказ. Такие учения они проводят на продакшене. С одной стороны, это кажется страшным, так как если произойдет что-то непредсказуемое, ляжет весь дата-центр и не будет доступен на проде. Но с другой стороны, этот процесс контролируемый и если что-то пойдет не так, то вы это сразу увидите, остановите, и все восстановится. Если такое произойдет в условиях боевой жизни, то включить обратно просто так не получится, а разбор причин отключения затянется надолго.

Польза хаоса в мобильной разработке


Даниил Попов: Пока речь про серверную разработку, где популярны микросервисы и возможно каскадное отключение. Можешь привести еще примеры, что проверять через chaos engineering в мобильной разработке?

Павел Осипов: Мой любимый пример — разлогины приложений. В тестовых условиях наши действия могут быть очень щадящими по отношению к приложению: зашли в настройки аккаунта, нажали кнопку «выйти», приложение вышло и при просмотре экрана логина вроде бы все хорошо. У пользователей часто бывают более экзотические ситуации. Например, клиент поменял через веб-интерфейс пароль или произошло большое количество разлогинов на других устройствах и refresh token вытеснился. Этот разлогин случается не в окне с аккаунтом пользователя, а, например, в момент работы полноэкранного просмотрщика фотографий.

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

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

Благодаря этому мы открыли интересное поведение UIKit в iOS: если при пересвечивании рутованного ViewController«а на окне модально запрезенчено другое окно, то рутованный ViewController утекает и остается жить в системе навеки вечные. Если при этом ViewController имел ссылку на сервисы, которые по логике архитектуры обязаны существовать в системе в одном экземпляре, то проблем не избежать. Например, в Облаке есть сервис автозагрузки фотографий, и, если в системе останется жить два таких сервиса, они будут выполнять кучу ненужной работы и посадят батарею устройства в два раза быстрее чем положено.

Еще курьезный случай. При появлении iOS 8 были проблемы с extensions: на некоторых устройствах, когда все permissions в настройках приложения были даны, на старте система заявляла, что в shared app group у приложения доступа нет.

Типология хаоса


Даниил Попов: Хаос вносится в систему автоматизировано на основе процентов или конфига, но нужен ли взгляд человека, чтобы понять, что пошло не так?

Павел Осипов: Хаос бывает разным: и ручным, и автоматическим. В случае с операционной системой, которая говорила, что у приложения нет доступа к shared app group, и extensions не могли получить доступ к общим ресурсам и базе данных, использовался ручной хаос, который включался с помощью галочки в системных настройках приложения. Это легко могли смоделировать ребята из QA-команды.

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

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

Когда приходит время хаоса?


Алексей Кудрявцев: Что послужило триггером для внедрения практики?

Павел Осипов: Мы пришли к этому через необходимость удешевлять тестирование. Как можно побороться с теми же проблемами разлогина? Можно написать unit-тесты на утечки, можно заморочиться и написать UI-тесты.

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


Второй триггер — до внедрения практики в нашем crash-report часто наблюдались похожие крэши с одинаковой корневой причиной. Например, что крэш произошел не из-за разлогина системы в профиле, а из-за того, что пользователь пролистывал в это время галерею фотографий. Ситуации разные, и невозможно протестить все комбинации разлогинов. Вот и захотелось придумать то, что автоматизирует процесс.

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

Отличие хаос-инжиниринга от мутационного тестирования в том, что мы автоматизировано меняем не сам продакш-код, а его окружение.


Алексея Кудрявцев: Можно ли было локализовать причину и пофиксить без chaos engineering?

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

Алексей Кудрявцев: Как долго вы уже используете эту практику?

Павел Осипов: Мы начали её использовать на заре проекта в 2012 году, потому что разрабатывать надо было быстро, а времени на широкомасштабное тестирование не выделялось. При этом это не только внушительный, но и позитивный опыт.

Даниил Попов: Если у меня в приложении что-то крэшнулось и надо завести в JIRA задачу, что починить в будущем, как эту ситуацию воспроизвести?

Павел Осипов: Нет универсального рецепта. Chaos engineering активируется в момент дебага приложения и деактивируется в момент сборки релизной версии, поэтому такие ситуации можно увидеть через логи в консоли среды разработки, из которых можно прикинуть, как поставить таску в JIRA.

Алексей Кудрявцев: Пытаетесь ли создать воспроизводимое поведение, чтобы ваша система хаоса оповещала о проблемных состояниях и предлагала внести в конфиг на старте, чтобы это состояние повторить?

Павел Осипов: Звучит космически и возможно в архитектурах типа Redux. Если архитектура позволяет записывать все действия, которые предваряли критические события, тогда это возможно. У нас не так. Такое практиковалось в мою бытность работы serverside-программистом в телекоме. Там были тесты, которые рандомизировали вход на подсистему и проверяли адекватный выход. Мы добились того, когда тест с рандомным входом крэшил систему, а в программе, которая отвечала за автоматизацию тестирования, откладывались все необходимые параметры входного запроса, чтобы можно воспроизвести.

Применяем хаос в приложении


Даниил Попов: Правильно, что такой хаос вносится в код руками?

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

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


Алексей Кудрявцев: Что вы рандомизируете кроме сети и файлов?

Павел Осипов: Мы отлаживали практику по рандомизации ответов от конкретных эндпоинтов, чтобы смоделировать поведение и хаос каждого микросервиса в отдельности. У нас закончена работа по выносу файловой системы в отдельные подсистемы, и я пробую моделировать разного рода ошибки при попытке приложения записать или считать файл. Вручную моделируется доступ к shared app group в приложении, и очень хочется начать моделировать поведение приложения, когда она стартует с экстремально малым дисковым пространством, при котором невозможно даже базу данных создать.

Алексей Кудрявцев: Это все, чем вы занимаетесь?

Павел Осипов: В принципе да. Мы еще не разгребли все те баги, которые найдены с помощью существующего хаоса. Конечно, интересно повышать хаос и переносить на другие подсистемы, но тогда мы не будем успевать фиксить столько, сколько хаос будет находить.

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

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


Это не касается биллинга, где важна корректная работа.

Алексей Кудрявцев: С другой стороны, мы не в курсе, что творится у пользователей — это сам по себе хаос, потому что ты не знаешь, куда его встроить, а куда нет, и остается только его симулировать.

Павел Осипов: Всегда нужно смотреть на ROI. Конечно, можно воспроизвести и самые экзотические кейсы, но если они единичны, то, возможно, и не являются критичными, и нет смысла их моделировать.

Сложности внедрения хаоса


Алексей Кудрявцев: Что из уже сделанного вам далось легко, а что вызвало трудности?

Павел Осипов: Привыкание к хаосу — это необычно для новичка, так как это не повсеместно применяемая практика. Сложно адаптироваться к тому, что у тебя куча ошибок. Почти на каждом экране можно получить пачку «пятисоток» или непонятных »404-х», сервер отвечает через раз. Только со временем привыкаешь, что все это бурления, и ответы от сервера моделируются самой системой.

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

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

Даниил Попов: Получается, у разработчиков на дебаге всегда по умолчанию включен хаос?

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

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


Если включать хаос дозированно и точечно, то эти редкие, но меткие выстрелы будут незаметны.

Даниил Попов: Не мешает ли хаос читабельности кода?

Павел Осипов: Когда хаос внедряется вне системы, прилепляется к готовой, то да, это выглядит неаккуратно. У нас, за счет долгого опыта использования, хаос органично вплетен в систему и изолирован настолько, что ты не замечаешь его в коде.

Алексей Кудрявцев: Вы отлавливаете много редких кейсов, фиксите их, и код обрастает костылями. Не усложняет ли это логику приложения?

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

Плюсы внедрения хаоса


Даниил Попов: Есть ли количественные показатели, которые улучшились после внедрения chaos engineering?

Павел Осипов: Для меня самая главная метрика — это внутреннее душевное спокойствие, когда я отправляю фичу в релиз.

Алексей Кудрявцев: Бизнесу душевное спокойствие не продашь. Чем аргументировать внедрение хаос-инженерии в компании?

Павел Осипов: Chaos engineering высвобождает время тестировщиков, так как появляются автоматические тесты. Те же крэши с разлогинами после внедрения практики хаоса практически исчезли из нашей JIRA.

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

У меня ощущение уверенности от результатов unit-тестов намного ниже, чем от включенного на 50% хаоса при загрузке тысячи файлов. При такой загрузке все самые невероятные комбинации точно будут зафиксированы.

У кого учиться и с чего начать?


Алексей Кудрявцев: Какие инструменты вы для этого использовали? Взяли открытые библиотеки или сами написали и выложили в open source?

Павел Осипов: Мы выложили в open source сетевую библиотеку, а специализированных инструментов и нет. Единственный, который я знаю — Netflix Chaos Monkey, который рандомно «бегает» по AWS instance и терминирует их, смотрит, все ли пошло хорошо, если определенное число контейнеров погашено. Я считаю, что написание конфигов там, где вы соприкасаетесь со смежными системами, не требует глубокой автоматизации.

Даниил Попов: Где подробнее почитать про chaos engineering?

Павел Осипов: Во-первых, сайт Principles of Chaos, на который ссылаются все ресурсы по этой теме. Во-вторых, книги Learning Chaos Engineering и Chaos Engineering Observability.

Вообще, хаос-инженерия — это практика здравого смысла и фундаментальных знаний там нет. Всегда нужно понимать, в каких местах внедрять хаос. В тоже время хаос для каждого приложения уникален? и нужно сначала понять, что нужно внедрять именно у вас.

Алексей Кудрявцев: С чего начать, если ты все-таки решился внедрить хаос?

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

Алексей Кудрявцев: Болеть в приложении может многое, но как приоритизировать? Куда лучше не соваться?

Павел Осипов: Нет нереальных вещей. Важно соотношение цены и выхлопа. Если есть богатый системный API, то обкладывать его своими обертками дорого. Если ты что-то не до конца понимаешь, то начнешь провоцировать хаос, который в природе невозможен и приведет к бесполезной борьбе. Например, если весь UIKit или API с покупками покрыть хаосом.

Хаос — это не рандомное тыканье на клавишу, а четкое понимание моделируемых ситуаций.


Алексей Кудрявцев: Насколько ты советуешь эту практику внедрять?

Павел Осипов: Я вообще советую начинать именно с внедрения хаос-инженерии, а не unit-тестов, так как это самая дешевая практика.

Заинтересовала тема хаос-инженерии? Ловите Павла Осипова на осенней AppsConf в Санкт-Петербурге 21–21 октября, где он представит свой новый доклад о Key-value базах данных.

© Habrahabr.ru