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

Рейтинг: 5

Поделиться
Купить и скачать

Микросервисы без иллюзий. Арифметика архитектурного решения

Год написания книги: 2026
На страницу:
2 из 5
Настройки чтения
Размер шрифта
Высота строк
Поля

Переезд занял около семи лет. Все клиентские сервисы Netflix перенёс в облако AWS ещё до 2015 года; последними переезжали биллинг и данные клиентов и сотрудников. Порядок, вероятно, не случаен. Сначала переезжало то, что видит клиент, а в конце — деньги и персональные данные, где ошибка при переносе обходится дороже всего. В начале января 2016 года компания отключила последние остатки дата-центров, которыми пользовался стриминговый сервис; о DVD-бизнесе пост ничего не говорит. Архитектурный итог авторы описали одной фразой: от монолитного приложения к сотням микросервисов.

Пока шёл переезд, Netflix построил инструменты, которые потом стали символами целой эпохи. Первым публично упомянут Chaos Monkey: в декабре 2010 года инженеры Netflix в блоге компании назвали его одной из первых систем, построенных в AWS. Его работа — случайно выбирать и отключать экземпляры сервисов прямо в боевой среде. В июле 2011 года Израилевский и Ариэль Цейтлин подробно описали его вместе с семейством похожих инструментов: система должна переживать отказ машины так, чтобы клиенты этого не заметили. Код Chaos Monkey компания открыла в июле 2012 года.

Между августом 2008-го и июлем 2011-го — три года и противоположное отношение к отказу. В 2008 году повреждение базы данных остановило отправку дисков на три дня. В 2011 году компания сама отключала свои машины в боевой среде и называла такой отказ распространённым, то есть рядовым событием. Это тот же вывод из августовского сбоя, доведённый до конца. Если отказ неизбежен, систему нужно строить так, чтобы она его переживала, и проверять это на настоящей работе, а не на стенде.

В ноябре 2012 года Netflix анонсировал Hystrix — библиотеку, которая, по словам компании, выросла из работы над устойчивостью, начатой командой API в 2011 году. Hystrix реализовал circuit breaker — механизм, который после серии неудачных вызовов перестаёт обращаться к отказавшей зависимости и сразу возвращает запасной ответ, пока она не восстановится. Проще всего представить это на странице из нескольких блоков: если сервис рекомендаций перестал отвечать, страница открывается без персональной подборки, а не зависает целиком. В июне 2013 года появился Zuul — сервис на границе облака, через который проходят входящие запросы. К тому времени Netflix уже системно открывал код своих инструментов: портал открытых проектов на GitHub появился в ноябре 2011 года, а в начале 2013-го программа выступала под именем NetflixOSS. К октябрю 2015 года она насчитывала больше пятидесяти открытых проектов.

Каждый из этих инструментов отвечал на конкретную проблему конкретного масштаба. У Netflix к концу 2015 года были десятки миллионов подписчиков, около 30 млн из них — за пределами США, и требования к доступности, при которых сбой сразу видят миллионы зрителей. У большинства компаний таких условий нет. Chaos Monkey имеет смысл там, где машин так много, что отказ одной из них — вопрос не «если», а «когда»: в системе из трёх серверов случайное отключение одного было бы не проверкой, а потерей трети мощности. Hystrix нужен там, где один запрос проходит через множество зависимостей и отказ одной не должен останавливать остальные. Вместе с открытым кодом индустрия получила не только сами инструменты, но и неявное допущение, что у неё те же проблемы, что у Netflix.

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

Карточка масштаба

Компания, год: Netflix, 2008—2016; переезд стримингового сервиса в облако — с августа 2008 года до начала января 2016 года.

Инженеров: опубликованных данных нет; сотрудников на полной ставке — 1 644 на конец 2008 года и около 3 500 на конец 2015 года, без разбивки по функциям.

Пользователи / трафик: около 9,4 млн подписчиков на конец 2008 года (диски и стриминг вместе); 74,76 млн стриминговых участников на конец 2015 года; объём просмотра за восемь лет вырос, по данным компании, на три порядка.

Сервисов (до → после): монолитное приложение → сотни микросервисов (формулировка компании, 2016); точного числа компания не публиковала.

Что именно изменилось: стриминговый сервис целиком ушёл из собственных дата-центров в AWS; вертикально масштабируемые базы в дата-центре заменены горизонтально масштабируемыми распределёнными системами; отказ отдельной машины стал штатным событием, которое проверяют в боевой среде.

Источник: Y. Izrailevsky, S. Vlaovic, R. Meshenberg (2016); Netflix, годовые отчёты за 2008 и 2015 годы; Netflix Tech Blog (2010—2013); Netflix, Hystrix README (2018); T. Mauro, NGINX (2015).

Мотив Netflix смешанный, и в этом ценность случая. История начинается не с людей, которые ждут друг друга, а с базы данных, которая отказала. В посте 2016 года причины переезда названы технические: надёжность и масштаб. Организационная сторона видна в другом источнике — в пересказе выступлений Адриана Кокрофта 2014 года, который Тони Мауро опубликовал в блоге NGINX в феврале 2015 года. Там переход описан как смена модели разработки: от одной группы инженеров вокруг монолитного приложения к множеству небольших команд. Это пересказ, а не слова самого Кокрофта, и число инженеров в нём приведено без года.

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

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

В ноябре 2018 года вышла версия Hystrix 1.5.18, и в описании репозитория появился новый статус. Библиотека больше не развивается и находится в режиме поддержки. Объяснение в том же описании короткое: для существующих приложений Hystrix достаточно стабилен, и Netflix продолжает им пользоваться. Внимание компании сместилось к механизмам, которые подстраиваются под поведение приложения в реальном времени, а не работают по заранее заданным настройкам, — например, к адаптивным ограничениям числа одновременных запросов (adaptive concurrency limits). Для новых внутренних проектов Netflix назвал открытую библиотеку resilience4j.

Флагманский инструмент эпохи устарел у собственного создателя через шесть лет после анонса. Идея при этом не оказалась ошибочной: Netflix от неё не отказался. Устарел конкретный ответ — заранее заданные настройки, выросшие из задач команды API 2011 года. За шесть лет изменились и масштаб, и инфраструктура вокруг, и у того же создателя появился другой ответ на тот же вопрос. Инструменты конкретного масштаба стареют вместе с ним.

1.3. Uber: та же боль в режиме гиперроста

В сентябре 2015 года инженеры Uber начали пост о своей архитектуре с признания, знакомого многим стартапам. Компания начинала с монолита, построенного для одной услуги в одном городе: тогда весь Uber был тарифом UberBLACK, а весь его мир — Сан-Франциско. Ретроспектива компании 2020 года уточняет, что около 2012—2013 годов монолитных приложений было, по сути, два. По другим постам компании 2015—2016 годов, основное было написано на Python и хранило данные в одной базе PostgreSQL, а диспетчеризация поездок — на Node. js. Для одного города и одной услуги большего и не требовалось.

Мир компании быстро перестал помещаться в один город, и вслед за этим ускорился найм. Мэтт Рэнни, главный системный архитектор Uber, рассказывал в 2016 году, что за полтора года инженерная организация выросла примерно с 200 до 2 000 человек. Эти числа известны по конспектам его доклада; официально компания их не публиковала. Пост 2015 года описывает, что происходило с кодом при таком росте. Компоненты оказались тесно связаны, развернуть код значило развернуть всё сразу, а перед любым изменением требовалось знание, которое передавалось только из уст в уста.

Та же ретроспектива описывает этот момент коротко. Когда инженеров стало не десятки, а сотни и у частей системы появились разные команды-владельцы, монолитная архитектура «связала судьбы команд» (tied the fate of teams together). Судьба здесь вполне конкретная: ошибка одной команды могла задержать выпуск всех остальных, а правка в общем коде требовала знания, которого у новичка не было. Долю новичков показывает простая модель с двумя допущениями: численность росла с постоянным темпом, каждый месяц в одно и то же число раз, а ушедших модель не учитывает. Тогда за полтора года она удвоилась трижды с небольшим, примерно раз в пять-шесть месяцев, и в любой момент около половины инженеров работали в компании меньше полугода. Знание, которое передавалось только в разговорах, при таком темпе не успевало дойти до всех.

Выход, который нашли команды, был самым прямым: новая команда не ждала очереди в общем коде, а заводила свой сервис, который могла развернуть сама. В 2014 году сервисов, по воспоминаниям участников, было от двух десятков до сотни. Пост сентября 2015 года говорит о 500 с лишним и тут же признаёт, что найти среди них нужный стало трудной задачей. В начале марта 2016 года, по словам самого Рэнни в аннотации доклада, в боевой среде работало больше 1 000 сервисов. О двух с лишним тысячах инженеры компании писали уже в начале 2017 года. Сервисы появлялись быстрее, чем их успевали учесть.

Главный источник о цене этого роста — доклад Рэнни «What I Wish I Had Known Before Scaling Uber to 1000 Services» на конференции GOTO Chicago в мае 2016 года. По-русски смысл названия такой: что стоило бы знать заранее, прежде чем Uber дорос до тысячи сервисов. Рэнни пришёл в Uber из Voxer, где был сооснователем и техническим директором. Цену здесь описывает не внешний критик и не историк спустя десять лет, а участник, пока рост ещё идёт. Само название фиксирует порядок событий: знание пришло после сервисов, а не до них.

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

Цена пришла с той же стороны, что и выгода. Свобода выбирать инструмент добавила к двум исходным языкам Uber ещё два: официальный обзор технологий компании в июле 2016 года называл основными Python, Node. js, Go и Java. Рэнни рассказывал, что из-за этого трудно делиться кодом и трудно переходить из команды в команду, а инженерная культура начинает дробиться вместе с языками. На практике это означает, что библиотеку, уже написанную одной командой, соседней может понадобиться писать заново, а инженер, переходящий в другую команду, отчасти начинает с нуля.

Вторая цена — трассировка (tracing), то есть возможность проследить путь одного запроса через все сервисы, которые он затронул. В конспектах доклада Рэнни эта трудность объясняется так: контекст запроса нужно передавать между сервисами на разных языках. Инженер Uber Юрий Шкуро в феврале 2017 года подтвердил это уже в блоге компании. Сервисы там были написаны на четырёх основных языках, и эта разнородность, по его словам, сделала внедрение распределённой трассировки намного более трудной задачей. Узнать, через кого прошёл запрос, стало отдельным инженерным проектом.

Самое точное наблюдение доклада касается не технологий. В пересказе конспектов Рэнни описывал микросервисы как способ заменить человеческое общение координацией через API: вместо неловкого разговора с соседней командой можно написать ещё немного кода и не разговаривать вовсе. Граница между сервисами на деле оказывалась границей между людьми. Решения, которые раньше принимались в споре над общим кодом, переходили в другую плоскость: чей сервис главнее, чьи приоритеты важнее, кто кого ждёт. Там же Рэнни говорил об обмене сложности на политику, а политикой считал любое решение, которое нарушает порядок «компания важнее команды, команда важнее собственных интересов».

Вывод Рэнни, в пересказе InfoQ, звучит спокойно: у всего есть цена, и компромиссы стоит выбирать намеренно. Судя по докладу, в Uber многие из них делались по ходу: решать приходилось быстрее, чем обдумывать. В этом разница трёх историй. У Amazon решение было сознательным и управленческим: порядок общения команд задал документ сверху, и сервисы пришли следом. Мотивы Netflix смешанные: отказ базы и рост просмотра шли рядом с независимостью команд. Uber рос стихийно: распоряжения, подобного указу Безоса, источники не описывают, и сервисы множились вслед за командами.

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

Та же компания позже сделает и обратный шаг. Автор ретроспективы 2020 года, инженер Uber Адам Глак, в июле того года писал примерно о 2 200 критичных сервисах и о том, как компания группирует их в домены. Рост организации в том же посте выглядит как переход от сотен инженеров к тысячам. Дробление и укрупнение оказываются частями одной истории. Uber — редкий случай, когда её можно проследить от начала до конца по текстам самой компании.

Карточка масштаба

Компания, год: Uber, 2014—2017; ретроспектива — 2020.

Инженеров: около 200 → около 2 000 за полтора года (примерно 2014—2016), по словам Рэнни в конспектах доклада; официальных данных нет; к 2020 году — «тысячи», без точного числа.

Пользователи / трафик: всего 1 млрд поездок к концу декабря 2015 года → 2 млрд к июлю 2016 года, по объявлениям компании; данных о нагрузке на серверы нет.

Сервисов (до → после): фактически два монолитных приложения (около 2012—2013) → от 20 до 100, по воспоминаниям участников (2014) → больше 500 (сентябрь 2015) → больше 1 000 в боевой среде (март 2016) → больше 2 000 (начало 2017); около 2 200 критичных (июль 2020).

Что именно изменилось: два монолита — основное приложение на Python с общей базой PostgreSQL и диспетчеризация на Node. js — разделены на сервисы, которые команды создают и развёртывают сами; основных языков стало четыре вместо двух — Python, Node. js, Go и Java; каждая команда отвечает за доступность своего сервиса.

Источник: R. W. Schmidt (2015); E. Haddad (2015); M. Ranney, GOTO Chicago (2016), по конспекту T. Hoff, HighScalability (2016); тот же доклад на QCon New York (2016), InfoQ; L. Lozinski (2016); E. Klitzke (2016); Y. Shkuro (2017); A. Gluck (2020); J. Clemm (2024).

Граница подтверждённого здесь проходит чётко. Числа сервисов с 2015 года, языки, трудности трассировки и исходные монолиты на Python и Node. js описаны в постах самой компании. Рост с 200 до 2 000 инженеров, мысль о границах между людьми и обмен сложности на политику известны по конспектам HighScalability и InfoQ. Запись доклада существует, но сверенной стенограммы нет, и точные слова Рэнни по конспектам не восстановить. Поэтому в этой истории числа сервисов — факт, а числа людей — свидетельство одного участника.

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

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

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

1.4. Закон Конвея и арифметика Брукса

В апреле 1968 года журнал Datamation напечатал статью программиста Мелвина Конвея. Заголовок статьи, «How Do Committees Invent?», спрашивает, как изобретают комитеты, а речь в ней идёт о любых группах, которые вместе проектируют систему, — не только о программистах. Главный тезис Конвей уместил в одно предложение: организации, которые проектируют системы, «вынуждены создавать проекты, копирующие коммуникационные структуры этих организаций» (are constrained to produce designs which are copies of the communication structures of these organizations). Проще говоря, стыки между частями системы повторяют линии, по которым договариваются друг с другом её авторы. Своего имени у этого наблюдения тогда ещё не было.

Имя ему дал Фредерик Брукс. В 1975 году вышла его книга «The Mythical Man-Month» — «Мифический человеко-месяц», о том, почему людей и месяцы в программном проекте нельзя обменивать друг на друга. Брукс сослался на статью Конвея и назвал её тезис законом Конвея; под этим именем он известен до сих пор. В той же книге есть арифметика, которая объясняет, почему этот закон тем заметнее, чем больше организация. Если каждую часть работы нужно отдельно координировать с каждой другой, пишет Брукс, трудозатраты растут как n (n—1) /2, где n — число участников. Трое, по его подсчёту, требуют втрое больше попарного общения, чем двое, а четверо — вшестеро.

Формулу легко проверить самому. У каждого из n человек есть n—1 возможных собеседников, но при таком счёте каждая пара учтена дважды, со стороны каждого из двоих, поэтому произведение делится пополам. Десять человек дают 45 пар, пятьдесят — 1 225, тысяча — 499 500. Когда вместо десяти человек работают пятьдесят, людей становится впятеро больше, а пар — примерно в 27 раз. Когда вместо десяти работает тысяча, людей становится больше в сто раз, а пар — в 11 100 раз. Число людей растёт линейно, число пар — примерно как половина его квадрата.

Обычно эту величину пересказывают как число каналов коммуникации. Основание для этого дал сам Брукс: в другой главе той же книги он пишет о (n²—n) /2 стыках, через которые может идти общение. Но там, где формула появляется впервые, он считает не линии на схеме, а трудозатраты на попарную координацию. Для счёта это безразлично: пар столько же. Для смысла разница важна: каждый канал — не провод, а время людей, которое уходит на то, чтобы договориться. Формула описывает худший случай, когда согласовывать приходится всё со всем, и в этом её польза: она показывает, от чего организация защищается своим устройством.

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

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

Где именно координация становится главным узким местом, формула не говорит: она показывает скорость роста, а не порог. Порог приходится оценивать по случаям. Amazon, судя по рассказу Бригхэма, упёрся в него с сотнями разработчиков. Uber, по словам Рэнни, дошёл до него на пути от двухсот к двум тысячам. Из этих случаев следует грубая оценка: где-то между сотнями и тысячами инженеров время на согласования начинает перевешивать время на саму работу. До этого предела медленную разработку можно объяснить многим, после него главное объяснение — очередь из согласований.

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

Порядок выигрыша видно на модели. Модель: тысяча инженеров в ста командах по десять человек; внутри команды договариваются все со всеми; между командами — только через контракты, и у каждой команды пять соседей, с которыми её связывает общая работа. Внутри команд получается 100 × 45 = 4 500 пар. Между командами — 250 пар соседей, и договариваются в них команды, а не каждый инженер с каждым. Вместо 499 500 возможных каналов остаётся меньше пяти тысяч, и число межкомандных пар растёт вместе с числом команд, а не как квадрат числа людей. Реальные организации устроены сложнее, и модель показывает не их, а порядок разницы.

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

Из этой арифметики видно, почему дробление сработало у Amazon и Netflix. Обе компании не столько нарезали код, сколько провели границы сервисов по границам команд. Если архитектура копирует структуру общения, её можно получить, заранее выбрав эту структуру. Распоряжение Безоса сначала определило, как командам разговаривать друг с другом, и сервисы выросли вдоль этих линий. У Netflix организационная сторона перехода известна только по пересказам, но и там сервисы в итоге разошлись по небольшим командам, а технические причины действовали вместе с этой перестройкой. Брукс вслед за Конвеем сделал из закона практический вывод: если проект системы должен свободно меняться, организация должна быть готова меняться вместе с ним.

Имя этот приём получил позже. В декабре 2010 года Джонни Лерой и Мэтт Саймонс из ThoughtWorks опубликовали в Cutter IT Journal статью «Dealing with Creaky Legacy Platforms» — о том, что делать со скрипучими унаследованными платформами. Обновление старой системы они советовали начинать не с кода, а с перегородок между группами, которые мешают командам работать вместе. Этот ход они назвали обратным манёвром Конвея (inverse Conway maneuver): идти от нужной архитектуры к структуре команд и ждать, что система последует за этой структурой. Широко известным термин стал после того, как ThoughtWorks включила его в июльский выпуск своего Technology Radar 2014 года. Amazon проделал этот манёвр примерно за восемь лет до того, как у него появилось имя.

На страницу:
2 из 5