Monoio: высокопроизводительная среда выполнения Rust на основе ввода-вывода

задняя часть открытый источник Язык программирования
Monoio: высокопроизводительная среда выполнения Rust на основе ввода-вывода

MonoioЭто высокопроизводительная среда выполнения Rust, основанная на модели ввода-вывода «поток-на-ядро», исходный код которой открыт группой ByteDance Service Framework Group, целью которой является обеспечение необходимой среды выполнения для таких сценариев, как высокопроизводительное промежуточное программное обеспечение сети.

Репозиторий проекта:GitHub.com/byte dance/no…

задний план

В прошлом высокопроизводительное сетевое ПО промежуточного слоя или серверы часто писались на C/C++, например наши распространенные Envoy и Nginx. Они, как правило, взаимодействуют с операционной системой очень прямым образом, и благодаря отсутствию сборки мусора накладные расходы очень низкие, а задержка стабильна по сравнению с языками с GC (такими как Golang и Java).

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

Почему бы не попробовать магию Rust? Язык Rust гарантирует безопасность памяти без внедрения сборки мусора за счет введения модели владения, а благодаря встроенной в язык асинхронной абстракции поддерживаетasync + awaitмодель асинхронного программирования. Используя хороший Runtime, вы можете писать асинхронный код на Rust так же плавно, как и на Golang — и производительность не уступает C++.

Rust Runtime и модель потоков на ядро

В отличие от Golang стандартная библиотека в Rust не предоставляет асинхронную среду выполнения (Runtime), только необходимую структурную абстракцию. Среда выполнения отвечает за работу с операционной системой и согласование с определениями Future и Waker стандартной библиотеки.Пользователи могут выбирать среду выполнения самостоятельно.

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

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

NGINX и Engoney Этот тип компонентов часто используют модуль для поток для каждого ядра, которая заключается в том, насколько проходит поток, и после того, как задача принимается потоком, его последующая обработка находится на потоке. В этой практике практически нет накладных расходов по никам, улучшит использование ЦП, что может лучше поддерживать линейную масштабируемость системы. Кроме того, поскольку нет перекрестной резьбы, логика обработки также может максимально использовать удобство локальной резьбы, а общие данные могут работать без блокировки.

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

представление

Мы сравнили Monoio, Tokio и Glommio (другая похожая среда выполнения, но менее агрессивная, чем Monoio, в плане производительности).

Monoio имеет более низкую задержку и более высокую пропускную способность в подавляющем большинстве тестов. По сравнению с Tokio, Monoio может обеспечить повышение производительности в 2-3 раза в многоядерных сценариях (в основном из-за модели, нет накладных расходов на синхронизацию между потоками); и по сравнению с Glommio мы можем уменьшить задержку, сэкономив около 1/4 до 1/3 использования ЦП (улучшение производительности связано с улучшенной реализацией планирования, пакетной отправкой io-uring).

Дальнейшие отчеты о тестировании и компромиссы дизайна хорошо задокументированы в репозитории Github.

Кроме того, мы также сравнили (на основе epoll) Nginx, используемый в производстве.В сценарии прокси TCP-прокси, написанный на основе Monoio, может достичь аналогичной производительности (производительность Monoio лучше, чем у Nginx, когда количество подключений велико, а время разница меньше чем Nginx.общие данные почти). Сравнение с TCP-прокси Envoy также показывает, что Monoio имеет очень очевидное преимущество в производительности.

Эпилог

Monoio обеспечивает высочайшую производительность среды выполнения для сценариев «поток на ядро». Наша цель — сделать Rust лучшей заменой C/C++ в высокопроизводительных сценариях. В настоящее время Byte приступил к созданию Service Mesh следующего поколения на основе Rust и Monoio.

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

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