Что такое хорошая архитектура программного обеспечения?
Как выглядит хорошая архитектура, как улучшить свои навыки в её создании и почему архитекторы не всегда являются решением проблемы. Гостевая публикация Мэтью Хоторна, который создавал крупные системы в Netflix и Twitter
Чтобы попытаться ответить на этот, казалось бы, простой вопрос, я обратился к ветерану разработки программного обеспечения Мэттью Хоторну. Он работает инженером-программистом более 25 лет и является автором готовящейся к выходу книги «Добейся результата или умри, пытаясь», в которой он делится опытом работы с программным обеспечением, архитектурой и выводом продукта на рынок. Книга находится на стадии раннего выпуска и должна выйти в следующем году.
Мэтт работал в Comcast, Twitter и Netflix, где он провёл шесть лет в 2010-х. Во время его работы в Netflix каждый инженер ежедневно принимал архитектурные решения и часто выпускал новые функции, которые становились доступны десяткам миллионов пользователей — и всё это без единого упоминания должности «архитектор».
В этом выпуске Мэтт рассказывает о:
- Архитекторы не решают архитектурных проблем. В Netflix долгое время не было архитекторов, но основы архитектуры оставались прочными.
- Отказ от решения сегодняшних проблем в пользу решения проблем завтрашних: переход на AWS. Переход в облако AWS создал множество проблем для Netflix, на решение которых впоследствии потребовались серьёзные усилия. Но это также устранило существующие проблемы.
- Положительные характеристики архитектуры. Они уравновешивают практические и амбициозные задачи, объединяют людей и системы и не связаны с хорошим кодом.
- Плохая архитектура — это большой объём работы, который мало что меняет. Это всё равно что переставлять мебель в доме, который нужно снести и построить на его месте что-то более удобное.
- Удачные архитектурные решения в проектах Netflix. Необычные компромиссы, создание инструментов для сокращения объёма оперативной работы, отказ от одних ограничений в пользу других и модернизация систем для повышения их эффективности в будущем.
- Как улучшить свои навыки в области архитектуры. Разрабатывайте системы, исходя из того, что может сломаться, изучайте свою аудиторию, уделяйте внимание нужным деталям и становитесь ценным сотрудником на нескольких должностях.
Если вы хотите следить за публикациями Мэтта, подпишитесь на его рассылку Push to Prod. Вы также можете приобрести его незавершённую книгу Push to Prod or Die Trying, которая на данный момент готова на 40 %.
В Netflix мы предпочитали создавать прототипы, а не писать официальные предложения по архитектуре, в то время как в других компаниях я видел, как проваливались непрактичные предложения по архитектуре, а чрезмерно практичные архитектурные решения приносили успех, но оказывали ограниченное влияние. Другие предложения пылились на полках из-за отсутствия обсуждений и согласований, необходимых для создания общего плана.
Мне всегда казалось, что работа, определяемая фразой архитектура программного обеспечения, расплывчата, а ценность, приносимая архитекторами с большой буквы, сомнительна. Я говорю это исходя из личного опыта после моего недолгого и ничем не примечательного пребывания в должности «архитектора предметной области» — опыта, из которого я многое почерпнул, но мало что привнёс. Со временем я понял, что если и есть что-то, что я знаю об архитектуре, так это то, что:
Хорошая архитектурная работа заключается в целенаправленном решении проблем, с которыми вы сталкиваетесь сегодня, ради решения более сложных проблем в будущем. По сути, если вы не решаете свои проблемы, вы просто переставляете мебель.
1. Архитекторы не являются решением архитектурных проблем
Я проработал в Netflix 6 лет, и за это время я увидел сотни вещей, которые делали компанию уникальной. Одной из них было отсутствие архитекторов программного обеспечения — по крайней мере, в названии должности. На самом деле у нас вообще не было инженерных уровней; каждый инженер был старшим инженером-программистом.
Первые четыре года я проработал в команде Edge, в которой было около 20 инженеров, занимавшихся разработкой и эксплуатацией программного уровня, расположенного между клиентскими устройствами и внутренними сервисами. «Edge» в данном случае — это граница серверной инфраструктуры Netflix, на которую приходилась большая часть эксплуатационных нагрузок.
Казалось, что первым делом в каждом производственном инциденте мы должны были доказать, что не виноваты. Это раздражало, но было эффективно: коллеги предполагали, что если каждый запрос клиента проходит через нашу систему, то у нас должны быть логи или метрики, собранные нашей системой, которые выявляют и проясняют проблемы. Часто так и было, а если нет, то мы работали над устранением пробелов. Конечно, иногда мы действительно становились причиной инцидентов, а иногда «мы» означало «я».
За несколько лет мы решили самые насущные проблемы, повысив отказоустойчивость, создав гибкую периферийную маршрутизацию и внедрив предиктивное автомасштабирование. Если задуматься об этих и других проектах, над которыми я работал в гиганте потокового видео, то можно сказать, что архитектуры в привычном понимании там не было. Те, кто предлагал идеи, сами выполняли работу, что позволяло избежать неловкого разделения на «белых воротничков» и «синих воротничков», которое часто возникает между архитекторами и инженерами в технологических компаниях. Большинство технических идей зарождалось в «окопах», что приводило к осознанному выбору архитектурных решений, имевших очевидную ценность. Со временем мы вступили в новую эру, которая характеризовалась обильными дискуссиями о создании новых масштабных систем для решения воображаемых проблем будущего, а не реальных проблем настоящего.
В компании сформировался новый поведенческий архетип — «Архитектор». Я говорю об инженерах, которые слонялись без дела, выдвигали новые идеи и не вносили существенного вклада в повседневную работу. Они не дежурили вместе с нами, якобы потому, что их руководители хотели дать им больше времени для мозгового штурма, так что у них было достаточно времени для разговоров и интеллектуальных изысканий, в то время как остальные из нас выполняли грязную, оперативную работу. Однажды за обедом мы с коллегой обсудили эту ситуацию. «Я не знаю, как решить эту проблему», — сказал я. «Решение, — ответил он, — в том, чтобы не было архитекторов».Я рассмеялся, но потом понял, что он не шутит.
Я думал, что Netflix не нуждается в архитекторах, и рассуждал об этом в более широком смысле: действительно ли они нужны какой-либо компании? Давайте разберёмся, зачем нужна должность архитектора. Я считаю, что это пережиток старой школы:
- Дизайн: архитекторы мыслят масштабно и рисуют схемы
- Сборка: инженеры превращают схемы в код
- Тест: QA находит ошибки
- Эксплуатация: отдел эксплуатации обеспечивает бесперебойную работу систем
Эти четыре этапа неизбежны, и каждая компания подходит к ним по-своему. Представьте себе ось: слева на ней изображена отдельная роль для каждого этапа, а справа — единая роль, выполняющая все функции. Каждая компания находится где-то на этой оси.
Например, переход крупных компаний на гибкую методологию разработки сделал менее популярным подход «большой дизайн, заранее», и часто Дизайн и Сборка объединялись в один непрерывный этап. А переход к облачным технологиям, DevOps и модели «ты пишешь, ты запускаешь» часто объединяет Сборку, Тестирование и Эксплуатацию в один этап.
Итак, зачем Netflix нанял архитекторов? На мой взгляд, это было связано с масштабом: наше руководство считало, что нам нужны более масштабные и смелые идеи, чтобы переосмыслить работу наших систем, и что тем, кто должен был воплотить эти идеи в жизнь, нужна была дистанция от повседневной работы.
Звучит вполне логично, но я никогда не видел, чтобы это работало. Я не пытался это исправить — я сменил команду и перешёл в группу «Инфраструктура персонализации», которая всегда меня интересовала. Эта команда была новой, и они решали конкретные проблемы. Насколько я понимаю, команда Edge продолжила успешно ревизуализировать свою платформу.
В долгосрочной перспективе успех порождает специализацию. Вы решаете самые сложные задачи, а руководство спрашивает: «Каковы наши планы на ближайшие три года?». Формируются отдельные группы «мыслителей» и «строителей», и многие компании официально закрепляют эту роль за главными инженерами или штатными инженерами, которые по сути являются архитекторами. По моим наблюдениям, людям, занимающим эти должности, трудно не отрываться от реальности: их умственные способности велики, но структура и стимулы затрудняют поиск подходящих целей.
2. Решение сегодняшних проблем ради завтрашних: переход на AWS
Самый значительный компромисс, который я наблюдал в Netflix, был связан с решением, принятым ещё до моего прихода в компанию: перенос всей инфраструктуры на AWS. «Ну и что?» — можете подумать вы. Многие компании используют AWS.
Конечно, многие компании делают это сегодня, но в 2010 году ни одна крупная компания этого не делала. Я помню, как читал несколько блогов постов о миграции Netflix на AWS до того, как устроился туда, и думал: «Они сумасшедшие». Но после того, как я устроился и увидел ситуацию своими глазами, я понял, что в этом есть смысл.
Каковы последствия работы в центре обработки данных, в локальной, не облачной среде?
- Стабильная сеть и оборудование.
- Ограничения по фиксированной мощности. Возможно, нет на постоянной основе фиксировано, но мощность можно увеличить по мере приобретения, установки и подключения оборудования.
Каковы последствия работы в AWS или других облачных средах?
- Практически неограниченная, эластичная ёмкость.
- Нестабильная работа сети и оборудования. Если слово «нестабильная» звучит резко, давайте скажем «намного менее стабильная, чем хотелось бы».
Если бы дело было только в этом, то экономическая целесообразность использования эластичных мощностей была бы достаточно веской, чтобы считать миграцию на AWS выгодной сделкой. Но с точки зрения команды Edge, эта сделка привела к возникновению множества других проблем.
- Зацикленность на отказоустойчивости при создании библиотек для реализации автоматических выключателей, ограничений параллелизма и резервных копий, а также информационных панелей для отслеживания этого поведения в режиме реального времени.
- Обнаружение и завершение работы неисправных инстансов AWS.
- Доработка обнаружения сервисов и балансировки нагрузки программного обеспечениядля сотен эластичных кластеров.
- Точная настройка политик реактивного автомасштабирования.
- Отказ от реактивного автомасштабирования и создание прогностической системы автомасштабирования с нуля.
Этих проблем у нас не возникло бы, если бы мы остались в дата-центре. Но они были в разы лучше, чем программное обеспечение с фиксированной пропускной способностью и ограниченным ростом клиентской базы. Это был не только хороший компромисс для бизнеса, но и катализатор для улучшения наших инженерных возможностей в планетарном масштабе.
3. Хорошие архитектурные характеристики
Давайте обсудим несколько характеристик хорошей и плохой архитектуры.
Хорошая архитектура не связана с хорошим кодом
В самом начале моей карьеры я присутствовал на совещании и наблюдал, как недавно принятый на работу опытный инженер в течение 30 минут что-то лихорадочно рисовал на доске. Я понятия не имел, о чём он говорит, но старшие коллеги его очень уважали, поэтому я внимательно слушал.
Несколько недель спустя у меня появилось свободное время, и мы вместе начали воплощать в жизнь некоторые из его идей. Его код был ужасен, и ему с трудом удавалось заставить что-либо работать. Но он сказал кое-что, что показалось моему юному разуму глубоким:
«В пользовательском интерфейсе у нас жёстко прописаны SQL-запросы, — сказал он.
— Нам нужно изменить это так, чтобы пользовательский интерфейс обращался к сервису, который абстрагирует запрос за счёт концепции, например „получить все элементы для текущего пользователя“».
Это отличная идея, подумал я. За следующие несколько лет я многому научился у него в плане тестирования, разделения задач, горячего и холодного хранения, сжатия, форматов и схем данных и многого другого. Но я так и не понял, как человек, который так плохо пишет код, может иметь такие чёткие представления о проектировании систем. Появилась более важная мысль:
Способность человека писать качественный код совершенно не зависит от его способности создавать или распознавать качественную архитектуру.
Я работал с руководителями технических отделов, которые годами не писали код, но при этом прекрасно разбирались в технических основах. Когда было нужно, они брали бразды правления в свои руки и направляли свои команды, уводя их от дорогостоящих ошибок и открывая перед ними широкие возможности. У них не было особых навыков программирования, но они обладали безупречным чувством стиля, интуицией и вкусом.
Я также работал с инженерами, которые были экспертами в различных тонкостях программирования, но при этом не обладали явными способностями к созданию систем, которые могли бы слаженно и функционально работать вместе. Их способность оптимально реализовывать классы или функции не выходила за рамки редактируемых ими исходных файлов.
Архитектура объединяет системы, созданные с помощью кода, но при этом является отдельной дисциплиной, имеющей мало общего с программированием. Вы не сможете с помощью LeetCode создать целостную, гибкую архитектуру, которая будет служить бизнесу.
Почему бы и нет? Давайте рассмотрим архетип «хорошо разбирается в архитектуре, но плохо пишет код». Я заметил, что таких людей привлекают самые важные детали. При разработке новой системы они задают такие вопросы:
- Какие данные мы можем собрать, чтобы обеспечить правильную работу системы?
- Какова максимально допустимая задержка для клиентов этой системы?
- Нужно ли нам рассчитывать результаты в режиме реального времени или это можно сделать в автономном режиме, в пакетном режиме?
Как правило, их меньше волнуют такие детали, как иерархия классов, названия методов и структура каталогов, которые не имеют большого значения в контексте бизнеса и распределённых систем.
Но код не может быть совершенно бесполезным, верно? Давайте рассмотрим архетип «хорошо разбирается в коде, но плохо разбирается в архитектуре». Я думаю, что он возникает, когда у людей нет опыта работы с такими вещами, как задержка в сети, резервные варианты или режимы отказа.
Обратите внимание, что я использую слово «архитектура» в значении «архитектура распределённых систем», что является общепринятым и отражает мой личный опыт.
В Netflix мы часто сталкивались с тем, что в серверных службах возникали медленные утечки памяти, которые было сложно обнаружить и устранить, потому что из-за политики автомасштабирования инстансы редко работали дольше 48 часов. Если бы мы сосредоточились на устранении утечек памяти, а не на автомасштабировании, Netflix не смог бы масштабироваться в соответствии со спросом и был бы гораздо менее прибыльным.
Хорошая архитектура объединяет людей, а не только системы
Несколько лет спустя, будучи штатным инженером в крупной компании, занимающейся социальными сетями, я возглавил проект по созданию аналитики для нашей системы персонализации контента в режиме реального времени.
Существующая архитектура была разработана на основе прототипа, созданного до моего прихода. Мы генерировали события в наших системах во время выполнения, которые некоторое время находились в очереди, прежде чем экспортироваться во внешнее хранилище данных.
В ходе этих мероприятий была получена следующая информация:
- Какой контент кому был показан в какое время
- Оценка модели машинного обучения для каждой пары пользователь/товар
- Отслеживайте предвзятость на разных этапах персонализации: от подбора кандидатов до фильтрации, ранжирования и показа
- Изучайте и устраняйте такие проблемы, как:
С «социальной» точки зрения нужно было многое учесть:
- Моя очередь из заинтересованных лиц росла в геометрической прогрессии, поскольку каждый предлагал привлечь ещё двух человек для консультаций.
- «Нам нужен дизайн» — эту фразу часто повторяли те, с кем я разговаривал. Когда я спросил, каких целей мы не можем достичь из-за текущего дизайна, я не получил внятных ответов.
- У нас был прототип конкурирующего проекта, который, по мнению нескольких инженеров в команде, мы должны были использовать вместо текущей системы.
- Граница между тем, что было «аналитикой», и тем, что ею не являлось, была размытой. Например, нас несколько раз спрашивали, можем ли мы регистрировать функции машинного обучения вместе с аналитическими данными. Мы всегда отказывались из-за плотного графика, но я чувствовал, что мы упускаем возможность решить более масштабную и важную проблему.
Нам нужно было выработать единое видение, чтобы все были на одной волне, поэтому я написал документ с описанием проблемы, которую мы решали, — как с точки зрения бизнеса, так и с точки зрения масштаба, — и добавил несколько диаграмм. Я представил несколько вариантов доработки проекта и объяснил, какой из них, по моему мнению, был лучшим и почему. Затем я поделился этим документом.
После нескольких недель обсуждений с командой и заинтересованными сторонами ситуация не улучшилась, а стала заметно хуже. Команда была разобщена как никогда, и несколько подгрупп двигались в разных направлениях. Идея комплексного аналитического решения казалась несбыточной мечтой.
Вскоре после этого я ушёл из компании, так как понял, что это не моё. Но ещё несколько месяцев я задавался вопросом, что я мог бы сделать по-другому, чтобы добиться лучшего результата. Я всегда прихожу к одному и тому же ответу:
Я был слишком сосредоточен на решении технической проблемы, в то время как основная проблема носила социальный характер.
Моя задача заключалась не только в том, чтобы принимать оптимальные технические решения. Моя задача состояла в том, чтобы объединить всех вокруг единой концепции, независимо от того, была она технически оптимальной или нет.
В упомянутом выше случае с ранжированием видео я более года периодически лоббировал этот проект, прежде чем началась работа: я представлял слайды и рассылал их всем, кого мог найти, собирал кучу данных и делал новые слайды. На какое-то время всё затихло. А потом, наконец, звёзды сошлись, и мы начали действовать.
В корпоративном мире объективно хорошие идеи встречаются редко. Идеи не обязательно должны быть хорошими сами по себе, они просто должны двигать людей вперёд. Конечно, хорошие идеи с большей вероятностью будут двигать людей, чем плохие, но на рабочем месте что-то считается «хорошим», если с этим согласны нужные люди.
Хорошая архитектура сочетает в себе практичность и устремлённость ввысь
Примерно в 2020 году я работал главным инженером в крупной американской телекомпании. Моя работа была связана с масштабными улучшениями в области персонализированного ранжирования видео, и я вместе с архитектором работал над решением проблемы повышения гибкости ранжирования видео. Исторически сложилось так, что большая часть контента предоставлялась продуктом либо через поиск, либо через различные подборки, составленные людьми. Для полной персонализации контента требовалось по-новому объединить несколько функций, систем и команд.
Давайте вкратце поговорим об этих командах. Нашим основным партнёром была команда Search — группа из 20 или около того инженеров, которые управляли большим поисковым индексом, а также системой доступа ко всем коллекциям контента, отобранным редакторами. Их приоритетной задачей была стабильная и высокодоступная выдача релевантных результатов поиска. Обычно на внедрение изменений в их систему уходило не меньше месяца.
Мы были командой по персонализации, в которую входило около 10 специалистов по машинному обучению и инженеров-программистов. Мы владели несколькими сервисами, которые предоставляли пользователям персонализированный контент во время работы, а также многочисленными конвейерами данных и случайными пакетными заданиями. Нашим приоритетом было повышение вовлечённости пользователей за счёт максимального увеличения объёма персонализированного контента. Если бы вы попросили нас внести изменения в нашу систему, мы, скорее всего, смогли бы запустить их в производство за два рабочих дня.
Нашей целью было подготовить предложение, которое с высокой вероятностью было бы одобрено командами-партнёрами. Одним из моих личных ограничений было то, что предложение по повышению персонализации должно было быть выполнимым в рамках наших текущих обязанностей и организационной структуры. Нам нужно было увеличить скорость внедрения новых функций и экспериментов в производство, поэтому мы должны были внимательно и реалистично оценивать требования, предъявляемые к самым медлительным командам.
Мой партнёр-архитектор не согласился с этим и сказал:
«Мы должны предложить наилучшее техническое решение.
А если для этого потребуются организационные изменения, пусть этим занимаются руководители».
Это была интересная идея, но в то время предложение, требующее реорганизации, в этой компании быстро уходило в никуда. Кроме того, это ограничило бы мои возможности для написания будущих предложений.
В данном случае команда по поиску работала медленно по объективным причинам. Команда по персонализации работала быстро, тоже по объективным причинам. Одной из целей предлагаемых нами архитектурных изменений было ускорение тестирования новых моделей машинного обучения в производственной среде. Если бы добавление новой модели или настройка существующей модели требовали внесения изменений вручную и тестирования со стороны команды по поиску, мы бы продолжали работать медленно, в их темпе. Игнорировать это ограничение означало бы предлагать решение ограниченной ценности.
Распространённый стереотип об архитекторах заключается в том, что они предлагают решения, которые не работают в реальном мире. Их решения требуют предварительного создания нового, идеального мира. В нашем случае идеальный мир можно создать путём реорганизации, которая разделит команду Search, или, возможно, путём переписывания всех сервисов с нуля.
Но проблема не в том, чтобы придумать новые миры, а в том, чтобы совместить идеальный мир с тем, что существует на самом деле. Конечно, было бы идеально провести реорганизацию или переписать правила, но можем ли мы сделать что-то ценное в рамках существующих ограничений, чтобы выявить возможности, которые упускаются в текущем состоянии?
Мы стратегически подошли к решению этой проблемы и устранили её с помощью прототипирования. Мы не смогли заручиться поддержкой для масштабного предложения, поэтому предложили три разные архитектуры и запустили их параллельно с небольшим объёмом реального клиентского трафика. Вариант, который пользовался наибольшим спросом у команды по поиску, работал значительно хуже остальных, отчасти из-за некоторых архитектурных недостатков, но в основном из-за того, что они работали медленнее, чем команда по персонализации. Производственный трафик — это главное практическое отличие.
4. Плохая архитектура — это большой объём работы, который мало что меняет
Давайте обсудим роль главного инженера из «Хорошая архитектура сочетает в себе практичность и стремление к идеалу» раздела выше. Меня попросили рассмотреть предложение по «улучшению архитектуры персонализации», подготовленное инженером из команды, с которой я работал. Оно содержало чётко сформулированные решения, такие как:
- Разделение нашего монолитного «сервиса персонализации» на микросервисы.
- Запуск наших контейнеров с помощью Amazon EKS.
- Использование CloudWatch для сбора журналов.
Предложение было чётким, подробным и хорошо написанным. Оно произвело впечатление как на моего руководителя, так и на вышестоящее руководство. Но у меня было одно серьёзное опасение: в нём не рассматривались наиболее важные проблемы.
Проблема № 1: слишком сложно проводить A/B-тестирование. У нас были функциональные, но громоздкие инструменты. Распределение пользователей по тестам включало в себя:
- Поиск пользователей вручную
- ...выгрузка пользователей в файлы CSV
- ... разделение пользователей на контрольную и экспериментальную группы
- ... сбор метрик для каждой группы путем ручного запуска заданий Spark
- …или выполнение сложных запросов, связанных с файлами CSV
Процесс не был масштабируемым: одновременное выполнение большого количества тестов было сложной задачей.
Проблема № 2: слишком сложно внедрять новые модели машинного обучения. Нам нужно было внедрить новые модели машинного обучения для ранжирования видео. Мы создали библиотеку-оболочку для встроенной модели машинного обучения, которая использовалась для ранжирования видео в системе поиска и хранения, принадлежащей другой команде. Мы надеялись перейти на систему, в которой ранжирование предоставлялось бы как услуга по протоколу HTTP, или, возможно, инвертировать модель, чтобы RankingService вызывал SearchService, а не наоборот. В любом случае нам нужно было развиваться в этой области, иначе мы бы так и продолжали использовать старые модели и двигались бы очень медленно.
В целом решения, предложенные в проекте, были правильными и хорошими. Однако, если бы я заглянул на год вперёд после завершения этой работы, я бы увидел, что самые большие проблемы никуда не делись и они будут ограничивать нашу способность быстрее повышать ценность бизнеса.
Плохая архитектурная работа — это перестановка мебели, когда нужен новый дом. Может быть, здесь изменена технология или там система разделена на несколько частей, но в конечном счёте это стазис, маскирующийся под архитектуру: ничего важного не происходит.
Для этого могут быть веские причины. Для решения действительно сложной проблемы часто требуется совместная работа нескольких команд, и, возможно, некоторые из них еще не включились в процесс. Возможно, вы ждете, что продуктовая стратегия повлияет на техническую стратегию, или, может быть, ваши текущие ограничения настолько суровы, что перестановка мебели — лучшее, на что можно потратить время инженеров. Или вы можете бояться неудачи, а риск неудачи при попытке решить сложную межфункциональную проблему значительно выше, чем при решении чего-то более простого и локализованного.
Возвращаясь к предложению — оно было одобрено высшим руководством, которое внесло изменения, и всё прошло хорошо. Но мне не кажется, что что-то улучшилось настолько, чтобы это имело значение.
5. Удачные архитектурные решения в проектах Netflix
Мы обсудили несколько архитектурных нюансов и антипаттернов. Теперь давайте вернёмся к моему основному тезису о том, что хорошая архитектура — это последовательное решение существующих проблем с помощью более эффективных решений. Ниже приведены несколько моих любимых архитектурных компромиссов, к которым я пришёл за время работы в Netflix.
Необычные компромиссы: Зуул
В первый год моей работы в Netflix для трафика API использовался сторонний прокси-сервер. Внутренний Netflix API использовался практически для всего, что можно было делать на устройстве, не связанном напрямую с воспроизведением: аутентификации, поиске, получении персонализированного контента и т. д.
Сторонний прокси-сервер был надёжным, но неудобным в настройке, и у нас было мало информации о том, что он делает. Например, у нас не было возможности отслеживать количество одновременных подключений прокси-сервера к конкретной нижестоящей системе, кроме как через SSH-подключение к серверу и передачу netstat в grep, что было круто, но неудобно.
Со временем стало ясно, что наш сторонний прокси-сервер сильно ограничивает наши возможности как команды, поэтому один из наших самых талантливых инженеров начал проект по его переписыванию с нуля, и Zuul появился на свет. Это был специально созданный пограничный прокси-сервис, который обрабатывал все вызовы API, не связанные с воспроизведением, такие как аутентификация, поиск, получение персонализированного контента и подобные операции.
Переписать критически важную для бизнеса систему, которая обрабатывала более 50 000 запросов в секунду (RPS), было смелее, чем обычно, но такова была культура Netflix.
Zuul был написан двумя инженерами, одним из которых был я. Мы прошли путь от идеи до запуска в производство менее чем за шесть месяцев. Это был тернистый и увлекательный путь, особенно во время запуска, когда мы откатывали и повторно развертывали систему десятки раз, чтобы исправить различные проблемы на стороне устройства, связанные с OAuth, манипуляциями с HTTP-заголовками и тому подобным. Но быстрое обнаружение и исправление ошибок становится привычным делом, когда вы заменяете стабильную скучную систему гибкой, которую вы постоянно настраиваете и модифицируете.
Мы пошли на весьма необычный компромисс с Zuul: снижение стабильности ради значительного повышения гибкости в важной части нашего стека. Обычно стабильность не меняют ради гибкости, но мы сделали такой выбор, потому что у нас было много идей о том, как использовать эту гибкость, например:
- Пользовательские правила маршрутизации для перенаправления определённых пользователей или устройств в определённые кластеры серверных служб
- Пограничная маршрутизация и переход на другой ресурс
- Подробная информация о трафике
- Повышенная безопасность, в том числе защита от DoS-атак и мошенничества
Zuul изменил подход компании к маршрутизации трафика, не связанного с CDN. Но мне всегда было интересно, как мы использовали Zuul в нестандартных ситуациях:
- Мы взломали фильтры, чтобы удалить или преобразовать заголовки HTTP-ответов, которые вызывали ошибки на устройствах. Нам нужно было действовать очень точно, поскольку взаимодействие устройств и заголовков сильно различалось в зависимости от устройств и версий, и удаление заголовка ответа могло решить проблему на одном устройстве, но вызвать сбой на десяти других.
- Мы столкнулись со множеством особенностей устройств, в том числе с отсутствием или неправильным написанием конечных точек и параметров HTTP, странными пользовательскими схемами аутентификации и многим другим. Зачастую лучше устранить подобные недочёты в одном месте, чем распределять их по всему стеку.
- Один из коллег написал фильтр, который временно блокирует Netflix у него дома, чтобы мотивировать сына делать уроки. Фильтр легко настраивается: как только уроки сделаны, он отключается.
Создание инструментов для сокращения объёма оперативной работы: Grepzilla
В команде On the Edge в Netflix было много оперативной работы, которая постоянно отвлекала нас от повседневных дел. Часто к нам обращались случайные инженеры из других команд с вопросами вроде: «Вы не знаете, почему я получаю ответ HTTP 5xx на этот конкретный запрос?»
У нас также было много производственных инцидентов. Чтобы их устранить, нам часто приходилось отвечать на такие вопросы, как «наблюдали ли вы за последние 15 минут увеличение количества сбоев в работе каких-либо конкретных вышестоящих служб?»
Крупномасштабные инциденты — это плохо, но обычно их можно быстро устранить. По моему опыту, гораздо более болезненными были длительные проблемы с небольшим количеством запросов, которые затрагивали небольшое число клиентов. Чтобы решить такие проблемы, мы задавали вопросы, например о том, можем ли мы просмотреть все сеансы запросов с устройств типа X и найти что-то необычное.
Если ваша команда перегружена вопросами и расследованиями, можно использовать несколько подходов:
- Направляйте все запросы одному дежурному инженеру или инженеру службы поддержки
- Попробуйте нормализовать потребление с помощью JIRA, Google Forms, электронных таблиц или аналогичного инструмента
- Смиритесь с тем, что постоянные вопросы — это часть работы, и ничего не делайте, чтобы улучшить ситуацию
- Перепоручите работу подрядчикам
Мы решили найти способ справляться с большим количеством входящих запросов. Нам нужно было улучшить наши возможности по проведению расследований, а также дать возможность командам партнеров отвечать на их вопросы без нашего непосредственного участия.
Одним из внутренних инструментов, которые мы создали, был Grepzilla, распределённый аналог tail и grep, или специализированная, но значительно менее функциональная версия Splunk. Мы с коллегой работали над ним неполный рабочий день в течение трёх месяцев, пока не набралось достаточно функционала для запуска в производство. Если посмотреть шире, то можно увидеть, что мы пожертвовали необходимостью отвечать на бесконечный поток рабочих вопросов ради использования системы запросов событий в реальном времени.
Это открыло доступ к нескольким полезным функциям:
- Группировка HTTP-ошибок по зонам доступности, типам устройств, местоположению клиентов и многим другим параметрам в режиме реального времени
- Быстрое устранение ошибок в конкретных бэкенд-системах, которые давали сбой
- Для ошибок с меньшим количеством символов нужно найти конкретные узлы, на которых возникла ошибка, чтобы мы могли SSH подключиться к ним и найти более подробную информацию в журналах ошибок
- Поиск медленных запросов с последующим разделением их на самые медленные подзапросы для выявления основных причин задержек
Grepzilla действительно помогла нам сократить время, затрачиваемое на расследование пограничных случаев. Однажды я заметил всплеск трафика в нашем европейском кластере Zuul, запустил Grepzilla для анализа трафика и увидел, как в режиме реального времени происходит атака по словарю, в ходе которой злоумышленник перебирал пароли в алфавитном порядке.
Замена одних ограничений другими: маршрутизация на границе нескольких регионов
В 2012 году произошёл масштабный сбой в работе AWS us-east-1 в канун Рождества, который затронул многие критически важные балансировщики нагрузки Netflix.
Мы ненадолго задумались о создании собственных балансировщиков нагрузки, но решили этого не делать. Вместо этого мы расширили наши возможности, развернув Zuul в AWS us-west-2 и направив трафик с западного побережья Северной Америки на наши существующие серверы в us-east-1. Мы назвали Zuul в us-west-2 нашим Перешейком. Идея заключалась в том, что если у нас снова выйдет из строя балансировщик нагрузки в us-east-1, мы сможем перенаправить DNS на us-west-2, чтобы избежать этого. Задержка была бы выше, но и доступность была бы выше, что является хорошим компромиссом.
Но такой подход повысил отказоустойчивость только на периферии. Остальная часть нашего серверного стека по-прежнему была уязвима для сбоев в us-east-1. Поэтому мы перенесли весь наш стек в us-west-2и разделили трафик между регионами.
Очевидно, что управлять трафиком в нескольких регионах сложнее, чем в одном. Нам нужно было обеспечить разумное распределение трафика, доставлять все развертывания и изменения конфигурации во все регионы, а также определять нужный регион при отладке. Технически мы уже работали с несколькими регионами, потому что в 2011 году развернули сервис в eu-west-1 для запуска в Европе. Однако это решение было принято в первую очередь для развития бизнеса, а не для обеспечения отказоустойчивости, и не предполагало переноса существующего трафика, поскольку все европейские клиенты были новыми.
Мы отказались от сложностей и ограничений, связанных с максимальным повышением доступности в одном регионе в пользу сложностей, связанных с максимальным повышением доступности в нескольких регионах. Это позволило нам перейти от полной зависимости от одного региона AWS к частичной зависимости от нашей способности быстро и эффективно перераспределять трафик между несколькими регионами.
Это, несомненно, того стоило. Первым шагом в устранении серьёзных инцидентов в отдельных регионах стало перенаправление трафика в более стабильные регионы. Мы начали проводить плановые учения по аварийному переключению, которые сделали этот процесс более безопасным, быстрым и рутинным.
Модернизация системы для повышения эффективности в будущем: глобальные модели персонализации на основе ИИ и МО
До 2016 года многие основные модели персонализации Netflix обучались на региональном уровне. Это означало, что модели, используемые для рекомендаций контента в определённом географическом регионе, обучались только на данных пользователей из этого региона.
Одним из преимуществ такого подхода было то, что собрать обучающие данные было несложно: достаточно было отфильтровать данные из соответствующего региона. Но у этого подхода были и недостатки, один из которых заключался в том, что модель не могла обучаться глобально. Модели, обученные на данных из небольших стран, не учитывали соответствующие модели использования в других странах.
Итак, когда в 2016 году Netflix вышел на мировой рынок, то же самое сделали многие модели персонализации.
В связи с этим возникла новая проблема: необходимо было обеспечить обучение каждой глобальной модели на достаточном количестве данных из каждой страны, чтобы она могла эффективно работать со всеми участниками.
Мы отказались от простоты обучения и использования региональных моделей в пользу сложной задачи по сбору разнообразных обучающих данных для глобальных моделей. Когда в 2015 году я присоединился к команде Netflix, занимающейся инфраструктурой персонализации, я и представить себе не мог, что буду проводить большую часть времени, обсуждая обучающие данные. Но я рад, что так вышло, потому что я многому научился, например:
- При случайной выборке в наборе данных преобладают самые многочисленные группы. В то время при случайной выборке наших данных об использовании 90 % пользователей из США были бы в базе данных с длительным стажем. Это было не лучшим решением для обучения модели, которая также использовалась для обслуживания новых пользователей в Индии или Японии.
- Если вы хотите проводить обучение с использованием одинакового объёма данных по каждой стране, размер набора данных будет ограничен численностью населения самой маленькой страны. Это не лучший вариант, так как большинство моделей плохо работают при недостаточном количестве обучающих примеров.
Самое главное, что я понял: когда начинаешь детально изучать обучающие данные, тебя ждут сюрпризы. Это один из тех камней преткновения, за которые мы часто боимся браться из-за того, что находится под ними. Но несмотря на то, что под ними скрывается много неприглядного, там также есть возможности для роста.
Когда мы увидели, насколько плохи некоторые из наших обучающих данных, мы ужаснулись. Но после того, как мы это исправили, продукт стал лучше.
Когда мы обнаружили, что случайность, которую мы внедряли для 10 % пользователей, меняющихся каждые 10 дней, на самом деле не менялась, а просто месяцами показывалась одним и тем же пользователям, мы снова расстроились. Но, опять же, после того как мы это исправили, продукт стал лучше.
Хорошая архитектура — это не только выгодные сделки и не только решение проблем, чтобы завтрашний день был лучше сегодняшнего: это ещё и выбор в пользу развития бизнеса и инженерных возможностей. Это выбор того, под какие камни заглянуть, потому что преодоление уродства, скрытого под ними, сделает вас сильнее.
6. Как улучшить свои навыки в области архитектуры
Мы обсудили архитектурные нюансы и рассмотрели примеры исключительных архитектурных решений, с которыми я сталкивался за свою карьеру. Теперь я хотел бы завершить эту статью несколькими советами о том, как улучшить свои навыки в области архитектуры.
Разрабатывайте системы, исходя из того, что может сломаться
На протяжении всей своей карьеры я задавал на собеседованиях такой вопрос: я рисую простую систему, состоящую из двух сервисов, которые взаимодействуют по протоколу HTTP — один в качестве клиента (сервис 1), а другой в качестве сервера (сервис 2). Затем я прошу кандидата описать все возможные сбои в работе системы.
Обычно в ответ на это говорят, что service2 может «стать медленным», на что я отвечаю:
- Что именно означает «медленно»?
- По каким причинам запросы от сервиса 1 к сервису 2 могут выполняться медленно?
- Как измеряется задержка?
- Могут ли другие факторы влиять на воспринимаемую задержку service2 в зависимости от способа измерения?
- Каковы последствия замедления работы сервиса 2 и как их можно смягчить?
После нескольких минут разговора с кандидатом я получил довольно полное представление о его профессиональных знаниях и опыте, а также узнал несколько историй о соответствующих сбоях, во время которых он был на дежурстве.
Мы также начнём искать решения:
- Чтобы ускорить работу сервиса 2, можно добавить кэш.
- Если данные меняются нечасто, мы всегда можем проверить кэш перед отправкой запросов в сервис.
- Если запуск кластера, способного кэшировать всё, обходится слишком дорого, то какой процент обращений к кэшу можно считать приемлемым?
- Если кэш исчезнет во время сбоя, как мы сможем ограничить зону поражения?
Научитесь определять, что может пойти не так, и предлагайте решения. Мы разрабатывали систему, двигаясь в обратном направлении от эксплуатационных проблем к решениям, выраженным в системном проектировании. Если вспомнить продуктивные обсуждения архитектуры, в которых я участвовал, то можно сказать, что понимание эксплуатационных проблем было критически важным навыком, который часто недооценивался многими инженерами.
Знайте свою аудиторию
Большая часть работы архитектора или старшего инженера заключается в том, чтобы убедить аудиторию принять ваши идеи. Без этого ничего не сдвинется с мёртвой точки.
Я помню, как смотрел презентацию, в которой была идея, которая запала мне в душу: цель любой презентации — убедить аудиторию совершить какое-то действие. Всё, что вы говорите, должно быть направлено на достижение этой цели.
Но вы не убедите инженера, используя ту же точку зрения, данные и формулировки, которые применили бы к руководителю. Точно так же вы не убедите менеджера по инжинирингу так же, как менеджера по продукту. Если копнуть глубже, то успешный подход может отличаться в зависимости от того, где находится человек — в районе залива Сан-Франциско или в Индии, не говоря уже о других странах, сферах и отраслях.
Перед каждым разговором тщательно продумывайте, какие действия вы хотите, чтобы совершила аудитория, и следите за тем, чтобы ваши слова и схемы способствовали достижению этой цели. Если вы знаете свою аудиторию — кто эти люди, что они знают и чего не знают, чего они хотят, — то эта задача становится намного проще.
Сосредоточьтесь на правильных деталях
При решении любой проблемы необходимо учитывать множество деталей, и некоторые из них гораздо важнее других. Один из первых шагов в решении проблемы — определение ключевых деталей и преобразование их в решения с помощью списка доступных вариантов.
Для этого есть несколько причин. Во-первых, нужно определить все решения, которые необходимо принять. Во-вторых, нужно классифицировать решения как важные или не очень. Незначительные решения можно отложить или делегировать кому-то другому, чтобы сосредоточиться на самых важных. Эти два типа решений можно сравнить с «односторонними» и «двусторонними» дверями, о которых говорил Джефф Безос в письме акционерам Amazon в 2015 году.
Ещё одна причина такого подхода заключается в том, что вы можете эффективно донести до аудитории лишь несколько идей за раз. Предложение будет гораздо более убедительным, если вы сосредоточитесь на двух решениях, а не на двадцати. А если вы рецензируете чужое предложение, то ваши комментарии с большей вероятностью возымеют эффект, если вы ограничитесь несколькими существенными замечаниями, а не двадцатью незначительными претензиями.
Если говорить конкретнее, то одна из деталей, которая часто не даёт мне покоя, — это задержка. За эти годы я видел множество предложений, связанных с вычислениями, которые невозможно выполнить за приемлемое время из-за таких ограничений, как логическая последовательность, размер данных и задержка в сети. Если вы спросите об этом на совещании или при обсуждении документа, вам могут ответить: «Мы разберёмся с этим позже». Но «позже» — это слишком поздно, если фундаментальные аспекты архитектуры невозможно оптимизировать для достаточно быстрого выполнения. Чтобы донести эту мысль, вам действительно нужно углубиться в детали. В долгосрочной перспективе это будет только лучше.
Сосредоточьтесь на главном, чтобы лучше соображать и выражать свои мысли, а также добиться максимального эффекта. Ваше время, энергия и умственные способности ограничены, как и у всех остальных.
Сделай себя полезным
Независимо от должности или стажа работы, все мы занимаемся тем, что переводим проекты из стадии идеи в стадию реализации. Если следующий шаг неясен, найдите способ — любой способ — двигаться дальше.
Это может быть связано со многими вещами. Вот несколько личных примеров:
- Потратьте месяц на то, чтобы повысить скорость развёртывания, так как это позволит добиться многих улучшений в дальнейшем.
- Руководить проектом, выступая посредником между несколькими командами, которые не ладят друг с другом.
- Написание стратегических или концептуальных документов или помощь коллегам в их доработке.
- Написание тестов, инструментов или скриптов для повышения надёжности или удобства использования конкретной системы.
Этот список можно отнести к «черновой работе», поэтому следите за тем, сколько времени вы на неё тратите, если ваша организация не ценит её. Но я заметил, что если вы зарекомендовали себя как компетентный специалист, то заполнение этих пробелов и продвижение вперёд могут расширить ваши возможности в будущем. Кроме того, я заметил, что архитекторам, которые не боятся запачкать руки и выполнять чёрновую работу, гораздо проще оказывать влияние на других. Авторитет можно заслужить разными способами, и это один из них.
Постоянно приносить пользу, выполняя несколько функций, — хороший способ быть ценным сотрудником. Самые эффективные старшие инженеры и архитекторы, которых я встречал, совмещали в себе роли инженера, технического директора, менеджера по продукту и руководителя проекта. Диаграммы последовательности и крупные технические инициативы — это круто, но не всегда необходимо, в то время как умение продвигать проекты вперёд — критически важный навык.
Выводы
За свою более чем 25-летнюю карьеру я видел, как архитектурная работа принимает самые разные формы: от документов до манифестов, от концепций до «воздуха», от смелых переписываний до бессмысленных, а также от обычной работы над функциями до масштабного брендинга.
Если ваши проблемы не решаются, значит, не решается и проблема с архитектурой, а также с технологиями, которые лежат в основе вашего бизнеса. Это универсальный принцип.
За время моей работы в Netflix компания была далека от идеала, но мы решали архитектурные проблемы лучше, чем где-либо ещё, где я работал. На ум сразу приходят две причины: практический подход к решению проблем и бесстрашие.
Временами это бесстрашие приводило к серьёзным проблемам. Меня будили в 3 часа ночи, и я работал по 60 с лишним часов в неделю чаще, чем мне хотелось бы. Но я сталкивался и с другой крайностью: часами просиживать на совещаниях, выбирая OKR, и неделями дорабатывать квартальные планы. Позвольте мне сказать, что слишком медленное развитие вредит гораздо сильнее, чем слишком быстрое.
Если вам пригодились мои наблюдения об архитектуре и вы не знаете, как быстрее перейти от идеи к реализации, смело обращайтесь ко мне через мою консалтинговую компанию Supreme Informatics. Спасибо, что прочитали. А теперь идите и что-нибудь постройте!
Гергели здесь. Большое спасибо Мэтту за то, что он объяснил, что для него значит хорошая архитектура и как в ней совершенствоваться. Вы можете следить за Мэттом в LinkedIn и подписаться на его рассылку Push to Prod. И, конечно же, его книга о создании устойчивых к сбоям систем в настоящее время находит своё завершение.
Что для вас значит хорошая архитектура программного обеспечения? Поделитесь своими мыслями в комментариях.
Перевод: https://newsletter.pragmaticengineer.com/p/what-is-good-software-architecture