پیاده سازی لود بالانسر Vortex با IO Uring
توی این کامیت دو تا کار جالب کردم:
۱- اومدم تو io uring از روشی استفاده کردم که تعداد سیستم کال هارو به حداقل برسونه. یعنی اگر توی روش قبلی ۱۰۰ تا سوکت به صورت همزمان به سرور وصا میشدن، باید ۱۰۰ تا سیستم کال انجام میدادیم، ولی الان توی یک سیستم کال همشون رو پردازش میکنیم:
while (true) {
io_uring_submit_and_wait(&ring_, 1);
unsigned cqe_count = 0;
unsigned head;
io_uring_for_each_cqe(&ring_, head, cqe) {
++cqe_count;
auto *request = static_cast<io_request *>(io_uring_cqe_get_data(cqe));
if (request) {
switch (request->type()) {
case io_request::request_type::accept:
request->socket().on_accept(request, cqe->res);
prepare_accept(request->socket());
break;
default:
core::logger::error("Unknown request type");
break;
}
delete request;
}
}
io_uring_cq_advance(&ring_, cqe_count);
}
وقتی که 1 رو به
io_uring_submit_and_wait
میدیم، این متد منتظر فقط یک ایونت میشه تا ترد من رو ازاد کنه و لوپ اصلی شروع به کار کنه. خب مگه نگفتیم یک ایونت؟ پس چطور ممکنه ۱۰۰ تا سوکت رو همزمان داشته باشیم؟! این یک که گفتم به این معنی نیست که اگه فقط یک ایونت اتفاق بیفته تنها همون ایونت توی صف باشه، در واقع io_uring این قابلیت رو داره که چندین ایونت (مثلاً چندین درخواست از سوکتهای مختلف توی یک لحظه) رو توی یه مرحله جمعآوری کنه. یعنی اگه چندتا سوکت همزمان به به سرور من درخواست بفرستن، io_uring تمامی اوتارو توی یه سیستم کال مدیریت میکنه و همشون رو به صف
completion queue
اضافه میکنه. در نتیجه وقتی
io_uring_submit_and_wait
حداقل منتظر یه ایونته احتمالاً چندین ایونت به صف اضافه شده و توی لوپ با ماکرو
io_uring_for_each_cqe
همهی این ایونت ها رو بدون نیاز به سیستم کال جدید پردازش میکنیم.
۲- اومدم یکم دیزاین پترن و اینترفیس ریختم تو پروژه، طوری که الان هسته ی نوتیفیکیشن بر اساس io uring کار میکنه، ولی اگه خواستم فردا روی epoll یا هرچیز دیگه ای ببرم راحتتر انجام بشه
لینک فایلای تغیر داده شده:
https://github.com/aabolfazl/Vortex/pull/3/files
نظری یا سوالی اگه بود بهم بگین.
@knowpow