0. System design – это тебе не квадратики рисовать

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

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

Проходит несколько лет, и твой умный дядька исчезает. PM приходит уже к тебе. И вдруг выясняется: теперь именно ты отвечаешь на неудобные вопросы и должен объяснить, как строить сервис.

Последний год ты много слышал про system design, но не обращал внимания. Думал, это для больших и умных. Слышал, что он про архитектуру. Его хотят на собесах. Там рисуют квадратики и стрелочки: квадратики становятся сервисами, базами, кешами и (прости господи) очередями , стрелочки - каналами связи.

Посмотрел ютуб, посмотрел прошлые сервисы, подумал и нарисовал. Рассказал команде. Они постарались и сделали. Сервис выкатили на прод.

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

Ты идешь советоваться к умными дядьками из других команд и компаний. Они почему-то в разрез с ютубом мало говорят про квадратики и стрелочки. Они говорят про какого-то Клепмана, про Эшби и кибернетику, про Альтшуллера и ТРИЗ.

Тебе говорят, что system design это про компромиссы: надежность, масштабируемость и сопровождаемость. Говорят, что мало один раз нарисовать — нужно возвращаться, пересматривать, менять архитектуру под новые боли и требования. Что нужно собирать эти требования. Что схем должно быть много: для бизнеса — своя, для девопсов — своя, для разработки — своя. Разные уровни абстракции, разные нюансы.

И все это – теперь хотят от тебя. Мрак. Ужас.

Поэтому, пока не поздно, я предлагаю тебе погрузиться со мной в знакомство с system design. Я не буду рассказывать «как пройти собес». Я расскажу тебе: почему system design не про стрелочки и квадратики, зачем тебе он нужен и как он может облегчить твои страдания.

Что же такое «System design»?

Чем System design точно не является: рисованием и инструментом для прохождения интервью. Так его блоггеры на ютубе продают. Так проще. Но реальность гораздо сложнее.

System design - это спор с реальностью, борьба с ограничениями, поиск компромиссов. Это мир, в котором у каждой идеи есть цена, у каждого ограничения есть причина. Это мир, в котором "правильная архитектура" сейчас становится "неправильной" через пару месяцев.

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

С осознанием этого, ты скорее всего придешь к первой взрослой мысли: «нужно собрать требования». Это на первый взгляд просто. Спросил, чего хотят, сделал что-то похожее. Но нет.

Собирать нужно с умом. Формулировка: «хотим ленту как у Threads” не подойдет. Нужно выбить из бизнеса и аналитиков конкретику: сколько пользователей планируется на старте, сколько через год, сколько времени у тебя на p99, какой сбой считается нормой, чем можно пожертвовать при пиках, важнее истина или скорость, чем бизнес готов жертвовать взамен на экономию.

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

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

Требования дают представление: «такой профиль данных, здесь читаем, тут пишем, такие хвосты распределения, такие пики». Отсюда вытекают формат данных, модель консистентности, понимание, что журнала хватит и очередь не нужна, что вот тут может быть узко, а тут проблем быть не должно. Ты уже прикидываешь, нужен ли hot path в памяти, и чем придётся платить за восстановление.

Стек складывается естественно: какие составные части, на чём они будут написаны, какие инструменты лягут в основу. Эти мысли уже можно переносить в ТЗ и схемы.

Что-то уже есть на бумаге и технологический стек первично определен. Начинаешь погружаться глубже. Теперь нужно работать со связями. Мысль три: «нужно определить поток данных и обратную связь системы».

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

И главное - как система реагирует, когда на нее давят. Не существует «пассивной» системы: если разнообразие воздействий мира на систему больше спектра ее реакций, система уходит в отказ.

Если по-простому: поток данных должен быть сопряжён с обратной связью. Когда вход растёт быстрее, чем ты можешь переварить, ты либо сигнализируешь «стоп, хватит» (backpressure), либо начинаешь управляемо деградировать. Не «всё для всех, но “сдохли”», а «меньше, но вовремя».

И вот здесь начинает появляться настоящая архитектура: система, которая умеет не геройствовать до смерти, а вовремя сказать «нет» и остаться живой.

Если обобщить: System design всегда живёт на четырёх слоях: технологическом, организационном, фундаментальном и изобретательском. Игнорируешь хоть один и система падает не там, где ждёшь, а там, где больнее всего.

Посмотрим на примере

У тебя небольшой сервис в HFT-экосистеме. Клиенты сами парсят разные внешние источники и приводят данные к формату, нужному системе.

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

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

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

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

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

Горячий путь идёт по памяти и держит SLA, а рядом ты пишешь минимальный, но надёжный журнал, из которого можно подняться, догнать и перепроверить. Не «всё и сразу», а ровно столько, чтобы после падения не начинать жизнь заново. Это дороже по ресурсам и по мозгам: двойная запись, идемпотентность, продуманная консистентность. Зато вместо религиозного спора «брокер или память» у тебя работает система, объединившая оба подхода.

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

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

Оформляешь эти решения словами, которые команда понимает: здесь у нас компенсирующая логика, тут мы разносим запись и чтение в разные модели, тут у нас предохранитель, тут выбрасываем «дорогое» обогащение при перегреве.

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

С этого места становится видно главное. System design не про то, чтобы однажды красиво объяснить «как мы всё построим». Это про способность системы и команды менять форму, не теряя сути. Про честные компромиссы между скоростью и истиной, между простотой и гибкостью, между идеалом и тем, что реально держит прод. И да, про изобретательность по ТРИЗ: не «выбрать единственно верный инструмент», а развернуть противоречие так, чтобы выиграть временем и уменьшить боль.

Вывод

System design это широко, сложно и очень интересно. Это не про квадратики и стрелочки. Это про то, как разговаривать с реальностью на языке требований, обратной связи и компромиссов. Если твоя схема выдерживает новый источник, новый SLA и новый сбой без капитального ремонта, значит, ты всё сделал правильно. Всё остальное — декор.

Что еще почитать?