Разговор про Rust в сервисах почти всегда сворачивает на бенчмарки, и это самая бесполезная его часть. Что язык без сборщика мусора даёт предсказуемые задержки — не новость и не предмет спора.
Спорить стоит о другом: где эта предсказуемость меняет продуктовое поведение, а где остаётся строчкой в графике, на которую никто не смотрит.
Где выигрыш реален
Горячий путь с жёстким требованием к хвосту задержек. Если ваш SLA сформулирован через девяносто девятый перцентиль, а не через среднее, пауза сборщика мусора — не абстракция, а прямое нарушение обязательства. Здесь Rust решает ровно ту задачу, ради которой его берут.
Важно, что дело не в средней скорости. Языки со сборщиком мусора часто дают сопоставимое среднее; отличается именно хвост, и отличается предсказуемо.
Долгоживущие процессы с высоким давлением на память. Прокси, шлюзы, обработчики потоков — всё, что держит соединения часами. Экономия здесь измеряется не в процентах на графике, а в количестве машин, и на достаточном масштабе это становится статьёй бюджета, а не техническим предпочтением.
Всё, что встраивается в чужой процесс. Расширения для баз данных, плагины, модули WebAssembly. Отсутствие рантайма — не оптимизация, а условие возможности: язык со своей средой исполнения туда просто не помещается.
Где не окупается
CRUD-слой поверх базы. Время запроса определяется базой и сетью, а не языком. Переписав такой сервис, вы получите одинаковые графики и в полтора-два раза более медленную разработку — не потому что язык плохой, а потому что вы платите за гарантии, которые в этом месте ничего не гарантируют.
Код, который меняется каждую неделю. Строгость компилятора окупается на стабильном коде и штрафует на экспериментальном: каждое изменение формы данных тянет за собой правки типов. Там, где вы ещё ищете форму задачи, это прямой налог на поиск.
Фоновая обработка, где важна пропускная способность, а не задержка. Здесь горизонтальное масштабирование дешевле переписывания: добавить процессов проще, чем переучить команду.
Что мы попробовали бы иначе
Типичная ошибка — начинать с самого нагруженного сервиса. Логика понятная: там больше всего выигрыш. Практический результат — команда одновременно учит язык и трогает то, что нельзя ронять. Ошибки новичка в Rust не приводят к падениям в рантайме, но приводят к неделям на ревью и к архитектурным решениям, которые потом переделывают.
Разумнее начать с изолированного компонента на границе: парсер, преобразователь формата, что-то с чистой функцией и понятным контрактом. Выигрыш будет скромнее, зато вы получите работающий код в проде и честное представление о том, сколько времени уходит на ревью и сколько — на борьбу с заимствованиями.
Второй вывод из того же наблюдения: первый сервис стоит выбирать по простоте отката, а не по величине выигрыша. Если через квартал станет ясно, что не пошло, вы должны иметь возможность вернуться без переписывания половины системы.
Два фактора, которые решают
Срок закрытия вакансии. Это не про то, что разработчиков нет; это про то, что поиск занимает заметно больше времени. Решение принимается не в инженерном отделе, и аргумент «зато у нас предсказуемые задержки» в том кабинете не работает.
Количество мест, где придётся объяснять выбор. Один сервис на нестандартном для команды языке требует объяснений при каждом онбординге, каждом дежурстве и каждом обсуждении архитектуры. Это налог, который платится не в момент решения, а потом и по частям — и поэтому его систематически недооценивают.
Есть и третий фактор, о котором вспоминают позже всех: кто будет дежурить. Ночью нужен человек, способный прочитать незнакомый стек-трейс, а не только тот, кто этот сервис написал.
Как мерить, чтобы себе не соврать
Если вы всё же меряете, то замер без условий бесполезен. Минимум, который должен стоять рядом с числом: машина, версия рантайма, размер данных, число прогонов и что именно считается за единицу работы.
Отдельно: меряйте на своей нагрузке, а не на синтетике. Синтетический тест почти всегда показывает разницу больше реальной, потому что убирает из картины базу, сеть и сериализацию — то есть ровно то, что в продакшене занимает большую часть времени.
Мнение
Rust стоит брать там, где предсказуемость задержек или отсутствие рантайма — часть требований, а не приятный побочный эффект. Во всех остальных случаях выбор языка не входит в первую пятёрку факторов, влияющих на результат: архитектура, границы сервисов, качество данных и организация команды влияют сильнее.
Условие, при котором мы неправы: если команда уже пишет на Rust и он для неё дефолт, вся приведённая аргументация меняет знак. Стоимость незнакомого языка — единственная существенная статья расходов в этом списке, и у такой команды её просто нет. Тогда вопрос не «стоит ли брать Rust», а «есть ли причина брать что-то другое».
Три вопроса до решения, а не после
Что именно вы обязались обеспечить? Если в договорённости с продуктом стоит среднее время ответа, разговор про хвост задержек не имеет отношения к делу. Если стоит перцентиль — имеет прямое. Это первый вопрос, потому что он один отсекает большинство случаев.
Где сейчас уходит время? Прежде чем менять язык, стоит посмотреть распределение по слоям. Если восемьдесят процентов времени запроса тратится в базе, самый быстрый язык в мире изменит оставшиеся двадцать. Этот замер занимает день и регулярно закрывает вопрос без переписывания.
Кто это будет сопровождать через год? Не «кто напишет», а «кто починит ночью». Ответ «автор» — не ответ, а риск, оформленный как план.
Про постепенный переход
Переписывание целиком почти всегда обсуждается и почти никогда не оправдано. Практичнее выносить по одному компоненту через понятную границу — очередь, HTTP-контракт, вызов процедуры, — оставляя остальное как есть.
У такого подхода есть скучное преимущество, которое обычно решает: в любой момент можно остановиться. Если через квартал выяснится, что выигрыш меньше ожидаемого, вы останетесь с одним нестандартным компонентом, а не с наполовину переписанной системой и командой, которая уже не помнит, зачем всё начиналось.
Редакции: любые сравнения производительности публикуются только с условиями — машина, версия, размер данных, число прогонов. Замеры без условий бесполезны читателю и вредны изданию. В этом тексте их нет намеренно.