Книга: Site Reliability Engineering. Надежность и безотказность как в Google
Назад: 26. Сохранность данных: как пишется, так и читается
Дальше: Часть IV. Управление

27. Надежный масштабируемый выпуск продукта

Авторы — Рандив Синг и Себастьян Кирш при участии Вивека Рау

Под редакцией Бетси Бейер

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

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

Рассмотрим обычный сервис компании Google, например Keyhole, который доставляет изображения со спутника для Google Maps и Google Earth. В обычный день Keyhole выдает до нескольких тысяч изображений в секунду. Но в канун Рождества 2011 года трафик увеличился в 25 раз — до миллиона запросов в секунду. Что же вызвало такой всплеск?

Прибытие Санта-Клауса.

Несколько лет назад компания Google работала вместе с NORAD (North American Aerospace Defense Command — Командование воздушно-космической обороны Северной Америки) с целью размещения сайта на рождественскую тематику, который отслеживал бы перемещение Санта-Клауса по миру, позволяя пользователям смотреть, как он разносит подарки в реальном времени. Частью задумки был «виртуальный воздушный парад», который включал в себя изображения со спутника, позволявшие отследить перемещение Санты по симулированному миру.

Несмотря на то что проект NORAD Tracks Santa мог показаться экстравагантным, он имел все характеристики сложного и рискованного запуска: жесткий дедлайн (компания не могла попросить Санту прибыть на неделю позже, если бы сайт был не готов), большая публичность, миллионная аудитория и очень резкое увеличение трафика (все хотели посетить сайт в канун Рождества). Никогда не недооценивайте силу миллионов детей, жаждущих подарков, — этот проект вполне мог поставить серверы компании Google на колени.

Команда SR-инженеров хорошо поработала для того, чтобы подготовить нашу инфраструктуру к этому запуску, гарантируя, что Санта доставит все свои подарки вовремя под пристальным взглядом аудитории. Последнее, чего мы хотели, — это заставить детей плакать из-за того, что они не смогли посмотреть, как Санта разносит подарки. Фактически мы продублировали различные аварийные выключатели, встроенные в сайт, чтобы защитить наши серверы, — «выключатели, заставляющие детей плакать». Предвидя, что запуск проекта может пойти не так множеством способов и координируя разные группы инженеров, вовлеченные работу над ним,  мы создали внутри службы SRE особую команду инженеров — координаторов запуска (Launch Coordination Engineers, LCE).

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

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

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

Управление запусками

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

Компания Google отвечает на вызовы, связанные с запусками, созданием внутри службы SRE специальной консультационной команды, которая отвечает за техническую сторону запуска нового продукта или функциональности. Эта команда состоит из программных и системных инженеров, имеющих опыт работы в других командах SRE, и специализируется на помощи разработчикам в создании надежных и быстрых продуктов, соответствующих стандартам компании Google по устойчивости, масштабированию и надежности. Эта консультационная команда, состоящая из инженеров — координаторов запуска (Launch Coordination Engineering, LCE), придает процессу запуска плавность несколькими способами. Входящие в нее специалисты:

проверяют продукты и сервисы на соответствие стандартам надежности компании Google и практическим рекомендациям, а также советуют, как увеличить надежность;

• действуют как посредники между несколькими командами, участвующими в запуске;

• управляют техническими аспектами запуска, гарантируя, что задачи будут выполняться с нужной скоростью;

• действуют как шлюз, выполняя запуски, определенные как безопасные;

• обучают разработчиков лучшим приемам и способам интеграции с другими сервисами компании Google, обеспечивая их внутренней документацией и практическими упражнениями для ускорения обучения.

Члены команды LCE проверяют сервисы несколько раз на протяжении их жизненного цикла. Большая часть проверок нового продукта или сервиса выполняется до запуска. Если команда разработчиков продукта выполняет запуск без поддержки SR-инженеров, LCE делятся своими знаниями для того, чтобы гарантировать спокойный запуск. Но даже команды запуска продуктов, уже имеющие сильную поддержку SR-инженеров, зачастую привлекают команду LCE во время критических запусков.

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

Роль инженера — координатора запуска

Наша команда координации запусков состоит из инженеров — координаторов запуска (LCE), которые либо были наняты непосредственно на эту позицию, либо перешли из службы SRE, так как имели опыт запуска сервисов Google. К LCE предъявляют те же требования, что и к SR-инженерам, они также должны иметь значительные навыки общения, взаимодействия и лидерства — LCE объединяют разрозненные группы для того, чтобы работать над общей целью, сглаживают случайные конфликты, а также направляют и обучают коллег-инженеров.

Наличие команды, координирующей процесс запуска, дает такие преимущества.

Широта опыта. Поскольку команда работает с большим количеством продуктов, ее члены действуют во всех областях деятельности Google. Обширное знание продуктов и поддержание отношений с другими командами компании позволяют LCE легко распространять знания.

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

• Объективность. Как беспристрастный советник, LCE играет роль балансировщика и посредника между заинтересованными лицами, включая SR-инженеров, разработчиков продуктов и маркетологов.

Поскольку роль инженера — координатора запуска — это роль SR-инженера, LCE также отдают приоритет надежности. Компания, которая не разделяет целей компании Google в области надежности, но стремится к быстрым изменениям, может выбрать другой набор стимулов.

Настройка процесса запуска

Компания Google улучшала процесс запуска более 10 лет. Со временем мы определили несколько критериев, которые характеризуют удачный запуск.

Упрощенность. Процесс прост для разработчиков.

• Продуманность. Во время запуска обнаруживаются очевидные ошибки.

• Доскональность. При запуске стабильно решаются наиболее важные проблемы.

• Масштабируемость. Выполняется как большое количество простых запусков, так и небольшое количество сложных.

• Адаптируемость. Процесс налажен как для распространенных видов запусков (например, добавление нового языка интерфейса для продукта), так и для новых (например, первый запуск Google Chrome или Google Fiber).

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

Простота. Усвойте основы. Не планируйте свои действия для каждого возможного случая.

• Персонализированный подход. Опытные инженеры настраивают процесс так, чтобы он подходил для каждого запуска.

• Быстрые распространенные методы. Идентифицируйте классы запусков, которые всегда выполняются по конкретной схеме (например, запуск продукта в новой стране), и обеспечьте для них упрощенный процесс запуска.

Практика показывает, что инженеры стремятся избегать процессов, которые считают слишком обременительными или не несущими пользы, особенно когда коман­да уже работает в кризисном режиме. По этой причине LCE должны постоянно оптимизировать процесс запуска, чтобы найти верный баланс между стоимостью и пользой.

Чек-лист для запуска

Чек-листы применяются для того, чтобы уменьшить количество сбоев и гарантировать стабильность и завершенность процессов в различных сферах деятельности. Распространенные примеры — карты контрольных проверок перед полетом и хирургические чек-листы [Gawande, 2009]. Аналогично LCE используют чек-лист (пример приведен в приложении Д) для оценки запуска. Этот документ помогает LCE оценить процесс запуска и предлагает запускающей команде варианты действий и ссылки на более подробную информацию. Рассмотрим примеры элементов, которые могут входить в чек-лист.

Вопрос: нужно ли вам новое доменное имя?

Действие: поговорите с представителями службы маркетинга о том, каким должно быть желаемое доменное имя, и запросите регистрацию домена. Вот ссылка на форму маркетинга.

• Вопрос: сохраняете ли вы устойчивые данные?

Действия: реализуйте ограничение скорости и квоты. Используйте следующий разделяемый сервис.

На практике о любой системе можно задать практически бесконечное количество вопросов, и чек-лист запросто может разрастись до неконтролируемых размеров. Для того чтобы нагрузка на разработчиков оставалась управля­емой, потребуется тщательно вести чек-лист. Сдержать его рост помогает то, что с какого-то момента добавление в него новых вопросов требует подтверждения вице-президента. Служба LCE при этом руководствуется следующими соображениями.

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

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

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

Сходимость и простота

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

Почти все группы в компании Google участвуют в распространенных процессах запуска, что делает чек-лист для запуска отличным инструментом улучшения сходимости для распространенной инфраструктуры. LCE могут порекомендовать вместо реализации собственного решения использовать существующую инфраструктуру как кирпичики — инфраструктуру, которая закалена годами применения и может снизить риски, связанные с производительностью или масштабируемостью. Примером является широко распространенная инфраструктура для ограничения скорости или пользовательских квот, отправки новых данных на серверы или выпуска новых версий бинарного файла. Такой тип стандартизации помогает радикально упростить чек-лист для запуска: например, обширные разделы чек-листа, связанные с выполнением требований для ограничения скорости, могут быть заменены одной строкой «Реализовать ограничение скорости с помощью системы X».

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

Запускаем неожиданное

Когда проект выходит на новый уровень, службе LCE может понадобиться создать новый чек-лист с нуля. Этот процесс зачастую включает в себя синтезирование опыта, полученного специалистами в требуемой области. При создании черновика чек-листа может быть полезно структурировать его так, чтобы выделить в отдельные разделы наиболее распространенные темы, такие как надежность, типы сбоев и процессы.

Например, до запуска Android компания Google редко сталкивалась с устройствами широкого потребления, имеющими логику клиентской стороны, которую мы не можем контролировать. Мы способны в течение нескольких часов довольно легко исправить ошибку в сервисе Gmail, отправляя новую версию кода JavaScript в браузеры, но такой способ не подходит для мобильных устройств. Поэтому LCE, работающие над запусками, связанными с мобильными устройствами, подключают к работе экспертов в этой области, чтобы определить, какие разделы чек-листа можно и нельзя создавать и когда нужно добавлять в него новые вопросы. В таких беседах важно учитывать цель каждого вопроса, чтобы избежать бездумного применения действия, которое не важно для разработки уникального продукта. LCE, столкнувшиеся с необычным запуском, должны вернуться к первым абстрактным принципам выполнения безопасного запуска, а затем индивидуализировать их, чтобы сделать чек-лист конкретным и полезным для разработчиков.

Разрабатываем чек-лист для запуска

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

Архитектура и зависимости

Обзор архитектуры позволяет определить, корректно ли сервис применяет разделяемую инфраструктуру и идентифицирует ее владельцев как дополнительных заинтересованных лиц. Компания Google имеет множество внутренних сервисов, которые служат кирпичиками для новых продуктов. На более поздних стадиях планирования производительности (см. [Hixson, 2015a]) список зависимостей, описанный в этом разделе чек-листа, может быть использован для того, чтобы убедиться, что мы правильно подготовили каждую зависимость.

Примеры вопросов чек-листа

Как выглядит поток запросов от пользователя к фронтенду и бэкенду?

• Существуют ли запросы, для которых имеются разные требования к задержке?

Примеры действий

Изолируйте запросы, с которыми работают пользователи, от запросов, с которыми не работают.

• Проверяйте предположения об объеме запросов. Один просмотр страницы может превратиться в большое количество запросов.

Интеграция

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

Примеры действий

Настройте новое имя DNS для вашего сервиса.

• Настройте балансировщики нагрузки, которые будут общаться с вашим сервисом.

• Настройте систему наблюдения для вашего сервиса.

Планирование производительности

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

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

Примеры вопросов чек-листа

Связан ли запуск с пресс-релизом, рекламой, статьей в блоге или другой формой рекламной кампании?

• Какого трафика и уровня роста вы ожидаете во время и после запуска?

• Получили ли вы все необходимые вычислительные ресурсы для поддержки своего трафика?

Типы сбоев

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

Примеры вопросов чек-листа

Имеются ли в проекте единые точки сбоев?

• Как вы справляетесь с недоступностью зависимостей?

Примеры действий

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

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

Поведение клиента

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

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

Пример вопроса

Предусмотрена ли у вас функциональность автосохранения/автозаполнения/контрольных сигналов?

Примеры действий

Убедитесь, что ваш клиент имеет экспоненциальную задержку при сбое.

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

Процессы и автоматизация

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

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

Пример вопроса чек-листа

Существуют ли ручные процессы, которые необходимы для того, чтобы сервис работал?

Примеры действий

Задокументируйте все ручные процессы.

• Задокументируйте все процессы, необходимые для перемещения сервиса в новый дата-центр.

• Автоматизируйте процессы сборки и выпуска новой версии.

Процесс разработки

Компания Google широко применяет системы контроля версий, с ними глубоко интегрированы почти все процессы разработки. Многие наши приемы связаны с эффективным использованием системы контроля версий. Например, мы выполняем бо'льшую часть разработки в основной ветви, но сборка релизов происходит в отдельных ветвях. Такая настройка позволяет легко исправлять ошибки в релизах, не требуя получения несвязанных изменений из основной ветви.

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

Примеры действий

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

• Выполняйте каждый релиз в новой ветви.

Внешние зависимости

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

Примеры вопросов чек-листа

От каких кода, данных, сервисов или событий, предоставляемых сторонними разработчиками, зависит сервис или запуск?

• Зависят ли от вашего сервиса какие-либо партнеры? Если да, то нужно ли их оповещать о вашем запуске?

• Что случится, если вы или поставщик не сможете соблюсти жесткий дедлайн запуска?

Планирование отправок

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

Внешние требования, предъявляемые командами маркетинга и PR, могут еще больше усложнить задачу. Например, команде нужно, чтобы какая-то функцио­нальность была доступна к моменту основного доклада на конференции, но оставалась скрытой до этого времени. Действия на случай непредвиденных обстоятельств — еще одна часть планирования отправок. Что если вы не сможете вовремя выпустить функциональность для доклада? Иногда эти действия сводятся к простой подготовке запасного набора слайдов, которые гласят: «Мы запустим эту функциональность в течение нескольких дней» — вместо: «Мы запустили эту функциональность».

Примеры действий

Создайте план запуска, который определяет шаги, которые нужно предпринять для запуска сервиса. Укажите ответственного за каждый шаг.

• Определите риск для отдельных этапов запуска и реализуйте действия на случай непредвиденных обстоятельств.

Избранные приемы выполнения надежных запусков

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

Постепенные отправки и отправки в несколько этапов

Поговорка из области системного администрирования гласит: «Никогда не изменяйте работающую систему». Любое изменение несет за собой риск, а он должен быть минимизирован для того, чтобы гарантировать надежность системы. То, что работает для маленьких систем, вдвойне верно для высокореплицированных глобально распределенных систем наподобие тех, что запускает компания Google.

Лишь немногие запуски в нашей компании выполняются, так сказать, нажатием одной кнопки, когда мы запускаем новый продукт в заданное время для того, чтобы его мог использовать сразу весь мир. С течением времени компания Google разработала несколько шаблонов, которые позволили нам запускать продукты и функциональность плавно и тем самым минимизировать риск (см. приложение Б).

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

Канареечные тесты — это концепция, которая встроена в большое количество внутренних инструментов компании Google, используемых для выполнения автоматических изменений, а также в системах, изменяющих конфигурационные файлы. Инструменты, которые управляют установкой нового ПО, обычно какое-то время наблюдают за поведением только что запущенного сервера, убеждаясь, что он не «падает» и ведет себя как следует. Если изменение не проходит проверку, оно автоматически откатывается.

Концепция постепенных отправок применима и к тому ПО, которое не работает на серверах компании Google. Новые версии приложения для Android также могут быть внедрены постепенно — некоторым клиентам будет предложено обновить свои устройства до обновленной версии. Процент обновленных экземпляров приложения постепенно будет увеличиваться, пока не достигнет 100 %. Такой тип отправок особенно полезен, если внедрение новой версии приводит к тому, что на серверы бэкенда в дата-центры компании Google поступает дополнительный трафик. Таким образом, мы можем наблюдать, как эта процедура воздействует на наши серверы, по мере того как мы постепенно отправляем новую версию и обнаруживаем проблемы.

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

Фреймворки флагов функциональности

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

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

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

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

Отправляют множество изменений одновременно на несколько серверов, пользователей, объектов или дата-центров.

• Постепенно увеличивают группу пользователей, обычно на 1–10 %.

• Направляют трафик через разные серверы в зависимости от пользователей, сессий, объектов и/или локаций.

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

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

• Измеряют степень влияния изменений на навыки пользователя.

Фреймворки флагов функциональности компании Google делятся на две общие категории.

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

• Фреймворки, которые поддерживают произвольные изменения серверной и бизнес-логики.

Самый простой фреймворк флагов функциональности для изменений пользовательского интерфейса в сервисе, не сохраняющем состояние, — это инструмент, переписывающий полезную нагрузку HTTP для фронтенд-серверов приложения, ограниченный подмножеством cookies или другого аналогичного атрибута запросов/ответов HTTP. Механизм конфигурации может указывать идентификатор, связанный с новыми путями кода, масштабом изменений (например, диапазон режима хеширования для cookies), белыми и черными списками.

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

Справляемся со злоупотреблениями клиента

Самым простым примером злоупотреблений клиента является неверная оценка уровня обновлений. Новый клиент, который синхронизируется каждые 60 секунд, а не каждые 600 секунд, как прежде, вызывает десятикратное увеличение нагрузки на сервис. Поведение сервиса при повторных попытках имеет несколько ловушек, которые влияют на запросы, инициированные как пользователем, так и клиентом. Рассмотрим пример сервиса, который перегружен, из-за чего некоторые запросы к нему дают сбой. Если клиенты выполняют повторные попытки запросов, да­вших сбой, они повышают нагрузку на уже перегруженный сервис, что еще больше увеличивает количество повторных попыток и повторных запросов. Вместо этого клиенты должны снизить частоту выполнения запросов, обычно добавляя экспоненциально увеличивающуюся задержку между повторными попытками в дополнение к тщательному рассмотрению типов ошибок, которые требуют выполнения повторных попыток. Например, ошибка сети обычно требует сделать повторную попытку, тогда как ошибка HTTP 4xx (которая показывает ошибку на стороне клиента) обычно этого не делает.

Намеренная или непреднамеренная синхронизация автоматических запросов в «шумной толпе» (например, описанная в главах 24 и 25) — это еще один распространенный пример злоупотреблений клиента. Разработчик приложения для телефона может решить, что два часа ночи — это хорошее время для загрузки обновлений, поскольку пользователи в это время, скорее всего, будут спать и она им не помешает. Однако этот план приводит к появлению шквала запросов к серверу загрузки в два часа ночи каждый день, и почти никаких запросов не будет в остальное время. Вместо этого клиент должен выбирать время для подобных запросов случайно.

Случайность нужно внедрить и в другие периодические процессы. Говоря об упомянутых ранее повторных попытках: рассмотрим клиент, который отправляет запрос и, когда сталкивается со сбоем, выполняет повторные попытки через 1, 2, 4 секунды и т.д. Без случайности короткий пик запросов, приводящий к повышению количества ошибок, может повториться через 1, 2, 4 секунды и т.д. Для того чтобы стабилизировать эти синхронизированные события, каждую задержку нужно «встряхнуть», то есть сдвинуть на случайный промежуток времени.

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

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

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

Поведение при перегрузке и нагрузочные тесты

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

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

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

Рассмотрим конкретный пример поведения при перегрузке: сервис записывал в журнал информацию для отладки в ответ на ошибки бэкенда. Оказалось, что делать это было гораздо дороже, чем обрабатывать ответ бэкенда при нормальном состоянии. Поэтому, как только сервис обнаруживал перегрузку и прерывал по тайм-ауту ответы бэкенда внутри собственного стека RPC, он тратил еще больше времени процессора на журналирование этих ответов, прерывая по тайм-ауту еще большее количество запросов, и это продолжалось до тех пор, пока сервис не отключался полностью. В сервисах, запущенных на виртуальной машине Java (Java Virtual Machine, JVM), похожий эффект иногда называется GC-перегрузкой (засорением сборщика мусора). В этом сценарии управление внутренней памятью виртуальной машины происходит в постоянно уменьшающихся циклах. Память освобождается до тех пор, пока все время процессора не затрачивается только на управление памятью.

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

Развитие службы LCE

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

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

Когда следует проконсультироваться с юристами.

• Как выбирать доменные имена.

• Как зарегистрировать новые домены, правильно сконфигурировав DNS.

• Какие ловушки часто встречаются при проектировании и развертывании на производстве.

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

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

Для того чтобы сгладить этот сценарий с точки зрения инженеров, в рамках службы SRE в 2004 году была создана небольшая команда LCE, работавших на полную ставку. Они отвечали за ускорение запуска новых продуктов и функцио­нальности, применяя опыт SRE для того, чтобы гарантировать, что компания Google поставляет надежные продукты, имеющие высокую доступность и низкую задержку.

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

Эволюция чек-листа LCE

По мере того как окружение компании Google становилось более сложным, усложнялся чек-лист инженеров — координаторов запуска (см. приложение Д) и рос объем запусков. В течение трех с половиной лет один LCE проводил 350 запусков с помощью чек-листа. Поскольку в команду входили в среднем пять человек, то мы выполнили более 1500 запусков за 3,5 года!

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

По мере увеличения количества запусков, а также ежегодного увеличения штата инженеров, LCE искали способ упростить свои обзоры. Они определили категории запусков с низкими рисками, которые, скорее всего, не вызовут сбоев. Например, запуск функциональности, не включающий в себя новых исполняемых файлов для сервера и повышающий трафик менее чем на 10 %, почти не несет риска. Для таких запусков применялся более простой чек-лист, а запуски, связанные с высокими рисками, проходили через весь диапазон проверок и балансировок. К 2008 году 30 % обзоров считались не несущими рисков.

Одновременно окружение компании Google масштабировалось, избавляясь от ограничений для многих запусков. Например, приобретение YouTube заставило компанию Google построить его сеть и более эффективно использовать полосу пропускания. Это означало, что множество более мелких продуктов могли «влезть в образовавшиеся трещины», избегая сложных процессов планирования производительности сети и снабжения, что ускоряло их запуски. Компания Google также начала строить очень крупные дата-центры, в которых несколько зависимых сервисов могли находиться под одной крышей. Такое развитие упростило запуск новых продуктов, нуждавшихся в значительной производительности для нескольких уже существующих сервисов, от которых они зависели.

Проблемы, которые инженеры LCE не решили

Несмотря на то что LCE старались свести к минимуму бюрократию для своих обзоров, этих усилий было недостаточно. К 2009 году сложность запуска маленького нового сервиса в компании Google стала легендой. Сервисы, чей масштаб увеличивался, сталкивались с собственным набором проблем, которые инженеры — координаторы запуска решить не могли.

Изменения масштабируемости

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

Рост операционной нагрузки

Когда сервис начинает работать после запуска, операционная нагрузка — количество ручной и повторяющейся работы, необходимой для функционирования системы, как правило, с течением времени увеличивается, если не предпринять целенаправленных усилий по управлению ею. Шумность автоматизированных оповещений, сложность процедур развертывания и нагрузка, вызываемая ручной работой по обслуживанию, с течением времени обычно растут, увеличивая полосу пропускания для владельцев сервиса и оставляя командам меньше времени на разработку функциональности. SR-инженеры должны поддерживать уровень операционной работы ниже 50 % времени (см. главу 5). Поддержание заданного уровня операционной работы, не превышающего этот максимум, требует постоянного отслеживания источников операционной работы, а также приложения усилий по их ликвидации.

Текучка инфраструктуры

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

Решение этих проблем требует значительных усилий в масштабах компании, находящихся вне компетенции LCE: комбинации более качественных API платформы и фреймворков (см. главу 32), продолжительной сборки и автоматизации тестов, а также бо'льших стандартизации и автоматизации производственных сервисов компании Google.

Итоги главы

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

Команда LCE в компании Google стала решением проблемы достижения безопасности без остановки процесса внедрения изменений. В этой главе были показаны решения, к которым приходили члены команды LCE на протяжении более чем 10 лет именно при таких обстоятельствах. Мы надеемся, что наш подход поможет вдохновить других людей, которые сталкиваются с аналогичными задачами в своих организациях.

Назад: 26. Сохранность данных: как пишется, так и читается
Дальше: Часть IV. Управление