خلاصه سریع: پروژه tokio-quiche هم‌اکنون متن‌باز شد 🎉 — یک کتابخانه‌ی asynchronous برای QUIC که ترکیبی از quiche و runtime غیرهمزمان Rust یعنی Tokio است. این کتابخانه در مسیرهای پراکسی Cloudflare، شامل Proxy B در Apple iCloud Private Relay و پروکسی‌های Oxy نسل بعدی به کار می‌رود و توانایی پردازش میلیون‌ها درخواست HTTP/3 در ثانیه را با تاخیر پایین و throughput بالا دارد. همچنین کلاینت MASQUE در WARP که جایگزین تونل‌های WireGuard شده است با کمک همین تکنولوژی پیاده‌سازی شده است. همچنین این پروژه با معماری state machine برای مدیریت وضعیت پروتکل‌ها طراحی شده است. 👇


چرا state machine در tokio-quiche مهم است


استفاده از state machine در tokio-quiche به مدیریت بهتر حالت‌های ارتباط QUIC و HTTP/3 کمک می‌کند و به سازگاری با Tokio و مدل الگوهای actor پشتیبانی می‌دهد.

خلاصه سریع: پروژه tokio-quiche هم‌اکنون متن‌باز شد 🎉 — یک کتابخانه‌ی asynchronous برای QUIC که ترکیبی از quiche و runtime غیرهمزمان Rust یعنی Tokio است. این کتابخانه در مسیرهای پراکسی Cloudflare، شامل Proxy B در Apple iCloud Private Relay و پروکسی‌های Oxy نسل بعدی به کار می‌رود و توانایی پردازش میلیون‌ها درخواست HTTP/3 در ثانیه را با تاخیر پایین و throughput بالا دارد. همچنین کلاینت MASQUE در WARP که جایگزین تونل‌های WireGuard شده است با کمک همین تکنولوژی پیاده‌سازی شده است. 👇

چند کلمه درباره پیش‌زمینه: حدود شش سال پیش quiche به‌عنوان یک پیاده‌سازی متن‌باز و حافظه‌ایمن برای QUIC منتشر شد. اما طراحی اولیه‌اش از نوع sans-io بود؛ یعنی خودِ کتابخانه منطق حالت (state machine) پروتکل را پیاده می‌کند ولی هیچ فرضی درباره نحوه انجام IO توسط مصرف‌کننده‌اش ندارد. این رویکرد عالی برای انعطاف‌پذیری است، اما زمانی که بخواهید آن را در یک برنامه async واقعی و با Tokio یکپارچه کنید، کار خسته‌کننده و مستعد خطاست — باید socketهای UDP را مدیریت کنید، datagramها را بفرستید و دریافت کنید و تمام این‌ها را به شکل async با runtime هماهنگ کنید. tokio-quiche همین زحمت‌ها را برای شما برمی‌دارد — هیچ روغنی لازم نیست 😉.

پایین آوردن مانع ورود 🚪

ریشه‌ٔ ایجاد tokio-quiche از نیاز داخلی برای داشتن یک کلاینت HTTP/3 با پشتیبانی از MASQUE آمد. تیم‌های Zero Trust و Privacy نیاز داشتند تا داده‌ها را از طریق WARP و Privacy Proxies تونل کنند و مطلوب بود که از همان تکنولوژی برای client و server استفاده شود. هدف از متن‌باز کردن quiche این بود که پیاده‌سازی حافظه‌ایمن QUIC و HTTP/3 را در اختیار جامعه بگذاریم، اما تجربه نشان داد ادغام یک کتابخانه sans-io در یک اپلیکیشن واقعی می‌تواند زمان‌بر و خطاپذیر باشد. پس با tokio-quiche تلاش کردیم بخش بزرگی از کد لازم برای یکپارچه‌سازی با runtime را خودمان آماده کنیم تا ورود به این اکوسیستم ساده‌تر شود.

باز کردن کد برای همه باعث می‌شود شرکت‌ها و تیم‌هایی که می‌خواهند با محصولات و سیستم‌های ما تعامل کنند، راحت‌تر HTTP/3 را بپذیرند و در نتیجه کل اکوسیستم سریع‌تر به استاندارد جدید مهاجرت کند. tokio-quiche سال‌هاست که درون Cloudflare مورد استفاده قرار گرفته و در همین مدت پالایش و آزمون‌های میدانی لازم انجام شده تا نشان دهد می‌تواند میلیون‌ها RPS را پاسخ دهد. توجه داشته باشید که این پروژه به‌عنوان یک کلاینت یا سرور مستقل کامل عرضه نمی‌شود؛ بلکه پیاده‌سازی پروتکل‌های سطح پایین را فراهم می‌کند تا پروژه‌های سطح بالاتر بتوانند روی آن ساخته شوند — در README مثال‌هایی از event loop برای سرور و کلاینت وجود دارد.

همه‌چیز بر پایه actor است 🎭

Tokio یک runtime غیرهمزمان محبوب در Rust است که مدیریت و زمان‌بندی میلیاردها تسکی که در لبه اجرا می‌شوند را کارآمد انجام می‌دهد. چون ما در Cloudflare به‌شدت از Tokio استفاده می‌کنیم، تصمیم گرفتیم quiche را به‌صورت محکم با آن یکپارچه کنیم — حاصل نام tokio-quiche شد. در پشت صحنه، این کتابخانه از مدل actor برای پیشبرد قسمت‌های مختلف state machine مربوط به QUIC و HTTP/3 استفاده می‌کند. Actorها معمولاً تسک‌های کوچک با state داخلی هستند که با پیام‌گذاری (message passing) روی channelها با دنیای بیرون ارتباط برقرار می‌کنند.

چرا مدل actor مناسب است؟ چون هم actorها و هم طراحی‌های sans-io هر دو با مفهوم state داخلی و پیام‌ها کار می‌کنند. در quiche پیام‌ها عملاً بایت‌های خامی هستند که نمایانگر داده‌های شبکه ورودی و خروجی‌اند. در tokio-quiche یکی از پیام‌ها ساختاری به اسم Incoming است که بسته‌های UDP ورودی را توصیف می‌کند. روند async کردن یک کتابخانه sans-io معمولاً شامل منتظر ماندن برای پیام یا IO، ترجمه آن پیام‌ها به چیزی که کتابخانه می‌فهمد، پیش‌برد state machine، ترجمه خروجی به پیام یا IO و در نهایت فرستادن آنها است. برای بحث فنی بیشتر درباره actorها در Tokio می‌توانید پست عالی Alice Rhyl را ببینید.

هادی اصلی در tokio-quiche یک IO loop actor است که بسته‌ها را بین quiche و socket جا‌به‌جا می‌کند. چون QUIC یک پروتکل transport است، می‌تواند هر پروتکل اپلیکیشنی را حمل کند — HTTP/3 رایج است اما DNS over QUIC یا Media over QUIC مثال‌های دیگرند. tokio-quiche یک trait به اسم ApplicationOverQuic ارائه می‌دهد تا روی پروتکل‌های اپلیکیشنی انتزاع ایجاد کند؛ این trait متدهای quiche و I/O زیرین را انتزاع می‌کند تا شما بیشتر روی منطق اپلیکیشن تمرکز کنید. برای مثال، کلاینت دیباگ و تست HTTP/3 ما، یعنی h3i، بر پایه یک پیاده‌سازی client-focused از ApplicationOverQuic ساخته شده است.

H3Driver — درایوری که روی HTTP/3 تمرکز دارد — همراه tokio-quiche عرضه می‌شود. این درایور ماژول HTTP/3 را به IO loop متصل می‌کند و بلوک‌های ساختمانی لازم برای ساخت یک کلاینت یا سرور async HTTP/3 را فراهم می‌آورد. H3Driver رویدادهای خام HTTP/3 را به رویدادهای سطح بالاتر و streamهای داده‌ای async تبدیل می‌کند تا شما بتوانید به‌راحتی به آن‌ها پاسخ دهید. خودِ درایور generic است و دو واریانت مشخص ServerH3Driver و ClientH3Driver دارد که هرکدام رفتارهای اضافه‌تری روی رویدادهای هسته‌ای سوار می‌کنند.

جریان داده داخلی 🔁

در داخل tokio-quiche دو تسک مهم اجرا می‌شوند تا حرکت داده از socket به quiche سامان بگیرد. یک تسک به اسم InboundPacketRouter مالک نیمهٔ دریافت‌کنندهٔ socket است و دیتاگرام‌های ورودی را بر اساس connection ID (DCID) به channel هر اتصال مسیر‌دهی می‌کند. تسک دوم، یعنی IoWorker actor، همان IO loop است که یک ارتباط quiche را هدایت می‌کند؛ این تسک فراخوانی‌های quiche را با متدهای ApplicationOverQuic درهم‌تنیده می‌کند تا امکان بازرسی وضعیت اتصال قبل و بعد از هر تعامل IO فراهم شود.

بیشتر مطالب فنی درباره نحوه پیاده‌سازی actorها، استفاده از mutexها، UDP GRO و GSO، بودجه‌بندی همکاری taskها در tokio و موارد مشابه به زودی در پست‌های بعدی منتشر خواهد شد — اگر در حوزه SRE یا DevOps کار می‌کنید، این مباحث برای بهینه‌سازی عملکرد در لبه شبکه بسیار کاربردی‌اند.

مرحله بعد: بیشتر درباره QUIC و فراتر 🚀

tokio-quiche پایهٔ مهمی برای سرمایه‌گذاری Cloudflare در اکوسیستم QUIC و HTTP/3 روی Tokio است، اما خودش هنوز فقط یک بلوک ساختمانی با پیچیدگی‌های خاص است. در آینده قصد داریم همان انتزاع‌های آسان برای استفاده‌ی کلاینت و سرور را که امروز پروکسی‌های Oxy و کلاینت‌های WARP از آن بهره می‌برند، به‌صورت متن‌باز منتشر کنیم. همچنین منتظر انتشار کلاینت متن‌باز برای مشتریان Privacy Proxies و یک سرویس کاملاً جدید که با tokio-quiche میلیون‌ها RPS را مدیریت می‌کند باشید! برای شروع می‌توانید crate مرتبط را روی crates.io ببینید و سورس را در GitHub بررسی کنید — شاید یک echo server ساده، یک DNS-over-QUIC client، یک VPN سفارشی یا حتی یک HTTP server کامل بسازید. شاید شما جلوتر از ما عمل کنید 😉.

اگر دنبال راهکارهایی برای حفاظت از شبکه‌ها، ساخت برنامه‌های اینترنت‌سکیل، شتاب‌دهی وب‌سایت‌ها، دفع حملات DDoS یا مسیر رسیدن به Zero Trust هستید، مجموعهٔ خدمات ما می‌تواند کمک کند — و اگر دنبال تغییر مسیر شغلی هستید، فرصت‌های شغلی هم موجود است. ✨