На основе собственного опыта я знаю, какие мотивации и пути развития приводят к появлению in-house инструментов: ниже я попытаюсь выявить фундаментальные причины их создания на примерах наших решений.
Привет! Я хочу поговорить о том, почему крупные технологические корпорации одержимы созданием собственных решений для своей инфраструктуры. Ответ кажется очевидным: это не что иное, как синдром НИЗ. Но этот ответ далеко не полный, не говоря уже об объективном.
Я технический директор команды разработки платформ Яндекса, и наша цель — помочь инженерам выстроить весь цикл разработки, от написания кода до эксплуатации сервисов, чтобы сделать его более эффективным. Сюда входит оптимизация процессов: мы не только разрабатываем предложения как услугу, но и помогаем их внедрять внутри компании. Это работает в масштабах Яндекса: нашими услугами пользуются тысячи разработчиков по всей компании.
Примеры инструментов для организации цикла разработки
Для решения проблемы мы часто разрабатываем собственные инструменты, а не внедряем готовые. Например, еще будучи программистом в команде, я работал над системой количественного мониторинга на C++ и Python и помогал масштабировать ее до десятков миллиардов обрабатываемых метрик. Итак, исходя из собственного опыта, я знаю, какие мотивации и пути развития приводят к появлению in-house инструментов: ниже я попытаюсь выявить фундаментальные причины их создания на примерах наших решений.
История №1: Внутреннее облако Яндекса
Постановка задачи. Цель нашего внутреннего Runtime Cloud (RTC) — предоставить внутренним пользователям простые инструменты развертывания и управления трафиком. Пользователи РТК — это те же инженеры, которые разрабатывают сервисы Яндекса. И им нужно где-то запускать десятки тысяч созданных ими приложений, отправлять туда пользовательские запросы, балансировать нагрузку, разбираться с инцидентами в том числе.
Потребность во внутреннем облаке возникла в начале 2010-х годов, когда количество сервисов исчислялось уже сотнями, а общее количество выделяемых ядер росло на десятки процентов в год. Наличие выделенных серверов для каждой службы стало непомерно дорогим, и нам потребовались инструменты, которые позволили бы нам запускать приложения из нескольких служб на одном сервере. Изначально у нас было несколько требований к этим инструментам:
Необходимо автоматизировать рутинные действия, чтобы сэкономить операционные ресурсы и снизить количество инцидентов при релизах.
Отдельной важной задачей было увеличение использования облака, тем более что большинство сервисов имели суточный характер нагрузки, а ночью облако простаивало. Ситуация осложнялась еще и тем, что не все сервисы Яндекса в те годы размещались в облаке, а постоянное увеличение количества серверов усугубляло проблему.
Критически важно было быстро донести до пользователей функции или исправления ошибок, поскольку это напрямую влияло на скорость разработки Яндекса.
Требуется поддержка только IPv6: для обеспечения сквозной связи между подами наши дата-центры были построены только с поддержкой IPv6, так как в наших масштабах диапазона IPv4-адресов нам было бы недостаточно.
По сути, нам нужен был Kubernetes (и со временем RTC подошел очень близко). Но вот в чем загвоздка: K8s был анонсирован только в 2014 году. Apache Mesos существовал в то время, но находился в зачаточном состоянии.
Реализация основных функций. Мы начали решать задачу с своеобразного MVP — простого набора инструментов, который больше напоминал набор строительных блоков, автоматизирующих рутинные действия, например:
распределение ресурсов кластера;
доставка необходимой версии приложения и различных артефактов в кластер;
запуск необходимой версии приложения на кластере.
Со временем стало возможным собрать из этих строительных блоков полноценный граф компоновки сервиса (аналогично непрерывной доставке). После определенного количества итераций в 2013 году появилась Nanny — система управления работающими в РТЦ сервисами.
Еще одним фундаментальным аспектом Nanny стала реализация изоляции приложений на основе потребления ресурсов. Изначально мы запускали приложения из разных сервисов без изоляции ресурсов, что приводило к большому количеству операционных проблем и инцидентов.
На тот момент единственными готовыми решениями были LXC, который к тому времени прекратил разработку, и Docker, который не мог использовать только IPv6 и перезапускал все контейнеры при обновлении dockerd, что делало невозможным обновление dockerd без ущерба для пользователя. В результате мы начали развивать нашу система контейнеризации поверх контрольной группы ядра Linux примерно в середине 2014 года. Большинство приложений и некоторые системные агенты на серверах уже были перенесены в контейнеры Porto в 2015 году.
Решение проблем с использованием. В то время управление ресурсами во внутреннем облаке осуществлялось посредством фиксации в репозитории. Однако это замедляло развитие Яндекса и вступало в противоречие с задачей увеличения загрузки: для ее решения нам нужно было разместить нашу систему уменьшения карт в облаках, а именно — наша собственная внутренняя система хранения больших данных и распределенных вычислений, которую мы разрабатывали на тот момент около 7 лет. Его нужно было перенести во внутреннее облако, но при этом он должен был работать вместе с пользовательскими приложениями.
Чтобы перенести YTsaurus в RTC, требовалась возможность управлять модулями динамически, а не посредством фиксации в репозитории. Поэтому в 2018 году мы создали , система управления вычислительными ресурсами кластера. Yandex Planner был интегрирован с существующей системой развертывания Nanny, что разблокировало миграцию YTsaurus и превратило RTC в полноценное облако. В то время у RTC было несколько десятков тысяч серверов, а с введением сокращения карт это число значительно выросло.
Новые боли роста. За тот же период k8s превратился в гораздо более зрелое решение, став одним из сервисов AWS в 2017 году. Но оно по-прежнему не отвечало всем нашим требованиям:
Масштаб в десятки тысяч серверов — одна установка k8s по-прежнему не справляется с нашим масштабом.
Поддержка двухстековых IPv6 и IPv4 появилась в k8s только в 2020 году, и IPv6 был для нас критичен с самого начала.
Поддержка вложенных контейнеров, которая нам потребовалась, поскольку мы решили создать отдельные планировщики пакетной обработки и вычислений. В какой-то момент мы сравнили эффективность этого варианта с эффективностью общего планировщика, и оказалось удобнее и выгоднее не пытаться сделать общий планировщик для всего.
YTsaurus активно использовал возможность создания вложенных контейнеров Porto вместо создания единого планировщика. Конечно, мы могли бы сами добавить поддержку того же двойного стека в k8s. Однако опыт разработки ядра Linux показал, что не все можно отправить в открытый исходный код, и мы стремимся свести отклонение от вышестоящего ядра к минимуму, чтобы упростить обновление до новых версий.
Наше решение сегодня. Архитектура RTC очень похожа на архитектуру Kubernetes. Пользователь декларативно описывает свой сервис в виде некоторой спецификации, описывающей, как запустить указанное приложение и в каких центрах обработки данных. В каждом дата-центре есть своя установка Яндекс Планировщика, который с одной стороны служит базой данных для всех объектов кластера, а с другой — планировщиком подов. На каждом сервере в дата-центре работает агент, который получает спецификации модулей из Яндекс Планировщика и запускает их с помощью нашей собственной системы контейнеризации Porto.
В настоящее время RTC запустила десятки тысяч сервисов, распределив более 5 миллионов ядер на более чем 100 000 серверов. Ежедневно в спецификации услуг вносится более 100 000 изменений.
Планы. Что, если k8s справится с нашим масштабом? Тем более, что экосистема k8s в какой-то момент начала превосходить нас по функциональности. Не лучше ли перейти на k8s и надеяться, что готовые инструменты со временем дадут тот объем, который нам нужен? На практике мы продолжаем оставаться нишевым потребителем k8s, потому что лишь небольшой процент компаний работает в таких больших масштабах, каждая из которых имеет свои собственные облачные решения.
Еще один важный момент, о котором следует помнить, — это проблема миграции. По данным июля 2018 г. Согласно отчету, 90% современных приложений все еще будут использоваться к 2025 году, а технический долг на разработку этих систем будет составлять более 40% ИТ-бюджетов. Это близко к реальности, исходя из нашего опыта миграции пользовательских сервисов на Яндекс Планировщик: в 2023 году около 100 тыс. ядер все еще ждали своей очереди на переход на Яндекс Планировщик.
В 2021 году мы прикинули, сколько будет стоить переход с одной системы развертывания на другую при выборе стратегии развития. Переход Яндекса на vanilla k8s будет чрезвычайно дорогостоящей задачей, требующей сотен человеко-лет.
Таким нехитрым образом у нас получилось наше внутреннее облако, от которого мы вряд ли сможем отказаться в ближайшие 5 лет, даже если поставим такую цель.
Что делать с отсутствием внутреннего облачного функционала по сравнению с к8с? На практике наши клиенты могут использовать Managed Kubernetes в Яндекс Облаке. Этот вариант в первую очередь используется для проектов, где необходимо соблюдать строгие требования соответствия — это небольшая доля команд, менее 1%. По указанным выше причинам остальная часть населения не видит особой выгоды в переезде.
При этом мы активно присматриваемся к k8s и думаем, как приблизиться к общепринятым стандартам. Мы уже активно экспериментируем с k8s в некоторых задачах, например облачная загрузка или организация IaaC в масштабе всего Яндекс. В идеале мы хотели бы повторно использовать интерфейс k8s, сохраняя при этом собственную реализацию, максимально адаптированную к нашим потребностям. Остаётся только придумать, как это сделать на практике.
А как насчет других? Поскольку в этой статье мы обсуждаем большие технологии в целом, стоит отметить, что наш случай не уникален. Проверьте или кейсы для примеров.
История №2: монорепозиторий
Проблемы и требования к решению . Наш монорепозиторий Arcadia преследует ту же основную цель, что и наше внутреннее облако: предоставить удобные инструменты разработки. В случае репозитория это включает в себя всю экосистему разработки:
система контроля версий (Arc),
Интерфейс (Арканум),
система сборки (я делаю),
CI/CD (НовыйCI).
Аркадия появилась примерно в то же время, что и внутреннее облако Яндекса. Одной из причин создания монорепозитория стала необходимость повторного использования кода внутри Яндекса. В то время этому препятствовало наличие нескольких систем сборки. Для работы в масштабе всего Яндекса требовалась единая система с поддержкой эффективных распределенных сборок. Он также должен быть стабильным и удобным в использовании.
Реализация единой системы сборки. Наша собственная система сборки ya make дебютировала в 2013 году, когда она предназначалась только для кода C++. Перед созданием мы использовали CMake, но его скорость не позволяла масштабироваться до масштабов монорепозитория. Фирменный ya make работал с Аркадией гораздо быстрее. Других вариантов с открытым исходным кодом, которые могли бы решить нашу проблему, не было: например, Bazel вышел гораздо позже, в 2015 году.
Масштабирование системы контроля версий. Ранее Яндекс использовал SVN в качестве системы контроля версий. Хотя SVN имела большую емкость, она все еще была ограничена и сложна в обслуживании. Более того, мы осознавали, что в конечном итоге столкнёмся с ограничениями возможностей и удобства SVN. Например, эвристика использовалась для реализации возможности загрузки только необходимой части репозитория или выборочной выдачи. В результате в 2016 году мы начали экспериментировать с другими системами контроля версий, помимо SVN.
Mercurial был первым выбором. Но главной проблемой, с которой мы столкнулись, была скорость. Полтора года мы пытались запустить Mercurial в производство, но результаты были неутешительными. Например, нам в конечном итоге пришлось переписать части Mercurial для поддержки FUSE, иначе нам пришлось бы переносить весь репозиторий на ноутбук каждого разработчика.
В конце концов оказалось, что дешевле написать собственное решение с нуля, и в 2019 году появился Arc — новая система контроля версий для пользователей Arcadia с git-подобным UX. В основе Arc лежит FUSE (файловая система в пространстве пользователя), а не выборочное извлечение. Кроме того, YDB действует как масштабируемая база данных, что значительно упрощает работу Arc по сравнению с Mercurial.
Нас часто спрашивают, почему мы не использовали git. Потому что у него также есть ограничения по масштабу и функциональности: если мы импортируем только ствол Arcadia в git, статус git в этом масштабе займет несколько минут. При этом стабильной реализации FUSE, построенной поверх git, не было: VFS для Git больше не разрабатывается, а EdenFS со временем превратили в Sapling, но произошло это гораздо позже.
Текущее состояние решения и планы на будущее. Чтобы начать разработку, внутреннему пользователю просто нужно создать папку в нашем монорепозитории, написать код и рассказать вам, как собрать свое приложение, добавив манифест сборки. В результате пользователь получает запросы на включение, конфигурацию CI и возможность повторно использовать любой код в компании.
По масштабу в данный момент транк содержит 10 миллионов файлов, репозиторий в целом превышает 2 ТиБ, а каждую неделю делается более 30 тысяч коммитов.
В результате в созданной нами экосистеме многие компоненты приходится создавать с нуля. Однако сейчас она движется в сторону соответствия мировым стандартам. Arc, например, поддерживает работу с Git для предопределенного набора проектов.
А как насчет других? Опять же, если смотреть на большие технологии в целом, то в качестве примера стоит обратить внимание на и .
Что общего в этих историях
Так почему же крупным технологическим компаниям приходится изобретать собственные решения и почему их нельзя заменить решениями, которые соответствуют общепринятому стандарту?
Инновации. Крупным корпорациям часто приходится разрабатывать решения проблем, которые станут обычным явлением только в будущем. Именно так могут появиться инновационные решения, способные стать рыночными стандартами.
Не всегда проблема, решаемая компанией, стоит перед кем-то, кроме самой компании. Иногда опыт крупных технологических компаний в решении конкретной проблемы помогает всей отрасли избежать этой проблемы, выбрав совершенно другой путь развития. Не всегда возможно предсказать развитие рынка, и в результате разные примеры запатентованных решений имели совершенно разные результаты.
ClickHouse — пример по-настоящему успешного инновационного проекта, значительно обогатившего сферу онлайн-аналитической обработки (OLAP). Однако это касается не всех проектов. Porto, который начинался как проект с открытым исходным кодом, не смог набрать обороты по ряду причин. Хотя некоторые его возможности, такие как возможность создания вложенных контейнеров, остаются уникальными.
Шкала. Этот пункт в чем-то похож на предыдущий, ведь не каждая компания сталкивается с проблемой масштабируемости. Было время, когда 640 кбайт было более чем достаточно для всех, не так ли?
Фактически экспоненциальный рост нагрузки на систему стал одной из важнейших причин развития Аркадии и внутреннего облака. Именно поэтому были разработаны Arc и Yandex Planner. Arc был создан в ответ на потребность в удобной для пользователя системе контроля версий, которая позволит пользователям без затруднений работать с монорепозиторием, содержащим десятки миллионов файлов в транке. Yandex Planner был создан в ответ на необходимость эффективной работы с кластерами из десятков тысяч узлов и миллионов подов.
Публичные инструменты по-прежнему имеют проблемы с масштабированием (ведь это относительно редкий сценарий, и вкладывать в него зачастую просто невыгодно).
Инерция. Рассмотрим внутренний инструмент, который решает проблему внутри компании. Компания, которая активно использует этот инструмент, будет выделять ресурсы на то, чтобы лучше адаптировать его к своим потребностям, в конечном итоге превратив его в узкоспециализированный инструмент. Этот процесс может длиться годами.
Теперь рассмотрим возможность того, что в какой-то момент появится общепринятый стандарт решения этой конкретной проблемы. В этом случае специализация по-прежнему может быть важным фактором при выборе собственного решения. Рассмотрим системы сборки. Мы в Аркадии используем ya make, хотя есть Bazel от Google. Концептуально они схожи, но если вникнуть в детали, многие важные сценарии реализуются по-разному, поскольку шаблоны нагрузки для каждой рабочей нагрузки могут существенно различаться. В результате уже затраченные ресурсы почти наверняка придется реинвестировать для адаптации нового общепринятого стандарта.
Миграции. Если в предыдущем разделе был рассмотрен вопрос адаптации проекта под пользователей, то теперь займемся вопросом миграции самих пользователей. На мой взгляд, миграцию следует назвать следующей по значимости проблемой в сфере технологий после названия. Если мы предположим, что у нас уже есть собственный инструмент компании и мы хотим заменить его стандартизированным, нам неизбежно потребуется миграция.
Мы знаем множество примеров миграций из нашего опыта разработки внутреннего облака. Крупномасштабные миграции требуют времени, поэтому оба инструмента должны поддерживаться одновременно в течение продолжительных периодов времени. Если в этом процессе участвует большое количество пользователей, проблемы управления неизбежны. Конечно, стоит попробовать выполнить миграцию без участия пользователя, но это не всегда возможно.
Непрерывность бизнеса. Честно говоря, в последнее время этот момент приобрел достаточное значение. Раньше гораздо меньшее количество компаний относилось к этому серьезно из-за опасений по поводу привязки к поставщику. Доверять критические процессы поставщику, который может прекратить сотрудничество в любой момент, рискованно. JetBrains является ярким примером этого, ограничив использование своих IDE определенными компаниями. Еще один показательный пример — Github Enterprise, который начал блокировать учетные записи российских пользователей.
Внутренние решения обычно невосприимчивы к этой проблеме. С одной стороны, все еще существуют решения с открытым исходным кодом. С другой стороны, нет никаких гарантий, что модель с открытым исходным кодом будет с вами на протяжении всего пути: например, Corona, собственная разработка Facebook для программного обеспечения планирования Hadoop MapReduce, появилась в первую очередь из-за невозможности коммитить исправления, необходимые для масштабирования Hadoop вверх по течению.
При этом юридическая сторона вопроса затрагивает open source: например, коммиты в golang или k8s требуют подписания CLA. Будет ли это оставаться проблемой?
НАЦИОНАЛЬНЫЕ ИНСТИТУТЫ ЗДРАВООХРАНЕНИЯ США. Да, помимо объективных причин, возможно, принятые решения не прагматичны. Это синдром NIH во всей красе.
Например, пытаясь устранить влияние пакетной обработки на вычисления, мы попытались создать собственный планировщик в ядре Linux. На практике ничего хорошего из этого не вышло; можно было бы обойтись существующими возможностями ядра Linux. Однако чем выше затраты на рабочую силу, тем больше усилий затрачивается на разработку и решение проблемы и тем ниже вероятность возникновения синдрома NIH.
Подводя итог , как видите, крупным компаниям часто требуются собственные решения. Большинство из них в будущем сольются с еще не созревшими унифицированными глобальными стандартными решениями, а остальные уйдут в историю. В любом случае выбор между собственным решением и готовым остается сложным вопросом, на который невозможно ответить без предварительного понимания контекста и оценки стоимости такого проекта.