تیم نینجا: گزارش نجات پروژه چت ایکس
در سری پستهای «تیم نینجا» در مورد پروژههای واقعی صحبت میکنم که در شرایط بحرانی بودند و از من خواسته شد تا با درست کردن یک «تیم نینجا» در مدت زمان خیلی کوتاهی مشکلات اساسی این پروژهها را حل کنم.
تیمهای نینجا تیمهایی هستند که خیلی سریع درست میشن، به یه هدف خاص میرسن و بعد از هم جدا میشن. افراد این تیمها معمولا افراد خیلی حرفهای هستند که به راحتی نمیشه همه اونها رو تو یک تیم به صورت فولتایم داشت. ولی برای یک پروژه با وضعیت بحرانی ممکنه چند روز تصمیم بگیرن و با هم اون مشکل رو حل کنن.
پروژه چت شرکت ایکس (برای حفظ حریم شخصی شرکت از این نام برای شرکت استفاده میکنم) مربوط به محصولی از شرکت ایکس بود که ناگهان مشتریان زیادی پیدا کرده بود و باعث شده بود که در مواقعی نیاز پیدا کنه که به حدود ۱۰،۰۰۰ کاربر همزمان در یک ثانیه پاسخگو باشه و همه کاربران در مدت زمان کوتاهی بتونن ارتباط دوطرفه چت فعال داشته باشن.
به عنوان اولین قدم ما باید مشکلات گزارش شده رو دقیق شناسایی کنیم و صورت مسئله رو از «حالت همه چی کنده، سایت پایین میاد و کار نمیکنه» به عبارات دقیق فنی تبدیل کنیم. نتیجه این مرحله، شناسایی موارد زیر بود:
- عدم امکات اتصال کابران وقتی کاربران بیش از ۲۰۰۰ نفر شود
- قطع شدن کاربران و نگرفتن پیامها
- کند شدن سیستم چت در وقتی کاربران بیشتر از ۲۰۰۰ نفر شود
- کند شدن یا قطع شدن سایت در هنگامی که کاربران همزمان یک کاری را انجام میدهند
تکنولوژیهای مورد استفاده در این پروژه عبارت بودند از:
- کدهای سمت سرور: C#, .NetFramework 4.7, ASP.NET WebApi, SignalR
- کدهای سمت کلاینت: Angular 8.0
- دیتابیس: SQL Server
ساختار کلی کد به این صورت بود که تقریبا بیزنس همه سیستم به صورت SP و در دیتابیس نوشته شدهبود و لایه بکاند تقریبا تنها کاری که انجام میداد فراخوانی SP های دیتابیسی بود.
پس از بررسی فنی، مشکلات اصلی این سیستم به صورت زیر دستهبندی شدند:
- کدهای غیر بهینه سمت سرور چت برای مدیریت ارسال پیامها
- غیر async بودن قسمتهای مهمی از کد
- کدهای غیر بهینه در قسمت کار با دیتابیس
- وجود SP های کندی که باعث میشد جداول مورد نیاز بقیه برای مدت طولانی قفل شوند
- عدم معماری مناسب برای Scale Out کردن سرورهای SignalR
- مشکل در مکانیسمهای Reconnect در کدهای نوشته شده سمت SignalR
برای شروع کار و اطمینان از اینکه کل این پروژه در عرض ۱ هفته تمام میشود به غیر از حل مشکلات بالا نیازمند زیرساختهای دیگری نیز بودیم. از بین زیرساختهایی که نیاز داشتیم این تیم فقط سورسکنترل داشت و بقیه را باید ایجاد میکردیم.
- فرایند CI/CD: زیرساخت با توجه به حجم زیاد و پیدرپی تغییرات تصمیم گرفتیم یک تیم خیلی سریع، فرایند CI/CD را راهاندازی کند تا بتوانیم تغییرات را خیلی سریع روی محیطهای مختلف ببریم و تست کنیم. برای این کار از زیرساخت Azure DevOps استفاده کردیم و کل فرایند را روی Azure Pipelines فراهم کردیم. محیطهای DEV, QA, UAT و PROD محیطهایی بود که برای این پروژه ایجاد شد.
- سیستم لاگ: یکی از مهمترین مشکلات این پروژه نداشتن سیستم لاگ متمرکز بود. نبودن این لاگها باعث شده بود که مشکلات فقط حدس زده شوند و با سعی و خطا بعضی از مشکلات را بتوانند فقط به صورت مقطعی حل کنند. یک تیم مسئول ساخت زیرساخت لاگ Splunk برای شرکت شد تا عملکرد سیستم جدید را بتوان از طریق لاگ بررسی و مانیتور کرد. این سیستم به ما کمک کرد تا بتوانیم SP های کند را به تیم دیتابیس گزارش دهیم تا بتوانند مشکلات آنها را بررسی و برطرف کنند.
- سیستم Load Test: با توجه به اینکه مشکل پرفورمنسی که مهمتری مشکل گزارش شده بود و امکان تست این مشکل در حالت عادی وجود نداشت، یک تیم مسئول آماده کردن محصول و زیرساختی کوچک و سریع برای فراهم کردن محیط شبیهسازی شده لایو در محیط تست شد. در این شبیهسازی باید چت ۱۰،۰۰۰ کاربر همزمان قابل انجام میبود تا محصول جدید را بتوانیم با هم تست کنیم.
- بازنویسی کد: پس از بررسی کدها به این نتیجه رسیدیم که قسمتی از کد باید به طور کامل بازنویسی شود. قسمتی که مربوط به سیستم چت بود اولا باید کاملا از کدهای سایت جدا میشد. از طرفی بیزنسهای آن باید کامل بازنویسی میشد تا بتواند توان پاسخگویی تعداد زیادی از کاربران همزمان را داشته باشد. به دلیل زمان کمی که داشتیم تصمیم گرفتیم از زیرساخت Azure SignalR Service هم استفاده کنیم تا بتوانیم به راحتی سیستم را برای تعداد کانکشنهای همزمان بالای ۱۰،۰۰۰ نیز scale کنیم. تصمیم دیگر برای بازنویسی مهاجرت به NET 5 بود تا بتوانیم راحتتر از امکانات جدید استفاده کنیم.
یکشنبه بود، روزی که قرار بود روی سایت واقعی لود بالایی بیاید. زمان آن رسیده بود که نتیجه زحمات تیم را که حاصل همکاری همه افراد تیم ما و شرکت بود را با هم ببینیم. در ابتدا چند مشکل کندی به وجود آمد که لحظات خیلی پر استرسی را رقم زد. واقعا همه تیم نفسهاشون گرفته بود. ولی بعد با استفاده از لاگهایی که اسپلانک گزارش میداد خیلی سریع توانستیم مشکلات را شناسایی کنیم و در عرض چند دقیقه، به قول بچهها یک هو نفس سیستم باز شد! و نفس عمیییق...
تیمهای ما که همه ریموت بودن و هر تیم از یه جایی داشت قسمت خودش رو بررسی میکرد و فقط از طریق گروه اسکایپ صوتی مشترک در ارتباط بودیم یه هو پر از شادی شدیم. زحمات یک هفته گذشته ما که شبانهروزی بود کار کرد.
تو تیم نینجایی که برای این پروژه تشکیل شد افراد زیر رو داشتیم:
- افشین: مثل همیشه افشین رو داشتیم. افشین همیشه کمک میکنه کارهای غیرممکن رو بتونیم انجام بدیم. افشین تو این پروژه کل سیستم DevOps رو خیلی سریع راهاندازی کرد. افشین این کار رو با ریحانه از تیم خود شرکت پیش بردن که تونستن ساختار CI/CD رو در سریعترین زمان ممکن راه بندازن. همچنین افشین کمک کرد که سیستمهای SignalR رو روی Azure SignalR Service ببریم و Scale کنیم.
- وحید: نفر بعدی تیم وحید بود. وحید تجربه خیلی خوبی تو ساخت پروژههای پیچیده و کار در شرایط پر استرس داره. وحید تو این پروژه خیلی سریع سیستمهایی رو نوشت که بتونیم باهاش محصول نهایی رو ببریم زیر بار و پرفورمنس تست رو انجام بدیم.
- یاسر: یاسر معمار Bit Framework هست که همیشه Best Practice استفاده از تکنولوژیهای رو میدونه. یاسر بهمون کمک کرد تا به بهترین روش از SignalR استفاده کنیم و پروژه رو ببریم روی NET 5.
- شایان: شایان از بچههای خود شرکت بود و برنامهنویس خیلی تیزی بود. برای همین خیلی از کارها رو با هم انجام دادیم و تو اغلب کدهایی که من مینوشتم با شایان pair بودیم.
- محسن: راهانداختن زیرساخت قابل scale واسه لاگ با Splunk تو یکی دو روز کار سادهای نیست. این کار رو محسن در زمان خیلی کوتاهی انجام داد.