Amirali Yaghoutiمهندس ارشد نرم‌افزار

مطالعه موردی مهندسی

محافظ طوفان Transient

دو افزونه روی فروشگاه، به‌ازای هر بازدید محصول یک ترنزینت می‌نویسند: محصولات مرتبط ووکامرس و بازدیدهای اخیر YITH. روی کاتالوگی به این بزرگی، این یعنی بیش از یک میلیون ردیف در wp_options، و هزینه‌اش را هر بار بالاآمدن وردپرس می‌دهد.

مسئله تجاری

در wp_options حدود ۱٫۳ میلیون ردیف _transient_wc_related_ و _transient_yith_wrvp_ جمع شده بود. توصیه‌ی رایج یک کرون پاک‌سازی شبانه است، اما یک DELETE JOIN روی جدولی به این حجم آن‌قدر طول می‌کشد که کاربر در فرانت حسش کند. من چیزی می‌خواستم که فقط موقع طوفان راه بیفتد و جدول options را هیچ‌وقت طولانی نگه ندارد.

آنچه تحویل دادم

  • mu-transient-storm-guard.php، یک MU-plugin ۱۰۲ خطی با یک رویداد روزانه که در روز سالم اصلاً کاری نمی‌کند.
  • آستانه‌ی جدا برای هر خانواده، نه یک آستانه‌ی سراسری: wc_related بالای ۴٬۰۰۰ ردیف پاک می‌شود و yith_wrvp بالای ۲٬۰۰۰، چون سرعت رشدشان یکی نیست.
  • یک جاروی تکه‌تکه برای ترنزینت‌های منقضی که هر اجرا ۲۰۰ ردیف timeout را پاک می‌کند، به‌جای آن DELETE JOIN که اغلب اسنیپت‌ها سراغش می‌روند.
  • یک گارد که در حین جاب‌های WP All Import کل اجرا را رد می‌کند، تا ایمپورت کاتالوگ و پاک‌سازی سر یک جدول به هم نخورند.

رویکرد فنی

  • اول بشمار، بعد پاک کن. هر خانواده با یک COUNT(*) اندازه گرفته می‌شود و فقط وقتی از آستانه‌ی خودش رد شده باشد پاک می‌شود. نتیجه اینکه افزونه بیشتر روزها هیچ کاری نمی‌کند.
  • هر پاک‌سازی سقف ۲٬۰۰۰ ردیف دارد و ردیف مقدار را همیشه همراه ردیف _timeout_ متناظرش برمی‌دارد، تا timeout یتیمی نماند که فردا دوباره شمرده شود.
  • رویداد روزانه ۳۰۰ ثانیه بعد از init زمان‌بندی می‌شود، نه بلافاصله؛ لحظه‌ای که سایت خودش درگیر بالاآمدن است بدترین وقت برای این کار است.
  • مالتی‌سایت پاس جداگانه‌ی خودش را با فلگ شبکه می‌گیرد.

نتیجه و شواهد

هر دو خانواده زیر آستانه‌شان ماندند و اندازه‌ی wp_options دیگر مدام بالا و پایین نمی‌رود: جدول transient از حدود ۱٫۳ میلیون ردیف به حدود ۱۸۰ هزار رسید، همان عددی که در یادداشت‌های عمومی کارایی ثبت شده. زمان بالاآمدن را قبل و بعد در شرایط کنترل‌شده بنچمارک نکردم. پس ادعایم ساختاری است: در یک روز عادی، پاک‌سازی برای هر خانواده فقط یک کوئری شمارش خرج دارد، و هیچ‌وقت یک join روی کل جدول.

اهمیت برای کارفرما

این همان نگهداری‌ای است که تا کار می‌کند دیده نمی‌شود. حدود صد خط کد، یک منبع تکرارشونده‌ی کندی بی‌دلیل را برداشت که هر چند هفته یک‌بار برمی‌گشت.

خلاصه-اجرایی-پروژه

خلاصه اجرایی خوانا

خلاصه_اجرایی {
  پروژه: "Transient Storm Guard"
  فایل: "mu-plugins/mu-transient-storm-guard.php (۱۰۲ خط)"
  شروع: "کرون روزانه، ۳۰۰ ثانیه پس از init"
  آستانه‌ها: "wc_related > ۴۰۰۰ ردیف، yith_wrvp > ۲۰۰۰ ردیف"
  پاک‌سازی: "سقف ۲۰۰۰ در هر خانواده، ردیف مقدار + timeout"
  جارو: "۲۰۰ ترنزینت منقضی در هر اجرا، بدون DELETE JOIN"
  رد_می‌کند: "درخواست‌های WP All Import، تا سر جدول تداخل نشود"
}

ارزش حرفه‌ای این پروژه

چیزی که اینجا ارزش دیدن دارد خود آستانه است، نه حذف. نوشتن یک کرون پاک‌سازی از هر کسی برمی‌آید؛ خطر این است که خود پاک‌سازی روی یک جدول پرترافیک تبدیل به مسئله شود.

ترجیح می‌دهم چیزی تحویل بدهم که معمولاً هیچ کاری نمی‌کند و فقط وقتی اعداد توجیهش می‌کنند وارد عمل می‌شود. اول اندازه بگیر، بعد محدود مداخله کن؛ بیشتر کارهای عملیاتی‌ام همین شکلی است.