جشنواره‌ی فجر مهم‌ترین رویداد سینمای داخلی است. آن هم نه فقط برای فیلم‌بین‌ها و فیلم‌سازها، بلکه برای سینماها و بلیت‌فروش‌ها هم رویداد بسیار مهمی است. جشنواه‌ی فجر سال از بسیاری از جهات عجیب‌ترین جشنواره‌ی فجری بود که در این سال‌ها برگزار شد. از نامشخ ص بودن وضعی ت برگزاری آن تا دو هفته مانده به زمان جشنواره تا فروش تمام الکترونیکی بلیت‌های آن. فروشی که در چندساعت او ل عملا در کار نبود، چون تمام بلیت فروش‌ها از دسترس خارج شدند. این چندساعت عدم دسترس را بگذارید کنار تعطیلی تقریبا یک‌ساله‌ی سینماها و نیاز شدید تمام بخش‌های سینما به جریان نقدینگی‌ای که جشنواره‌ی فجر قراربود ایجاد کند. اینطوری شاید متوج ه اهم ی ت این خاموشی چندساعته بشوید. در این نوشته می‌خواهیم دلیل فن ی از دسترس خارج‌شدن سینماتیکت را، به عنوان بزرگ‌ترین فروشنده‌ی بلیت، با هم ببینیم. جشنواره‌ای متفاوت این جشنواره‌ی فجر با بقیه‌ی جشنواره‌ها فرقی مهم داشت. به خاطر شرایط کرونایی قرارشد که بلیت‌فروشی تنها به صورت اینترنتی انجام شود. مسیله این بود که تمام پایانه‌های فروش امسال برای او لین بار باید از طریق API های "سمفا"، سامانه‌ی مدیریت فروش سازمان سینمایی، بلیت‌فروشی می‌کردند. و خب این سازمان هم به همه اطمینان داده بود که ما بررسی‌های لازم را انجام داده‌ایم و مطمین هستیم که باری که هنگام شروع بلیت‌فروشی عمومی به روی سایت‌ها می‌آید برای ما مشکلی ایجاد نمی‌کند. در این جشنواره قرار بر این شد که دو روز زودتر از بلیت‌فروشی عمومی، بلیت‌فروشی برای افرادی که از طرف خود جشنواره‌ی فجر و سازمان‌های دیگر کد تخفیف دریافت کرده‌اند شروع شود و پس از آن فروش عمومی آغاز شود. فروش افراد خاص در آن دو روز انجام شد و به جز یک سری مشکلات کوچک در اعتبارسنجی کدها توس ط سمفا، مشکل دیگری وجود نداشت. پنج دقیقه پیش از فاجعه ساعت : روز شنبه بهمن . تنها پنج دقیقه تا شروع فروش عمومی جشنواره‌ی فجر باقی مانده بود. هر دقیقه به تعداد افراد آنلاین روی سینماتیکت هزارنفر افزوده می‌شد. همه‌چیز خوب پیش می‌رفت و تمام مانیتورها وضعی ت سرورها را خوب نمایش می‌دادند. نه مشکلی در سرعت بارگذاری سایت وجود داشت و نه مشکلی در کارکردهای مختلف آن. همه خوشحال و منتظر ساعاتی پرفروش بودند. ساعت : و اینک آخرالزمان ساعت به رسید و بلیت‌فروشی عمومی شروع شد. برای یکی دو دقیقه‌ی او ل همه‌چیز خوب بود. تا اینکه پیام‌های پر از نگرانی تیم‌های بازاریابی و مدیریت شروع شد: سایت باز نمی‌شود. تا بررسی سایت را شروع کردیم خبر آمد که دو سامانه‌ی فروش دیگر هم از دسترس خارج شده‌اند. این خودش قو ت قلب بود. چیزی که عجیب بود این بود که هنوز وضعی تی که در سیستم مانیتورینگ از سرورها می‌دیدیم عادی بود. یعنی منطقا نباید هیچ مشکلی وجود می‌داشت. حالا که رقبا هم غیر قابل دسترس بودند و فشار و استرس کم‌تر شده بود، یک بار دیگر پیام‌های خطا را بررسی کردیم. قضیه عجیب‌تر شد. پیام‌های خطای رنج مستقیما از طرف Nginx صادر می‌شدند. اصلا درخواست‌ها به سرورهای ما نمی‌رسید. از آن‌جایی که تمام Nginx ها در پاسخ تمامی درخواست‌ها خطای برمی‌گرداندند، تمامی عملکردهای سایت از کار افتاده بودند و افراد با ورود به سینماتیکت تنها یک صفحه‌ی خالی را مشاهده می‌کردند. چون که وب‌اپلیکیشن ما امکان دریافت هیچ داده‌ای را از سرورها نداشت. خبر جدیدی از تیم‌های دیگر به ما رسید: سایت‌های دیگر سامانه‌های فروش باز می‌شدند. ولی همچنان امکان فروش نداشتند. اوضاع دوباره برای تیم‌های فن ی و زیرساخت پرفشار شده بود. چون تمامی وبسایت ما غیرقابل استفاده بود. برخلاف دیگران که تنها بخش خریدشان از کار افتاده بود. ما برای حدود دقیقه هیچ فروشی نداشتیم. چرا Nginx دیگر پاسخگو نیست؟ اینکه هیچ سامانه‌ی فروشی امکان خرید نداشت ما را تقریبا متقاعد کرد که مشکل به خاطر پایین‌آمدن سرویس‌های سمفا است. چیزی که با بررسی لاگ‌ها ت یید شد. ام ا سوال اصلی این بود که چرا تمام سایت از دسترس خارج شده؟ با کمی بررسی بیشتر عل ت مشخ ص شد. تمام سرورهای ما، و در نتیجه تمام Nginx ها، برای گرفتن پلان سانس‌ها، لیست سانس‌ها، رزرو صندلی‌ها و تکمیل سفارشات به سمفا درخواست ارسال می‌کنند. حالا که هیچ‌کدام از API های سمفا پاسخ نمی‌دهند، سوکت‌های ما به سرورهای سمفا باز می‌مانند و از آن‌جایی که تعداد درخواست‌ها بسیار زیاد است، تمام سوکت‌های تمام Nginx ها پر شده اند. در نتیجه به صورت خودکار هنگامی که یک درخواست به یک Nginx می‌رسد، خود آن Nginx به صورت خودکار با یک خطای آب پاکی را روی دستان فرستنده می‌ریزد. چرا دیگر امکان ساخت سوکت جدید وجود نداشت؟ اول از همه ببنیم که سوکت چیست. سوکت درگاهی است که ارسال و دریافت داده‌ها از طریق آن انجام می‌شود. در واقع، سوکت یک ساختار نرم‌افزاری است که به یک پردازه تعلق دارد. در سیستم‌عامل‌های لینوکسی، مثل سیستم‌عاملی که ما روی ماشین‌هایمان از آن استفاده می‌کنیم، هر سوکت در واقع یک file descriptor است. همان‌طور که می‌دانید، ما هم تعداد محدودی file descriptor را می‌توانیم به صورت هم‌زمان استفاده کنیم. برای تغییر این محدودی ت‌ها باید محدودی ت سخت تعداد فایل‌های باز را در سطح سیستم‌عامل تغییر بدهیم. پس از آن محدودی ت نرم آن را هم می‌توان از طریق سیستم‌عامل یا خود تنظیمات Nginx تغییر داد. اگر می‌خواهید از میزان این محدودی ت روی سیستم‌عامل خودتان با خبر شوید، می‌توانید از دستور استفاده کنید. مثلا محدودی ت‌های پیش‌فرض ابونتو این است: با اینکه ما محدودی ت تعداد سوکت‌ها را با توج ه به نیازمان به صورتی منطقی تنظیم کرده بودیم، ولی از آن‌جایی که زمان زیادی طول می‌کشید تا ات صال‌های TCP / IP باز، بسته شوند، تمام ماشین‌ها به سقف ظرفی ت تعریف‌شده رسیده بوند. یعنی هنگامی که درخواست جدیدی به Nginx می‌رسید، از آن‌جایی که دیگر هیچ file descriptor آزادی وجود نداشت، پذیرش درخواست هم امکان‌پذیر نبود و به صورت خودکار یک پیام به فرستنده‌ی درخواست داده می‌شد. تلاش او ل برای رفع موق ت خطا او لین راه حل برای رفع موق ت مشکل، کاهش زمان timeout درخواست‌هایی بود که به سمفا ارسال می‌کردیم. هم‌زمان با بررسی‌های تیم زیرساخت، تیم فن ی میزان timeout را ثانیه کاهش داد. دلیل انتخاب این عدد این بود که باتوج ه به ت خیر پاسخگویی سمفا، بعید بود که با گذاشتن محدودی تی کم‌تر از ثانیه هیچ‌کدام از درخواست‌ها هیچ پاسخی دریافت کنند. امید ما این بود که با کاهش این عدد، کمی وضعی ت سرویس‌دهی بهتر شود. بال خره ساعت : ما او لین پاسخ‌ها را از API های سمفا گرفتیم. هرچند هنوز حجم درخواست‌هایی که منتظر پاسخ می‌ماندند بسیار زیاد بود. ولی شروع‌شدن فروش کمی از فشارها، چه از روی سرورها و چه از دوش تیم‌های فن ی، کم کرد. مسیله این بود که قراردادن timeout هم به تنهایی باعث رفع مشکل نشد و هنوز برای اکثر افراد سایت غیرقابل دسترس یا بسیار کند بود. بررسی راه حل های ممکن از آن‌جایی که هنوز کاربران زیادی دچار مشکل بودند، ما شروع به بررسی راه حل هایی کردیم که در دسترس‌مان بودند. او لین راه حل افزودن ماشین‌های جدید بود. مسیله این بود که آماده‌کردن ماشین جدید و ات صالش به بخش‌های دیگر کار زمان‌بری بود. از طرفی مهم‌ترین ساعات مهم‌ترین رویداد سینمایی کشور در حال تلف‌شدن بودند و اکثر کاربران امکان خرید بلیت را نداشتند. بلیت‌هایی که پول آن‌ها برای سینماهایی که یک سال تعطیل بودند و سامانه‌های فروشی که اکثر سال چیزی نفروخته بودند حیاتی بود. راه حل دیگری که مطرح‌شد، نجات‌دادن بخش‌هایی از سینماتیکت بود که با سمفا ارتباطی نداشتند. ما به این نتیجه رسیدیم که بهترین کار این است که فعلا تمام کاربران بدون مشکل بتوانند وارد سایت بشوند و تنها در صفحات خرید منتظر دریافت پاسخ از سمفا بمانند. اینطوری هم از نارضایتی آن‌ها کاسته می‌شد و هم احتمال اینکه منتظر عادی شدن شرایط سمفا بمانند افزایش می‌یافت. اینطوری کاربر کم‌تری از دست می‌رفت. ساعت : حالا من را می‌بینی ما دوباره به یک راه حل موق ت روی آوردیم. با تغییر تنظیمات HAProxy ، درخواست‌هایی که به سمفا می‌رفتند را به دو ماشین محدود کردیم. اینطوری فشار سوکت‌های بازمانده را از باقی ماشین‌ها کم کردیم. حالا، در ساعت ، وبسایت سینماتیکت بدون مشکل برای تمام کاربران بالا بود. هرچند هنوز تعداد زیادی از کاربران موقع خرید دچار مشکل می‌شدند. ساعت : وضعی ت سفید دو ساعت پس از راه حل موق ت ما، بال خره تعداد درخواست‌ها آن‌قدری کم شد که سمفا به اکثر درخواست‌ها پاسخ درست می‌داد. حالا هم سایت پایدار بود و هم کاربران امکان خرید داشتند. هرچند اکثر آدم‌هایی که قصد خرید داشتند تا این موقع شب دیگر ناامید شده بودند. حالا ساعت‌ها پس از شروع بلیت‌فروشی عمومی، تازه شرایط فروش قابل قبول شده بود و فشارها هم از تیم‌های فن ی برداشته شد. حالا می‌شد یک نفس راحت کشید و در آرامش یک لیوان چای نوشید. وضعی ت سفید شده بود. تمام اشتباهات ما درست است. ما زیر فشار کم نیاورده بودیم و این سمفا بود که از دسترس خارج شده بود. ولی عدم امکان دسترسی به وبسایت ما به خاطر از دسترس خارج شدن یک سرویس خارجی اشتباه ما بود. اگر بخواهیم به صورت کل ی نگاه کنیم، ما دو اشتباه بزرگ داشتیم: مثبت‌اندیشی ساده‌انگارانه ما تمام مد ت با یک مثبت‌اندیشی تو م با ساده‌انگاری با سرویس‌های شخص ثالث برخورد کردیم. همواره فرض ما در پیاده‌سازی بر این بوده که این سرویس‌ها در دسترس خواهند بود و اکثر اوقات پاسخ ما را می‌دهند. هرچند به خاطر فشار بازنویسی سینماتیکت برای ماه‌های ابتدایی نسخه‌ی جدید این مثبت‌اندیشی عاقلانه به نظر می‌رسید. ولی باید تا پیش از شروع جشنواره فجر بخش‌هایی از نرم‌افزار را که با این دید جلو رفته بودند تغییر می‌دادیم. درسی که از این موضوع گرفتیم این بود که همواره بنا را بر نادرستی سرویس‌های شخص ثالث بگذاریم. حت ی اگر deadline آن‌قدر نزدیک بود که نمی‌شد برای آن بدبینی چاره‌ای اندیشید. عدم پیاده‌سازی مکانیسم‌های جلوگیری از فاجعه درست است که اینجا هم می‌توان همان بهانه‌ی فشار deadline ها را آورد، ولی ما به اشتباه اولویت پیاده‌سازی مکانیسم‌های جلوگیری از فاجعه را از کارهای دیگر پایین‌تر درنظر گرفته بودیم. درسی که ما گرفتیم این بود که مکانیسم جلوگیری از فاجعه درست به اندازه‌ی خود ویژگی‌ای که در حال پیاده‌سازی آن هستیم اهم ی ت دارد. در این مورد خاص، کافی بود که ما از الگوی مدارشکن ( استفاده می‌کردیم. این الگو به زبان ساده و به شکل خلاصه می‌گوید: اگر به یک مقصد خاص چندبار درخواست زدید و پاسخی نگرفتید یا پاسخی که گرفتید معتبر نبود، برای مد تی به جای فرستادن درخواست جدید به همان مقصد، پیام خطا را به کسی که آن API را فراخوانی کرده برگردانید. اینطوری زیرساخت شما اسیر عملکرد نادرست شخص دیگری نمی‌شود و نرم‌افزار شما حت ی با وجود از کار افتادن سرویس‌های خارجی به زندگی‌اش ادامه می‌دهد. هنگام ساخت یک نرم‌افزار شما خیلی از چیزهای مهم را درنظر می‌گیرید. مفاهیم بزرگی که همان بزرگ بودن‌شان شما را گول می‌زند تا فکرکنید از باقی چیزها مهم‌تر هستند. اگر در این دام گرفتار شوید، چیزهای کوچکی که خیلی مهم هستند را فراموش می‌کنید. آن وقت می‌بینید سیستمی که تمام مشکلات بزرگ را به راحتی پشت سر می‌گذارد، به خاطر پیش پا افتاده‌ترین موضوعات زمین‌گیر می‌شود. یک ترک ریز در بدنه‌ی یک سد از چاله‌ای بزرگ وسط یک خیابان مهم‌تر است. نباید اجازه بدهیم که بزرگی و کوچکی انتزاعی مفاهیم، ما را از دایره‌ی ت ثیر آن‌ها در دنیای واقعی غافل کند. این مطلب توسط محمدرضا علی حسینی در نوشته شده است.