Чуть более 6 лет назад мы представили quiche — нашу реализацию QUIC с открытым исходным кодом, написанную на Rust. Сегодня мы объявляем об открытии исходного кода tokio-quiche — нашей проверенной в боях асинхронной библиотеки QUIC, объединяющей как quiche, так и асинхронную среду выполнения Rust Tokio. Обеспечивая работу Proxy B Cloudflare в Apple iCloud Private Relay и наших прокси следующего поколения на основе Oxy, tokio-quiche обрабатывает миллионы HTTP/3 запросов в секунду с низкой задержкой и высокой пропускной способностью. tokio-quiche также обеспечивает работу клиента Cloudflare Warp's MASQUE, заменяя наши туннели WireGuard на туннели на основе QUIC, и асинхронной версии h3i.
quiche была разработана как библиотека в стиле sans-io, что означает, что она реализует конечный автомат, необходимый для обработки транспортного протокола QUIC, не делая никаких предположений о том, как её пользователь намерен выполнять ввод-вывод. Это означает, что приложив достаточно усилий, любой может написать интеграцию ввода-вывода с quiche! Это подразумевает connect или listen на UDP-сокете, управление отправкой и получением UDP-датаграмм на этом сокете с одновременной передачей всей сетевой информации в quiche. Учитывая, что нам нужна асинхронная интеграция, нам пришлось бы делать всё это, интегрируясь с асинхронной средой выполнения Rust. tokio-quiche делает всё это за вас, усилий не требуется.
Снижение порога входа
Изначально tokio-quiche использовалась только как ядро HTTP/3 сервера Oxy. Но импульсом к созданию tokio-quiche как самостоятельной библиотеки стала наша потребность в HTTP/3 клиенте с поддержкой MASQUE. Нашим командам Zero Trust и Privacy нужны клиенты MASQUE для туннелирования данных через WARP и наши Privacy Proxies соответственно, и мы хотели использовать одну и ту же технологию для построения как клиента, так и сервера.
Изначально мы открыли исходный код quiche, чтобы поделиться нашей безопасной с точки зрения памяти реализацией QUIC и HTTP/3 с как можно большим количеством заинтересованных сторон. Наш фокус в то время был на низкоуровневом дизайне sans-io, который мог бы интегрироваться во многие типы программного обеспечения и широко развертываться. Мы достигли этой цели — quiche развернута во множестве различных клиентов и серверов. Однако интеграция библиотек sans-io в приложения — это подверженный ошибкам и трудоёмкий процесс. Наша цель с tokio-quiche — снизить порог входа, предоставив большую часть необходимого кода самостоятельно.
То, что только Cloudflare внедряет HTTP/3, не имеет особого смысла, если другие, желающие взаимодействовать с нашими продуктами и системами, также не перейдут на него. Открытие исходного кода tokio-quiche делает интеграцию с нашими системами более простой и помогает продвигать отрасль к новому стандарту HTTP. Возвращая tokio-quiche обратно в экосистему Rust, мы надеемся способствовать развитию и использованию HTTP/3, QUIC и новых технологий сохранения конфиденциальности.
tokio-quiche используется внутри компании уже несколько лет. Это дало нам время усовершенствовать и проверить её в боях, продемонстрировав, что она может обрабатывать миллионы RPS. tokio-quiche не предназначена для использования в качестве автономного HTTP/3 клиента или сервера, а реализует низкоуровневые протоколы и позволяет создавать более высокоуровневые проекты в будущем. В README приведены примеры циклов событий сервера и клиента.
Вездесущие акторы
Tokio — это невероятно популярная асинхронная среда выполнения Rust. Она эффективно управляет, планирует и выполняет миллиарды асинхронных задач, которые работают на нашем крае сети. Мы широко используем Tokio в Cloudflare, поэтому мы решили тесно интегрировать quiche с ней — отсюда и название, tokio-quiche. Под капотом tokio-quiche использует акторы для управления различными частями конечного автомата QUIC и HTTP/3. Акторы — это небольшие задачи с внутренним состоянием, которые обычно используют передачу сообщений через каналы для общения с внешним миром.
Модель акторов — это отличная абстракция для асинхронизации библиотек sans-io из-за концептуального сходства между ними. И акторы, и библиотеки sans-io имеют некое внутреннее состояние, к которому они хотят иметь эксклюзивный доступ. Обычно они взаимодействуют с внешним миром, отправляя и получая «сообщения». «Сообщения» quiche — это, по сути, сырые байтовые буферы, представляющие входящие и исходящие сетевые данные. Одно из «сообщений» tokio-quiche — это структура Incoming, которая описывает входящие UDP-пакеты. Из-за этого сходства асинхронизация библиотеки sans-io означает: ожидание новых сообщений или операций ввода-вывода, преобразование сообщений или операций ввода-вывода во что-то, что понимает библиотека sans-io, продвижение внутреннего конечного автомата, преобразование вывода конечного автомата в сообщение или операцию ввода-вывода и, наконец, отправку сообщения или выполнение операции ввода-вывода. (Для большего обсуждения акторов с Tokio обязательно ознакомьтесь с превосходным постом в блоге Alice Rhyl на эту тему.)
Основным актором в tokio-quiche является актор цикла ввода-вывода, который перемещает пакеты между quiche и сокетом. Поскольку QUIC — это транспортный протокол, он может передавать любой прикладной протокол по вашему желанию. HTTP/3 довольно распространен, но DNS over QUIC и предстоящий Media over QUIC — другие примеры. Существует даже RFC, который поможет вам создать своё собственное приложение поверх QUIC! tokio-quiche предоставляет трейт ApplicationOverQuic для абстрагирования над прикладными протоколами. Трейт абстрагирует методы quiche и базовый ввод-вывод, позволяя вам сосредоточиться на вашей прикладной логике. Например, наш HTTP/3 клиент для отладки и тестирования, h3i, работает на основе ориентированной на клиент, не-HTTP/3 реализации ApplicationOverQuic.

Диаграмма архитектуры сервера
tokio-quiche поставляется с ориентированным на HTTP/3 ApplicationOverQuic под названием H3Driver. H3Driver подключает HTTP/3 модуль quiche к этому циклу ввода-вывода, предоставляя строительные блоки для асинхронного HTTP/3 клиента или сервера. Драйвер преобразует сырые HTTP/3 события quiche в события более высокого уровня и асинхронные потоки данных тела, позволяя вам соответствующим образом на них реагировать. H3Driver сам по себе является обобщённым, предоставляя варианты ServerH3Driver и ClientH3Driver, каждый из которых добавляет дополнительное поведение поверх событий основного драйвера.

Внутренний поток данных
Внутри tokio-quiche мы порождаем две важные задачи, которые обеспечивают перемещение данных из сокета в quiche. Первая — это InboundPacketRouter, который владеет принимающей половиной сокета и маршрутизирует входящие датаграммы по их идентификатору соединения (DCID) в канал для каждого соединения. Вторая задача, актор IoWorker, — это упомянутый выше цикл ввода-вывода, который управляет одним quiche Connection. Он чередует вызовы quiche с методами ApplicationOverQuic, гарантируя, что вы можете проверить соединение до и после любого взаимодействия с вводом-выводом.
Вскоре появятся новые посты в блоге о создании tokio-quiche. Мы обсудим модели акторов и мьютексы, UDP GRO и GSO, совместное бюджетирование задач в tokio и многое другое.
Далее: больше о QUIC и не только!
tokio-quiche — это важный фундамент для инвестиций Cloudflare в экосистему QUIC и HTTP/3 для Tokio — но это всё ещё лишь строительный блок со своей собственной сложностью. В будущем мы планируем выпустить такие же простые в использовании абстракции HTTP-клиента и сервера, которые сегодня обеспечивают работу наших прокси Oxy и клиентов WARP. Следите за новыми постами в блоге о QUIC и HTTP/3 в Cloudflare, включая клиент с открытым исходным кодом для клиентов наших Privacy Proxies и совершенно новый сервис, который обрабатывает миллионы RPS с помощью tokio-quiche!