От лапок паука к щупальцам осьминога. Зачем мы поменяли архитектуру объектного хранилища Яндекса

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

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

Объектное хранилище: структура, требования, особенности

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

Основные сущности системы хранилища

  • Шард — минимально доступная единица для записи каких‑либо объектов.
  • Группа — контейнер для данных фиксированного размера. Чтобы повысить надёжность хранения, используется репликация. Один шард будет состоять из нескольких групп, число которых равно фактору репликации этого шарда.
  • Namespace — контейнер для всех шардов пользователя, он изолирует объекты каждого пользователя.

Базовые требования к хранилищу

  • Надёжность хранения данных: важно хранить и отдавать пользовательские данные без потерь.
  • Эффективные запись и чтение: пользователи не должны испытывать сложности.
  • Изоляция данных пользователей.
  • Масштабируемость системы: объём данных постоянно растёт, что требует регулярного расширения хранилища новыми хостами с дисками.

Старая архитектура: как это работало раньше

  • Первый слой — ноды Data Plane. Это сервис, который умеет только сохранять и отдавать данные. Здесь используется подход append‑only: все новые записи и изменения дописываются в конец диска. Это ускоряет последовательную запись и чтение, но добавляет необходимость периодически дефрагментировать удалённые данные (компактить).
  • Второй слой — клиентская репликация на уровне Proxy‑сервиса (обслуживание запросов пользователя).
  • Третий слой — сервис Control Plane: обслуживание, управление и сбор информации о кластере. Это «мозг» системы, он:
    • запускает процессы синхронизации групп;
    • запускает процессы дефрагментации (данные важно компактить, чтобы они занимали меньше места);
    • перевозит данные с хостов, если требуется их вывести для обслуживания;
    • занимается сбором статистики и информации о кластере (для грамотной балансировки нагрузки и равномерного распределения объёма данных).

В итоге мы получали следующую архитектуру:

  • Пользователь ходит в Proxy‑сервис (это его точка входа).
  • Proxy ходит в Control Plane, чтобы понять, в какой шард ему идти для записи данных пользователя.
  • Он получает от Control Plane всю необходимую информацию и идёт в Data Plane, выполняет репликацию и сохраняет данные в нужное количество нод.
  • Также Control Plane ходит в ноды Data Plane, собирает информацию и обслуживает кластер.

Выглядело это так:

Полноэкранное изображение

Плюсы прежнего подхода

  • Простой слой хранения данных: система умеет только сохранять и отдавать, поэтому всё работает надёжно.
  • Основная логика сосредоточена в Control Plane. Это удобно: у нас есть единый центр координации, который знает, что и как делать.
  • Полный контроль над кластером.
  • Система подходит для хранилищ малых и средних масштабов.

Минусы прежнего подхода

  • Архитектура с централизованным управлением. Единая точка отказа в этой архитектуре — это Control Plane, так как он управляет всеми процессами по обслуживанию кластера. Control Plane отвечает и за балансировку записи в кластере, указывая Proxy‑слою, куда записывать данные пользователя. Если Control Plane выходит из строя, могут возникнуть проблемы с дефрагментацией и синхронизацией.
  • Линейный рост сложности обслуживания кластера. С увеличением количества хостов в кластере потребуется больше времени на то, чтобы Control Plane обошёл кластер и собрал статистику.
  • Замедление времени реакции на нештатные ситуации с ростом количества хостов.
  • Императивный подход в обслуживании кластера. Зачастую процессы обслуживания кластера — это либо ручные действия, либо действия администраторов, либо скрипты. Они могут быть запрограммированы в виде алгоритма, но все они выполняются пошагово. Контроль за целостностью системы также лежит на исполнителе — будь то администратор или Control Plane.
Полноэкранное изображение

Объём данных растёт — пора менять подход

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

Итак, у нас был Data Plane — централизованный компонент, который всем управляет стратегически. Необходимо было добавить в ноды Data Plane немного «мозгов», дополнив стратегию тактикой. Тогда умный Data Plane сможет самостоятельно принимать определённые решения, а Control Plane будет заниматься только стратегическим планированием того, как должен выглядеть кластер.

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

Вот как эти отличия можно изобразить схематично:

Полноэкранное изображение

Слева — Control Plane, «мозг» всей нашей системы. Если ему что‑то потребуется от Data Plane, он придёт туда и выполнит нужные команды. После этого система обретает желаемое состояние.

Справа — новая усложнённая схема, отражающая аналогию с осьминогом. У нас есть умный Data Plane. Он сам принимает определённые решения и выступает автономной единицей. В то же время Data Plane ходит в Control Plane, чтобы понять, какие действия выполнить дальше.

Новые возможности для масштабирования

Изменения помогли нам получить довольно самостоятельный Data Plane. Вот его возможности:

  • Ответственность за обслуживание данных (без внешнего управления). Если ноде Data Plane надо выполнить дефрагментацию, она запускает её, не дожидаясь команды от Control Plane.

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

  • Знание о топологии каждого шарда на ноде. Каждый шард образуется в свой самостоятельный Raft‑кластер. Все группы — участники этого шарда — являются участниками Raft‑кластера и следят за консистентностью данных. Если какая‑то группа выйдет из строя и потом вернётся в кластер, она «поймёт», что отстала от других, и запустит процесс синхронизации.

  • Service Discovery. Группы могут самостоятельно объединяться в шарды с помощью Service Discovery и знания о топологии каждого шарда.

Таким образом, мы разгрузили Control Plane:

  • Data Plane самостоятельно ходит в Control Plane и рассказывает о своём состоянии: загруженность дисков, сети, наличие свободных и занятых групп. Как часто это происходит? Мы предусмотрели фиксированную настраиваемую периодичность, сейчас это 15 секунд.

  • Control Plane в ответ сообщает Data Plane об изменениях в топологии, требующих внимания.

Кроме того, у Control Plane есть фоновая задача, которая следит за тем, как регулярно приходит Data Plane с синхронизацией. Если время превышает лимит, Control Plane понимает, что с нодой неполадки, и запускает процессы синхронизации и добавления новых групп взамен ушедших.

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

Полноэкранное изображение

Таким образом, мы просто описываем состояние системы. Например, говорим, что у пользователя должен быть шард с ID номер один, а фактор репликации — равен трём. Добавляем ограничение: каждая группа должна находиться в своём дата‑центре. Это позволяет надёжно хранить данные: при отказе дата‑центра информация не потеряется.

Цикл согласования в новой системе

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

Цикл делится на три этапа:

  1. Мы видим, что шард требует внимания (об этом сообщает Data Plane).
  2. Сравниваем состояние шарда и переходим к корректировке: видим, что шарду не хватает одной группы, запускаем процессы взвешивания всего кластера и находим идеально подходящий хост (на основе объёма свободного места или нагрузки на сеть, диск).
  3. Фиксируем изменения в базе и на этапе синхронизации отправляем информацию в Data Plane. Далее Data Plane находит нужный шард через Service Discovery и подключается к соседям в группы.

Схема цикла построена так:

Полноэкранное изображение

Как выглядит новая архитектура

На этой схеме можно увидеть изменения в архитектуре объектного хранилища.

Полноэкранное изображение
  • Пользователь по‑прежнему ходит в Proxy, а Proxy — в Control Plane, чтобы получать веса.

  • Proxy больше не требуется самостоятельно реплицировать данные: благодаря объединённому шарду в Raft‑кластер там достаточно сходить в любую из нод, и объект автоматически отреплицируется в две соседние ноды. После этого придёт коммит, и мы ответим пользователю, что его файл успешно записан.

  • Направление синхронизации изменилось: теперь ноды Data Plane ходят в Control Plane и сообщают о своём состоянии.

От императивного к декларативному подходу: быстрее и проще

Обновив архитектуру, мы ушли от императивного подхода в управлении кластером, когда Control Plane сам всё пошагово выполнял и следил за состоянием системы.

Декларативный подход дал следующие преимущества:

  • Мы избавились от команд типа «Добавь эту группу в шард» или «Создай новый шард». Теперь мы просто описываем, что шард должен быть в таком‑то Namespace и иметь три реплики. Система и умные ноды Data Plane самостоятельно организуются в шард и будут доступны на записи.

  • Ускорился сбор шардов благодаря тому, что в Control Plane остаётся только их описание. Нам достаточно сказать: «Создай новый шард» — не нужно ждать, пока Control Plane найдёт группы и последовательно выполнит команды для сбора шарда.

  • Теперь кластер обслуживать проще: наша система стала самовосстанавливающейся и практически не требует внимания со стороны человека или Control Plane как исполнителя. Умный Data Plane не только ускоряет операции, но и снижает нагрузку на Control Plane. Мы также избавились от линейного роста сложностей со сбором статистики и обслуживанием кластера, что позволяет хорошо масштабироваться.

  • Ускорилась реакция на нештатные ситуации. Раньше, когда Control Plane последовательно опрашивал весь кластер (даже с 10–100 хостами), период синхронизации составлял около минуты. При 3000 хостах обновление информации занимало около 10 минут. С новым подходом синхронизация происходит каждые 15 секунд, поэтому мы быстрее узнаём о проблемах и принимаем решения. Это позволяет повысить надёжность хранения данных.

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

От лапок паука к щупальцам осьминога. Зачем мы поменяли архитектуру объектного хранилища Яндекса
Войдите, чтобы сохранить пост