Программирование и разработка программного обеспечения

Как постепенно интегрировать Rust для ускорения существующей кодовой базы без полной переписывания

Lily Mara объясняет методологию рефакторинга функций через интерфейс взаимодействия между языками FFI для переноса отдельных частей Python в Rust с использованием PyO3, сохраняя существующее приложение и снижая риски полной переписывания. Эксперимент показывает, что ускорение на уровне функции может превышать 100 раз, тогда как общее улучшение в HTTP-тесте составило лишь около 15%, что подчёркивает важность измерений на уровне системы.

2026-09-15
5 мин. чтения
10 просмотров
فريق تحرير certi.news
Как постепенно интегрировать Rust для ускорения существующей кодовой базы без полной переписывания

Вместо полной переписывания приложения на Rust Lily Mara, Staff Engineer в Discord, предлагает постепенно переносить наиболее ресурсоёмкие функции из динамического языка, такого как Python, в Rust и связывать обе реализации внутри одного процесса. Mara представила эту методологию на сессии, опубликованной через InfoQ, опираясь на свой опыт создания распределённых систем для отправки десятков миллиардов уведомлений пользователям Discord ежедневно, а также на свою книгу Refactoring to Rust.

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

Почему полная переписывание не должна быть отправной точкой?

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

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

Что означает рефакторинг через FFI?

Методология использует то, что Mara называет FFI refactoring, то есть переписывание функции или небольшой части функций на другом языке и связывание её с существующим приложением через интерфейс взаимодействия между языками. В представленном примере приложение Flask продолжает принимать HTTP-запрос и декодировать JSON, затем передаёт данные статистической функции, написанной на Rust, после чего возвращает результаты в Python и отправляет ответ.

Связь основана на интерфейсе C, который фактически служит общим языком между множеством систем и языков. В случае Python проект PyO3 предоставляет инструменты для создания модуля, импортируемого из Python, а Maturin можно использовать для сборки этого модуля. Такие программные атрибуты, как pyfunction и pyclass, превращают функции и структуры данных в Rust в интерфейсы, вызываемые из Python.

Выбор подходящей функции и измерение эффекта

Эксперимент рекомендует искать функции, которые либо вызываются часто, либо отличаются высокой стоимостью одного вызова. Функция может быть относительно дешёвой при каждом запуске, но выполняться для каждого запроса, например логика проверки перед обработчиками API. С другой стороны, существуют редкие, но очень дорогие операции. Критерием должен быть совокупный эффект на процессорное время, а не впечатление, что конкретная функция выглядит медленной.

В статистическом примере реализация на Rust при измерении самой функции через Python оказалась чуть более чем в сто раз быстрее, хотя тест запускал оба приложения через интерпретатор Python. Однако при измерении полного HTTP-обработчика, включая Flask, сериализацию и десериализацию JSON, улучшение составило лишь около 15%. Время выполнения исходной версии функции составляло примерно 86 микросекунд — небольшое значение для одного вызова, которое, однако, может превратиться в значительные затраты при широком масштабировании.

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

Функциональная совместимость, тесты и ограничения

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

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

Тестирование включает непосредственные тесты Rust, существующие тесты Python для обработчиков Flask, тесты, сравнивающие результаты обеих реализаций, а также property-based тестирование, когда оно уместно. Однако добавление нативного кода создаёт эксплуатационные сложности: средам разработки нужен компилятор Rust или бинарные файлы, совместимые с операционной системой и архитектурой, развёртывание становится сложнее, а также появляется вероятность новых ошибок.

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

Источник новости
InfoQ - Architecture Articles
Открыть первоисточник ↗
ف
Автор

فريق تحرير certi.news

В той же категории

Вам также может понравиться

Все новости