رفتن به فضای کاری بزرگتر، بدون اینکه کسی را منتظر بگذاریم
هر پروژهی Mythex فضای کاری خودش را دارد: یک کامپیوتر ابری کوچک که عامل در آن کد مینویسد و پیشنمایش اپ شما اجرا میشود. برای فضاهای کاری جدید حافظه را از ۱ گیگابایت به ۲ گیگابایت برده بودیم، اما فضاهای قدیمیتر روی ۱ گیگابایت ماندند — در روزی که بررسی کردیم، حدود یکچهارمشان. اولین اصلاح ما، پروژه را هنگام باز شدن بعدی به یک فضای کاری بزرگتر منتقل میکرد. در اولین روز تولید، همین کار باعث شد یک نفر هفت دقیقه منتظر بماند. بعد یک مهلت زمانی سخت روی آن گذاشتیم، و در نهایت انتقال را کلاً از باز کردن پروژه حذف کردیم.
چرا فضاهای قدیمی کوچک ماندند
ارائهدهندهی sandbox ما اندازهی فضای کاری را هنگام ساخته شدن تعیین میکند و در تمام توقفها و ازسرگیریها نگه میدارد. تغییر قالب — دستورالعملی که فضاهای کاری جدید از روی آن ساخته میشوند — فقط روی فضاهایی اثر دارد که بعد از تغییر ساخته شدهاند. چیزی فضاهای موجود را تغییر اندازه نمیدهد.
این مهم بود. یکی از فضاهای کوچک هنگام git push در حین شروع پیشنمایشش حافظهاش تمام شد و ۱۱ دقیقه پاسخ نداد. یک انتشار به همین دلیل شکست خورد.
تلاش اول: هنگام بیدار شدن پروژه را منتقل کن
فضاهای کاری وقتی کسی از آنها استفاده نمیکند متوقف میشوند و وقتی پروژه باز شود بیدار میشوند. بیدار شدن بهنظر لحظهی درستی برای انتقال پروژه میآمد، چون هنوز کسی در آن کار نمیکند.
انتقال اینطور کار میکرد:
- اندازه را بررسی کن. اگر فضای کاری کوچکتر از ۲ گیگابایت است، منتقلش کن. اگر اندازهاش نامعلوم است، هیچ کاری نکن.
- انتشار را مختل نکن. انتشار فایلهای فضای کاری را میخواند، پس اگر یکی در حال اجراست، انتقال را رد کن.
- پروژه را بستهبندی کن. همهچیز پروژه را آرشیو کن — از جمله تاریخچهی git، یعنی هر checkpoint که پروژه دارد، و فایل
.envخود اپ که متعلق به صاحب است — اما وابستگیهای نصبشده (node_modules) را کنار بگذار، چون میتوانند دوباره نصب شوند. - مستقیم منتقلش کن. آرشیو را از فضای کاری قدیمی به یک فضای کاری تازه ۲ گیگابایتی جریان بده، تا هرگز مجبور نباشد در حافظهی سرور خودمان جا شود.
- قبل از جابجایی مقایسه کن. در هر دو فضای کاری تعداد فایلها، آخرین checkpoint و تعداد checkpointها را بشمار. فقط وقتی هر سه برابر بودند جابجا کن.
- با هر خطا، قدیمی را نگه دار. هر خطا یا عدم تطابق، فضای کاری جدید را دور میاندازد و پروژه را مثل قبل در فضای قدیمی باز میکند.
یک جزئیات در مقایسه بیش از آنچه به نظر میرسد اهمیت داشت. بررسی با حساب مدیر اجرا میشود، و git از خواندن مخزنی که مالکش کاربر دیگری است خودداری میکند. هر دو طرف چیزی چاپ نمیکردند — و «هیچ» با «هیچ» برابر بود، پس بررسی بدون اینکه تاریخچهای را مقایسه کند قبول شد. به git گفتیم به آن پوشه اعتماد کند، و یک تست اضافه کردیم که این اشتباه دوباره وارد نشود.
روز اول چه شد
در اولین روز تولید، بستهبندی یک پروژه به یک مهلت پنج دقیقهای فرمان در داخل بیدار شدن خورد. مالک هفت دقیقه منتظر ماند تا فضای کاریاش باز شود. و چون انتقال شکست خورده بود، پروژه هنوز کوچک بود، پس باز کردن بعدی دوباره تلاش میکرد و دوباره منتظرش میگذاشت.
یک مهاجرتی که هنگام باز کردن پروژهی خود کسی را منتظر بگذارد، معاملهی بدی است. تمام هدف از انجامش هنگام بیداری این بود که کسی متوجه نشود.
تلاش دوم: بودجهی سخت
همان روز چهار چیز را عوض کردیم:
- یک دقیقه برای کل انتقال. هر مرحله — بررسی اندازه، بستهبندی، ساخت فضای کاری جدید، کپی، باز کردن و مقایسه — یک بودجهی مشترک ۶۰ ثانیهای دارد. وقتی تمام شود، پروژه در فضای کاری قدیمی باز میشود.
- خود کار را متوقف کن، نه فقط انتظار را. دست کشیدن از سمت خودمان کافی نیست اگر آرشیو کردن هنوز داخل فضای کاریای که مالک قرار است از آن استفاده کند در حال اجرا باشد. هر فرمان آرشیو حالا درون خود فضای کاری، کمی قبل از پایان بودجه، کشته میشود. اگر فضای کاری جدید بعد از اینکه ما دست کشیدهایم برسد، دور انداخته میشود.
- مالک را برای پاکسازی منتظر نگذار. حذف آرشیو موقت حالا در پسزمینه انجام میشود.
- هر بار باز کردن دوباره امتحان نکن. پروژهای که نتوانست منتقل شود ۲۴ ساعت دستنخورده میماند، پس یک شکست حداکثر یک تأخیر در روز هزینه دارد، نه یکی برای هر باز کردن.
تلاش سوم: انتقال را از بیداری بیرون بیاور
این بدترین حالت را به یک دقیقه رساند. اما یک دقیقه هنوز یک دقیقه است، و فهمیدیم انتقال اصلاً نیازی نیست روی مسیر کسی باشد.
دیگر هیچ فضای کاریای با ۱ گیگابایت ساخته نمیشود. پس این یک کار ادامهدار نیست؛ یک کار یکباره با فهرست ثابتی از فضاهای کاری است. انجامش داخل بیدار شدن یعنی یک انسان واقعی هزینهی هر انتقال کند را میپرداخت، و تنها راهی که میفهمیدیم فضایی منتقل نمیشود این بود که کسی تازه منتظرش مانده باشد.
پس انتقال را کلاً از بیداری حذف کردیم. باز کردن پروژه مثل قبل کار میکند. فضاهای کاری کوچکی که باقی ماندهاند، بهعنوان یک دستهی نظارتشده مدیریت میشوند: کسی منتظرش نیست، و فضایی که منتقل نشود در گزارش دسته ظاهر میشود، جایی که میتوانیم نگاهش کنیم، نه جلوی چشم مالکش.
آنچه از این ماجرا یاد گرفتیم
- تغییر اندازه همیشه ممکن نیست. وقتی یک پلتفرم اندازه را هنگام ساخت ثابت میکند، بالا بردن پیشفرض فقط برای چیزهای جدید کمک میکند. برای قدیمیها برنامه بریزید.
- «هنوز کسی از آن استفاده نمیکند» به معنی این نیست که کسی منتظر نیست. کاری که در مسیر ورود به یک محصول انجام میشود، کاری است که یک انسان تماشایش میکند.
- روی هر چیزی که در مسیر کاربر است بودجه بگذار، و وقتی بودجه تمام شد کار را متوقف کن. از سمت خودمان مهلتزمانی بگذاریم در حالی که فرمان در جای دیگری همچنان اجرا میشود، فقط مشکل را جابهجا میکند.
- یک مهاجرت یکباره باید در یک کار یکباره باشد. پنهان کردن آن داخل کارهای روزمره نوشتنش را ارزانتر و اجرایش را گرانتر میکند.
- بررسیهای ایمنیات را تست کن. مقایسهای که چیزی را مقایسه نمیکند، دقیقاً شبیه مقایسهای است که قبول شده.
اگر روی Mythex میسازید، کاری لازم نیست: هدف فقط این است که فضاهای کاری کمتری از حافظه تمام شوند، و باز کردن پروژه مثل قبل سریع باشد. اینکه فضاهای کاری چطور متوقف و بیدار میشوند، در مستندات، زیر فضای کاری خصوصی پوشش داده شده است. برای داستان دیگری از کرش حافظه، کرش حافظهای که پشت یک برچسب پیشرفت پنهان بود را ببینید.