ar
Feedback
An Inspired Engineer

An Inspired Engineer

الذهاب إلى القناة على Telegram

اینجا در مورد performance, distributed systems و کرنل لینوکس مینویسم

إظهار المزيد
244
المشتركون
لا توجد بيانات24 ساعات
لا توجد بيانات7 أيام
لا توجد بيانات30 أيام
أرشيف المشاركات
چرا NGINX انقدر وحشتناک سریعه؟! بخش دوم: Blocking I/O -------------------------------------- توی بخش قبلی فهمیدیم که NGINX ترافیک روتینگ رو توی لایه‌ی چهار و لایه‌ی هفت مدل OSI انجام میده و از مدل Reverse Proxy استفاده میکنه. حالا باید بدونیم چطور NGINX چندین هزار رکویست رو در لحظه میتونه مدیریت کنه؟! خب NGINX میاد از Nonblocking I/O برای مدیریت کانکشن ها استفاده میکنه، ولی من اول میخوام بریم ببینیم که اصلا Blocking I/O چیه که Nonblocking I/O هم وجود داره؟ اصن چرا باید بلاک بشه چیزی؟ زمانی که برنامه ای میخواد به IO دسترسی پیدا بکنه باید یه سری فرایند رو بگذرونه که این کارها زمانبره و به صورت blocking انجام میشه، یعنی فرض کنید اگر برنامه‌ای میخواد یک فایلی باز کنه تا اون رو بخونه باید فرایند زیر رو طی کنه: ۱- سیستم کال: باید درخواست باز کردن فایل رو با سیستم کال open بدین ۲- تغییر حالتCPU: کرنل برای اینکه بتونه این درخواست رو پردازش کنه نیاز داره که CPU رو به حالت کرنل تغییر بده(چرا؟ چون سوئیچ ضروریه و دسترسی مستقیم به سیستم فایل و منابع سخت افزاری کاری محسوب میشه که فقط کرنل مجازه انجام بده) ۳- صحت سنجی آدرس: اول کرنل شروع میکنه ببینه ادرس فایلی که دادین درسته بعد هم چک میکنه ببینه که آیا شما مجازین که این کار رو انجام بدین یا نه ۴-تخصیص فایل: در نهایت اگه مراحل قبل موفق باشه، کرنل یه file handler یا file descriptor به این فایل تخصیص میده ۵- بررسی قفل فایل: کرنل اینجا چک میکنه ببینه کسی قبل از شما این فایل رو قفل کرده یا نه و اگه کسی نباشه به این فایل یک lock در نظر میگیره و فایل رو باز میکنه ۶-بازگشت توصیفگر فایل: بعد از باز کردن فایل، کرنل file descriptor رو بعد از اینکه CPU به حالت یوزر برگشت به شما برمیگردونه و شما باقی کارها رو با اون file descriptor انجام میدین خب این مسیر کلی بود که پروسس شما برای باز کردن یه فایل ساده انجام میداد، الان میخوام بگم کدوم مراحل ممکنه پروسس شمارو بلاک کنه و بیشتر از طبق معمول طول بکشه، تغییر حالت CPU از کرنل به یوزر یه کار هزینه بره ولی من چون توی همه‌ی سیستم کال ها اینکارو انجام میدیم دیگه درنظرش نمیگیرم، حالا توی مرحله ی ۳ اگه ادرسی که دادین روی یه هارد مکانیکی باشه یا روی دیسکتون بار خوندن و نوشتن بالایی وجود داشته باشه میتونه اینکار بلاک بشه، توی مرحله ی ۳ چک کردن دسترسی ها نیازی به کار خاصی نداره و سریع انجام میشه، توی مرحله ی ۴ هم کارا سریع انجام میشن ولی اگه کرنل به حد مجاز توصیفگرهای فایل(file descriptor)هایی که باز هستن نزدیک بشه و نیاز به مدیریت و تخصیص مجدد ریسورس داشته باشه ممکنه بیشتر از حد معمول طول بکشه توی مرحله ی ۵ هم پتانسیل بلاک شدن وجود داره چون اگر پروسس دیگه ای فایل رو قفل کرده باشه، کرنل باید منتظر آزاد شدن قفل باشه که طبیعتا منتظر موندن کرنل یعنی بلاک شدن پروسس ما. توی مرحله‌ی اخر تنها کاری که مجبوری انجام بدیم و بازگشت به حالت کاربر هست و تمام جمع بندی: هر کاری که نیاز به I/O داشته باشه به احتمال خیلی زیاد پروسس شمارو بلاک میکنه و باید منتظر تموم شدن کاری که درخواست کردیم باشیم، چرا گفتم به احتمال خیلی زیاد؟! چون توی حالت عادی که باری روی سیستم نیست تمامی باس های داده خالیه و همه میتونن راحت رفت و آمد کنن، ولی وقتی بار سیستم میره بالا و باس های داده مثل اتوبان کرج-تهران میشه و دیگه همه چی مثل قبل نیست، باید برای باز کردن فایل که یه کار ساده محسوب میشه صبر کنیم و پروسسمون رو بلاک کنیم، و این اصلا برای سیستسم خوب نیست. دقت کنید که ما حاضریم هزینه ی انجام دادن تسک رو بدیم ولی نباید ریسورس سیستم رو برای کاری مثل منتظر موندن برای خلوت شدن باس داده یا در دسترس بودن lock انجام بدیم، اینکاره که سیستم رو کند میکنه، مگر نه من اگه بخوام یه فایل یه میلیون سطری رو بخونم هیچ چاره ای ندارم جز اینکه خط به خط این فایل رو بخونم و هزینه ی این تسک رو باید بدم چون هیچ راه فراری وجود نداره غیر از اینکه خط به خط فایل خونده بشه، ولی میتونم یه مکانیزم استفاده کنم که سیستم رو منتظر باز شدن قفل فایل، ازاد شدن باس داده و هرچیز دیگه ای نکنم! اسم این مکانیزم Nonblocking I/O هست که توی پست بعدی صحبت میکنم در موردش. @knowpow

اگه اینجا اون ریورس پروکسی که توی عکس میبینیم رو بهش یه لاجیکی اضافه کنیم که تصمیم بگیره با یه مبنایی ترافیک رو به یه مقصدی ه
اگه اینجا اون ریورس پروکسی که توی عکس میبینیم رو بهش یه لاجیکی اضافه کنیم که تصمیم بگیره با یه مبنایی ترافیک رو به یه مقصدی هدایت کنه در حقیقت ما یه لودبالانسر ساختیم لود بالانسرها به همین سادگی هم نیستن ولی کلیت ماجرا اینه @knowpow

چرا NGINX انقدر وحشتناک سریعه؟! بخش اول: Traffic Routing -------------------------------------- مدتی بود دنبال پروژه ای بودم که با هدف عمیق تر شدن توی مفاهیم شبکه و کانکارنسی بتونم با سی++ پیاده سازی کنم، هم فال بود و هم تماشا. بعد از یه مدت تصمیم گرفتم سمت وب‌سرورها برم و رفتار اونارو زیر بار بررسی کنم، سورس NGINX رو دانلود کردم و شروع کردم به بیلد کردنش و بعد از سر و کله زدن با openssl در نهایت بیلدش کردم، هدف من بیشتر مشاهده ی رفتار NGINX روی حالتی بود که میخواست Load balancing کنه. طبق چیزی که دیدم NGINX میاد و به دو روش معمول ترافیک رو به سمت سرور های مقصد ارسال میکنه، به طوری که میتونیم بگیم به روش Reverse proxy داره ترافیک رو سمت سرور مقصد هدایت میکنه. وقتی درخواستی از سمت کلاینت ارسال میشه NGINX اون رو دریافت میکنه و طبق الگوریتمی سرور مقصد رو انتخاب میکنه و روش یه سوکت جدید باز میکنه همچنین ممکنه از سوکت های قبلی که اماده داره به سرور مقصد استفاده کنه تا زمان Connection Establishing رو کاهش بده، بعد ترافیک رو از کلاینت میخونه و به سمت سرور اصلی فوروارد میکنه و منتظر جواب میمونه(بخش های بعدی میگم چطور) بعد از اینکه جواب از سرور مقصد دریافت شد اون رو به کلاینت برمیگردونه و تمام. حالا چرا گفتم ۲ روش؟ چون هم میتونه این کار رو توی لایه ی ۴ نتورک مدل OSI انجام بده هم میتونه توی لایه ی ۷ مدل OSI انجام بده، اگه بخواییم بهتر متوجه بشیم من هم میتونم به NGINX بگم که درخواست هارو بر اساس هدر، سشن یا اندپوینت هدایت کنم(لایه‌ی ۷)، هم میتونم اجازه بدم بر اساس IP یا PORT کاربر این اتفاق بیوفته(لایه‌ی ۴). ‌ وقتی ما نیاز داریم که سشن یا هدر رو چک کنیم در حقیقت نیاز داریم که داده ای که برامون ارسال شده رو باز کنیم و پردازشش کنیم و بعد بر اساس اون تصمیم بگیریم ولی توی مدل دوم نیازی به داده ی ارسالی نداریم و IP و PORT کاربر مشخصه، پس میتونیم بگیم روش اول توی لایه ی هفتم و روش دوم توی لایه ی چهارم اتفاق میوفته که طبیعتا سریعتر از روش اول باید باشه. @knowpow

Oppenheimer - Ludwig Göransson (320).mp37.03 MB

در میان کثافت اینستاگرام، تو یوتوب باش با چنین محتوایی... این 16 دقیقه آینده خیلی ها رو تغییر میده، در دنیای احتمالات شاید یکی از این "خیلی ها" سی سال دیگه نوبل فیزیک ببره؛ و البته در دنیای احتمالات، یک نوجوون ایرانی پشت فیلترینگ این فرصت رو از دست میده. (محسن طهماسبی) https://www.youtube.com/watch?v=ErMSHiQRnc8

روس ها توی مسابقات برنامه نویسی همیشه جزو تاپ ترین ها بودن، چرا اینو گفتم؟! چون یکی از محصولات خوبی که هرروز ازش استفاده میکنیم و پر از نوآوری هست و کیفیت کاملا متفاوتی داره هم توسط مهندسای روسی که خودشون جزو تاپ ۱۰ مسابقات بودن ساخته شده: بله تلگرام. حتی یکی از بزرگترین سایت های مسابقات (codeforces) هم توسط روس ها ساخته و میزبانی میشه و تلگرام هم پشتیبانی مالی میکنه از این سابت، حالا من دوتا کانال توی این پست میخوام معرفی کنم که میاد از همین سایت مباحث الگوریتم و ساختمان های داده که بنظرم مهم ترین رکن مهندسی نرم افزار هست رو به روشی که توی مسابقات بهش فکر میکنند و سریع کد مینویسن یاد میده، یعنی به شما competitive programming یاد میده، کانال اول از Errichto، برنده ی چند ده مدال از مسابقات برنامه نویسی، لهستان https://www.youtube.com/@Errichto کانال دوم از Colin Galen، مدال طلا توی مسابقات بین المللی، ایالات متحده: https://www.youtube.com/c/ColinGalen @knowpow

اینجا دو مدل سیستم عامل داریم که مدل اول Time Sharing و مدل دوم هم Multi Programing هست توی مدل اول کرنل میاد بدون توجه به وضعیت پروسس cpu رو از پروسس میگیره و به پروسس دیگه میده، یعنی اگر فکر کنید ما ۵ تا پروسس داریم و هر کدوم یه مدت t طول میکشه انجام بشن، کرنل دائما میاد این t رو بر اساس یک زمان‌بندی مشخص (scheduling) تخصیص رو انجام میده و cpu رو در اختیار اون پروسس میزاره، یعنی اگر بگیم که ما ۵ تا پروسس رو روی یک هسته‌ی cpu اجرا میکنیم و هرکدوم میانگین ۱ دقیقه طول میکشه باید در نهایت ۵ دقیقه وقت برای انجام شدن این پروسس ها در نظر بگیریم که این کاملا اشتباهه، ما اینجا وقت تلف شده داریم! از کجا؟! از کرنل، یعنی وقتی که کرنل میاد cpu رو از p1 بگیره و به p2 بده در حقیقت خودش هم داره اجرا میشه، ما زمانی که کرنل داره اجرا میشه رو میتونیم به عنوان وقت تلف شده در نظر بگیریم،‌چون در حقیقت هیچ کار مفیدی انجام نشده، پس داریم که: Total time = sum(kernel time) + t p1..p5 مدل دوم هم مدل Multi Programing هست که کرنل cpu رو در اختیار یک پروسس میزاره و بر خلاف مدل قبلی منتظر پروسس میمونه تا وقتی که پروسس وارد وضعیت waiting بشه(اینجا من فقط در مورد IO حرف میزنم)، مثلا منتظر کارت شبکه بمونه تا یه دیتایی بیاد، وقتی که پروسس بلاک میشه و میره توی وضعیت waiting کرنل میاد و cpu رو به پروسس بعدی میده. از دید کاربر مدل اولی بهتره چون همزمان میتونه هم توی ورد تایپ کنه، هم آهنگ گوش بده هم منتظر نوتیفیکشن ها تلگرامش باشه، ولی از دید سرعت انجام شدن کار ها مدل Multi Programing سریعتره چون کمتر کرنل وارد میشه و در نتیجه زمان تلف شده ی کمتری داریم. @knowpow

این ویدیو نشون میده که ناسا چطور توی دهه ی ۶۰ راکت Saturn V رو کنترل میکرد،‌ واقعا عجیبه، ساختار مموری رو میتونین با چشم ببینید،یه سری گره وجود داره که اینا نسبت به هم مغناطیسی میشن، وقتی یه گره به یه جهت مغناطیسی بشه ینی یک اگه برعکسش باشه یعنی صفر، به همین سادگی(!) https://www.youtube.com/watch?v=dI-JW2UIAG0&t=71s

09. BIROKH [PROD. BY PEYMANDEGAR].mp37.04 MB