Делай как вGoogle
Скачать 5.77 Mb.
|
487 Итак, герметичное тестирование может уменьшить нестабильность в тестах с боль- шим охватом и помочь изолировать сбои, решая две важные проблемы непрерывной интеграции, которые были определены в предыдущем разделе. Однако герметичные среды также могут быть очень дорогостоящими, потому что требуют больше ресурсов и времени для развертывания. Многие команды используют комбинации герметич- ных и действующих служб в своих тестовых средах. Непрерывная интеграция в Google Теперь перейдем к реализации непрерывной интеграции в Google. Сначала мы иссле- дуем нашу глобальную систему непрерывной сборки — платформу тестирования TAP, используемую подавляющим большинством команд в Google, и рассмотрим, как она позволяет использовать некоторые приемы и решать некоторые проблемы, перечис- ленные в предыдущем разделе. Вы узнаете, как преобразование непрерывной интегра- ции помогло масштабировать приложение Google Takeout как платформу и как услугу. TAP: ГЛОБАЛЬНАЯ СИСТЕМА НЕПРЕРЫВНОЙ СБОРКИ В GOOGLE Адам Бендер Мы в Google используем систему массовой непрерывной сборки для всей нашей кодовой базы, которая называется TAP. Она отвечает за выполнение большинства наших автома- тических тестов. Как прямое следствие использования монолитного репозитория, TAP является шлюзом для почти всех изменений в Google. Каждый день она обрабатывает более 50 000 уникальных изменений и выполняет более четырех миллиардов тестов. TAP — это сердце инфраструктуры разработки в Google. Концептуально ее рабочий процесс очень прост. Когда инженер пытается отправить код в репозиторий, TAP выполняет соот- ветствующие тесты и сообщает об успехе или неудаче. Если тесты выполнятся успешно, изменения включаются в кодовую базу. Оптимизация предварительной проверки Чтобы быстро и последовательно выявлять проблемы, тесты должны выполняться для каждого изменения. Но выполнение тестов обычно остается на усмотрение отдельного ин- женера, и это часто приводит к тому, что несколько мотивированных инженеров пытаются выполнить все тесты и выявить все сбои. Как обсуждалось выше, долгое ожидание выполнения всех тестов на этапе предварительной проверки, для чего порой требуется несколько часов, может действовать разрушительно. Чтобы минимизировать время ожидания, подход к непрерывной сборке в Google позволяет вносить критические изменения в репозиторий (как вы помните, они сразу становятся видимыми для всей компании!). Все, что мы просим у инженера, — это создать быстрое подмножество тестов, часто из юнит-тестов проекта, которые можно запустить до отправ- ки изменения (обычно до обзора кода) в репозиторий. Опытным путем установлено, что изменение, успешно прошедшее предварительную проверку, имеет очень высокую веро- ятность (95 % и выше) успешно пройти остальные тесты, и мы оптимистично позволяем интегрировать его, чтобы другие инженеры могли начать его использовать. После отправки изменения мы используем TAP для асинхронного выполнения всех тестов, так или иначе затронутых изменением, включая большие и медленные тесты. 488 Глава 23. Непрерывная интеграция Когда изменение вызывает сбой теста в TAP, оно должно быть исправлено максимально быстро, чтобы не препятствовать работе других инженеров. Мы установили культурную норму, не рекомендующую приниматься за любую новую работу, которая может быть за- тронута неудачными тестами, однако специализированные тесты затрудняют следование ей. Поэтому, когда предпринимается попытка зафиксировать изменение, нарушающее нормальную сборку проекта в TAP, такое изменение может помешать команде двигаться вперед или выпустить новую версию. Поэтому незамедлительно устранять ошибки жиз- ненно необходимо. Чтобы справиться с такими проблемами, в каждой команде есть «наблюдающий за сбор- кой». Перед ним стоит задача — обеспечить успешное выполнение всех тестов в проекте, независимо от принадлежности ошибки. Когда наблюдающий получает уведомление о не- удаче теста в своем проекте, он откладывает свою работу и исправляет ошибку. Обычно для этого он выявляет проблемное изменение и определяет, нужно ли его откатить (пред- почтительное решение) или исправить в будущем (более рискованное решение). На практике возможность зафиксировать изменения до проверки всеми тестами дей- ствительно окупила себя: среднее время ожидания для отправки изменения составляет около 11 минут, и часто отправка выполняется в фоновом режиме. Введя неформальную должность наблюдающего за сборкой, мы получили возможность устранять ошибки, об- наруженные продолжительными тестами, с минимальными задержками. Выявление причин Одна из проблем, с которыми мы сталкиваемся в Google при работе с большими наборами тестов, — поиск конкретного изменения, вызвавшего сбой во время тестирования. По идее, в этом не должно быть ничего сложного: получить изменение, выполнить тесты и, если какие-то тесты завершатся неудачей, отметить изменение как плохое. К сожалению, из-за того, что проблемы возникают часто и иногда причина кроется в самой тестовой инфра- структуре, не всегда есть полная уверенность в том, что сбой вызван изменением. Хуже того, TAP должна оценивать очень много изменений в день (более одного в секунду) и не запускать каждый тест при каждом изменении. Для этого она использует пакетную обра- ботку связанных изменений, что сокращает общее количество выполняемых тестов. Этот подход может ускорить выполнение тестов, но точно так же он может затруднить выявление в пакете изменения, которое привело к сбою. Для ускорения выявления причин сбоев мы используем два подхода. Во-первых, TAP автоматически разбивает пакет с ошибкой на отдельные изменения и повторно выполняет тесты для каждого компонента. Иногда этот процесс может занять некоторое время, прежде чем будет обнаружен сбой, поэтому мы также создали инструменты для поиска причин, которые разработчики могут использовать для бинарного поиска изменений в пакете. Управление сбоями После выявления «виновника» сбоя важно исправить ошибку как можно быстрее. Наличие неудачных тестов может быстро подорвать доверие к набору тестов. Как упоминалось выше, за исправление ошибок, выявленных в ходе сборки, отвечает наблюдающий за сборкой. Самый эффективный инструмент наблюдающего — это откат. Откат изменения часто является самым быстрым и безопасным способом восстановить сборку, потому что он восстанавливает систему до заведомо исправного состояния 1 1 В Google любое изменение в кодовой базе можно отменить двумя щелчками мышью! Непрерывная интеграция в Google 489 Фактически в TAP недавно была добавлена возможность автоматического отката изменений при высокой уверенности, какое именно изменение стало причиной сбоя. Быстрые откаты работают рука об руку с наборами тестов и обеспечивают высокую про- дуктивность. Тесты дают нам уверенность в необходимости изменений, откаты — в не- обходимости отмены этих изменений. Без тестов откат не будет безопасным. Без откатов неработающие тесты будет невозможно исправить быстро, что снизит доверие к системе. Ограничения на ресурсы Инженеры могут запускать тесты локально, и все же большинство тестов выполняется в распределенной системе сборки и тестирования под названием Forge. Forge позволяет инженерам запускать свои сборки и тесты в наших центрах обработки данных параллельно. В нашем масштабе для выполнения всех тестов, запускаемых инженерами вручную, и всех тестов, запускаемых в процессе непрерывной сборки, требуются огромные ресурсы. Даже с учетом имеющихся у нас вычислительных ресурсов такие системы, как Forge и TAP, ограничены в ресурсах. Чтобы обойти эти ограничения, инженеры, управляющие плат- формой TAP, придумали несколько способов, помогающих определить, какие тесты сле- дует запускать и когда, чтобы гарантировать, что на проверку изменения будет потрачен минимальный объем ресурсов. Основным механизмом выбора тестов для запуска является анализ графа зависимостей для каждого изменения. Распределенные инструменты сборки в Google, такие как Forge и Blaze, поддерживают версию глобального графа зависимостей почти в масштабе реального времени, и этот граф доступен платформе TAP. Благодаря этому TAP может быстро опре- делить, какие тесты следует выполнить для любого изменения, и запустить минимальный набор, чтобы проверить безопасность изменения. Еще один фактор, влияющий на работу TAP, — скорость выполнения тестов. TAP часто использует для проверки изменения сокращенный набор тестов. Это побуждает инженеров писать узконаправленные изменения. Разница во времени между ожиданием выполнения 100 тестов и 1000 тестов может составлять десятки минут в напряженный день. Инженеры, стремящиеся тратить меньше времени на ожидание, в конечном итоге вносят более мелкие и узконаправленные изменения, что выгодно для всех. Пример непрерывной интеграции: Google Takeout Google Takeout начал создаваться в 2011 году как продукт для резервного копи- рования и загрузки данных. Основатели этого проекта впервые предложили идею «освобождения данных», согласно которой пользователи должны иметь постоянный доступ к своим данным в удобном формате, где бы они ни находились. Сначала Takeout был интегрирован в несколько продуктов Google в виде архивов фотографий пользователей, списков контактов и т. д., доступных для загрузки в любой момент. Однако Takeout быстро развивался и превратился в платформу и сервис для самых разных продуктов Google. Как мы увидим далее, эффективная непрерывная инте- грация играет ключевую роль в поддержании работоспособности любого крупного проекта, но особенно важна для быстро растущих приложений. 490 Глава 23. Непрерывная интеграция Сценарий 1: постоянно неработающее развертывание в среде разработки Проблема: как только Takeout приобрел репутацию мощного инструмента для из- влечения, архивирования и загрузки данных в масштабах всей компании Google, другие команды начали обращаться с просьбой открыть его API, чтобы их собствен- ные приложения тоже могли пользоваться функциями резервного копирования и загрузки, в том числе Google Drive (загрузка папок осуществляется с помощью Takeout) и Gmail (для предварительного просмотра содержимого файлов ZIP). В итоге Takeout вырос из службы, предназначенной только для оригинального продукта Google Takeout, в API для как минимум десяти других продуктов Google, предлагающий широкий спектр возможностей. Команда решила развернуть каждый из новых API в виде отдельного экземпляра, используя имеющиеся двоичные файлы Takeout, но настроив их для работы в не- сколько ином контексте. Например, среда для Google Drive имела самый большой парк, наибольшую часть, зарезервированную для извлечения файлов из Drive API, и некоторую логику аутентификации, позволяющую пользователям, не выполнив- шим вход, загружать общедоступные папки. Вскоре Takeout столкнулся с «проблемой флагов». Флаги, добавленные для одного из экземпляров, нарушали работоспособность других, и попытки их развертывания прерывались, когда серверы не могли запуститься из-за несовместимой конфигу- рации. Помимо функциональных настроек имелись также настройки безопасности и ACL. Например, клиентская служба загрузки Google Drive не должна была иметь доступа к ключам, которые шифруют корпоративный экспорт Gmail. Конфигурация стала быстро усложняться и приводила к почти постоянным поломкам. Были предприняты некоторые попытки распутать и разделить конфигурацию на модули, но возникла более серьезная проблема: когда инженер Takeout хотел вне- сти изменения, он не смог вручную проверить запуск каждого сервера с каждой конфигурацией. Инженеры узнавали об ошибках в конфигурации только после развертывания на следующий день. Конечно, существовали юнит-тесты, выполняв- шиеся в ходе проверки до и после фиксации (в TAP), но их было недостаточно для выявления подобных проблем. Что предприняла команда. Команда создала для каждого из экземпляров временные изолированные мини-среды, которые запускались на этапе предварительной про- верки и оценивали возможность запуска всех серверов. Использование временных сред на этапе предварительной проверки помогло предотвратить 95 % ошибок, об- условленных неправильной конфигурацией, и снизило количество сбоев ночного развертывания на 50 %. Но новые тесты не устранили сбои развертывания полностью. В частности, сквоз- ные тесты Takeout по-прежнему часто прерывали развертывание и их было трудно запустить на этапе предварительной проверки (из-за использования тестовых учет- ных записей, похожих на настоящие учетные записи и требующих того же уровня Непрерывная интеграция в Google 491 гарантий безопасности и конфиденциальности). Сделать их более дружелюбными для тестирования было бы слишком сложной задачей. Если команда не может выполнять сквозные тесты на этапе предварительной про- верки, то когда их запускать? Разработчики хотели иметь возможность получать результаты сквозного тестирования раньше, чем будет выполнено развертывание в среде разработки, и решили, что запуск тестов каждые два часа — это хорошая отправная точка. Но команда не хотела так часто проводить полное развертывание в среде разработки из-за слишком больших накладных расходов и нарушения про- должительных процессов, которые инженеры тестировали в той же среде. Создание новой совместно используемой тестовой среды также было сопряжено со слишком большими накладными расходами, причем поиск ошибок (то есть обнаружение при- чин прерывания развертывания) мог потребовать нежелательной ручной работы. В итоге команда решила повторно использовать изолированные среды из пред- варительной проверки, расширив их для тестирования после фиксации. В отличие от предварительной проверки, проверка после фиксации соответствовала нормам безопасности для использования тестовых учетных записей (в том числе и потому, что код был одобрен), поэтому появилась возможность запускать сквозные тесты. Непрерывная интеграция запускалась каждые два часа, брала последний код и конфи- гурацию из зеленой главной ветви, создавала предварительную версию и выполняла для нее тот же набор сквозных тестов, который использовался в среде разработки. Извлеченный урок. Короткие циклы обратной связи предотвращают проблемы при развертывании в среде разработки: y Перенос тестов для разных продуктов Takeout из этапа «после ночного развер- тывания» в этап предварительной проверки помог предотвратить 95 % ошибок, обусловленных неправильной конфигурацией, и снизил количество сбоев ночного развертывания на 50 % y Перенести все сквозные тесты в этап предварительной проверки было невоз- можно, но их удалось перенести из этапа «после ночного развертывания» в этап «после фиксации в течение двух часов». Это помогло сократить количество ошибок в 12 раз. Сценарий 2: нечитаемые журналы результатов тестирования Проблема: по мере увеличения числа поддерживаемых продуктов Google Takeout превратился в зрелую платформу, позволяющую командам разработчиков добавлять плагины для выборки конкретных данных непосредственно в двоичный файл Takeout. Например, плагин Google Photos извлекал фотографии, метаданные альбомов и т. п. В результате Takeout превратился из первоначальной «горстки» продуктов в плат- форму, интегрированную более чем в 90 продуктов. Сквозные тесты Takeout записывали ошибки в журнал, но этот подход не масшта- бировался до уровня 90 плагинов. По мере роста интеграции возникало все больше отказов. Несмотря на то что с добавлением непрерывной интеграции после фиксации 492 Глава 23. Непрерывная интеграция команда проводила тестирование раньше и чаще, многочисленные сбои продолжали накапливаться, и их было легко пропустить. Просмотр журналов превратился в уто- мительную трату времени, и тесты почти всегда заканчивались неудачей. Что предприняла команда. Команда реорганизовала тесты в динамический набор на основе конфигурации (с использованием параметризованного инструмента за- пуска тестов ( https://oreil.ly/UxkHk )), который сообщал результаты, четко отмечая результаты отдельных тестов зеленым или красным цветом, благодаря чему отпала необходимость копаться в журналах. Они также значительно упростили отладку сбоев, в частности отображая информацию о сбоях со ссылками на сообщения об ошибках в журналах. Например, если Takeout не удалось получить файл из Gmail, тест динамически создавал ссылку для поиска идентификатора этого файла в журналах Takeout и включал ее в сообщение об ошибке теста. Это помогло автоматизировать большую часть процесса отладки для инженеров плагинов и уменьшило потребность в помощи со стороны команды Takeout для отправки журналов (рис. 23.3). Сре днее ко личеств о ко мментариев на ошибк у от к оманды Ta keout Рис. 23.3. Вовлеченность команды в отладку ошибок на стороне клиентов Извлеченный урок. Доступная и полезная обратная связь от непрерывной инте- грации уменьшает количество сбоев во время тестирования и увеличивает продук- тивность инженеров. Эти инициативы уменьшили вовлеченность команды Takeout в устранение ошибок на стороне клиента (плагина) на 35 %. Сценарий 3: отладка «всего кода в Google» Проблема: интересный побочный эффект от внедрения непрерывной интеграции, которого команда Takeout не ожидала, заключался в том, что из-за проверки 90 сто- ронних продуктов, ориентированных на конечных пользователей, в виде архива, они фактически тестировали «весь код в Google» и выявляли проблемы, никак не связанные с Takeout. С одной стороны, это хорошо — команда Takeout смогла внести свой вклад в повышение качества продуктов Google в целом. Но с другой стороны, Непрерывная интеграция в Google 493 это породило проблему для процессов непрерывной интеграции: команде требо- валась более полная изоляция сбоев, чтобы иметь возможность определить, какие проблемы находятся в их сборке (а их было меньшинство), а какие в микросервисах, находящихся за вызываемыми ими API продуктов. Что предприняла команда. Команда решила непрерывно запускать в продакшене тот же набор тестов, что и на этапе проверки после фиксации. Это было легко реали- зовать и позволяло команде определять, какие сбои появились в их сборке, а какие в продакшене, например в результате выпуска новой версии микросервиса где-то еще в Google. |