امیر صالحی
امیر صالحی
خواندن ۴ دقیقه·۱ ماه پیش

چطور تونستیم Failure تسک هایی که سمت GPU ها میره رو به صفر برسونیم

مقدمه

ما سرویس AI در حوضه املاک (real estate) میدیم که کلا با عکس سرو کار داریم، ینی اینکه فرض کن شما از پذیرایی خونتون یه عکسی میگیرید و میخواید پذیرایی رو بدون اثاث ببینی، شما میدی به ما و ما با استفاده از AI کل اثاث های شمارو پاک میکنیم، این یکی از سرویس ها بود و تعداد سرویس ها بیشتر از اینهاست.

طبیعتا تعداد زیادی از این عکس ها میاد سمت ما و ما باید بتونیم به درستی این عکس ها رو بدیم به AI تا برای ما Generate بکنه.

اصلا داستان چیه؟ (قبل بهبود)

ما ۵ تا GPU لوکال داریم، ینی ۵ تا GPUی که دقیقا بغل گوشمونه که بهش به اصطلاح task میدیم تا کاراشو بکنه. ۲ تا GPU cloud داریم و از سرویس FaaS هم استفاده میکنیم که ۳۰ تا GPU داره

نکته ای که باید اضافه کنم اینه که FaaS به تازگی اضافه شده و ما کل کار رو با ۷ تا GPU جمع میکردیم.

حالا ما برای توزیع تسک ها قبلا به این شکل بود که یه RabbitMQ بالا بود و برای هر GPU یه worker بالا اومده بود و تسک های مختلف به این شکل توزیع میشد که میرفت میدید ببینه کدوم صف از همه خلوت تره و هر کدوم که خلوت تر بود تسکو مینداخت توی اون صف، حالا مشکل این بود که به هر دلیلی اگه worker به مشکلی میخورد کل تسک های داخل اون صف failed میشد، این مشکلی که worker هم میخورد بیشتر به خاطر اختلالی که توی اینترنت کشور میوفتاد بود.

به چارت بالا اگه دقت کنید، عکسی هستش که من قبلا از تغییرات گرفتم و اون رنگ های قرمز تعداد تسک های fail شدست که در ۳ روز گذشته اتفاق افتاده

  • رنگ قرمز: تسک های fail شده
  • رنگ سبز پررنگ: تسک هایی که زیر ۳۰ ثانیه Generate شدن
  • رنگ سبز کم رنگ: تسک هایی که بین ۳۰ تا ۶۰ ثانیه Generate شدن
  • رنگ آبی: تسک هایی که بین ۶۰ تا ۹۰ ثانیه Generate شدن
  • رنگ زرد: تسک هایی که بیشتر از ۹۰ ثانیه زمان برده تا Generate بشن


چطوری بهبودش دادیم؟

ما یه سرویس کاملا جدا آوردیم بالا به اسم Dispatcher که این سرویس وظیفش اینکه که بتونه تسک هارو به شکل بهینه توزیع کنه بین GPU ها، این سرویس جزيیات خیلی زیادی داره که بعدا تو یه مقاله ای دیگه توضیح میدم اما الان کلیات رو میگم.

این سرویس رو ما با Golang نوشتیم و RabbitMQ رو کامل حذف کردیم و از پترن worker pool استفاده کردیم، ما اومدیم GPUها رو گروه بندی کردیم و بهشون تگ زدیم، برای مثال یه دسته GPU لوکال داریم، یک دسته GPU cloud داریم و یک دسته FaaS داریم.

برای دسته هایی که امکان fail شدن تسک براشون خیلی زیاده رو یه backup گذاشتیم، برای مثال GPU های local امکان اینکه تسک fail بشه زیاده چون اختلال اینترنت باعث میشه GPUها از دسترس خارج بشن و تسک رو fail بکنه سر همین اگه fail کرد ما باید برای تسک بتونیم تصمیم بگیریم، اینجا وقتی میبینم یک تسک رفت سمت local و fail شد بر میداریم میزنیم به cloud چون GPU های stableی داره و این retry کردن رو ما حداکثر تا ۳ بار انجام میدیم.

شاید از خودتون سوال بپرسید چرا همون اول به cloud نمیزنم؟

چون برامون هزینه میتراشه، GPU های لوکال رو باید تو الویت ما باشن و چون خریدیمشون و کنار گوشمونن و اول به اونا میزنیم و بعد به cloud که همین باعث میشه تعداد تسک های fail ما خیلی کم بشه، اما نا گفته نمانند که GPUهای cloud هم تسک میگیرن و انجام میدن و همیشه منتظر نمیمونن که تسکی fail بشه تا بیاد سمتشون

حالا کی به FaaS میزنیم؟

سرویس FaaS با هر ریکوئستی که سمتش بفرستیم از موجودی ما پول کم میکنه و باید خیلی حواسمون باشه که هر تسکی سمتش نره و تسک هایی با الویت بالا رو سمتش بفرستیم.

یکی از مواردی که این سرویس Dispatcherی که نوشتیم داره انجام میده اینکه میتونه برای ما تسک ها رو الویت بندی بکنه، برای مثال کاربرهای آمریکا که بیشتر مشتریان ما هستند و چند تا از سرویس های ما براشون خیلی جذابه رو Segementهاشو مشخص کردیم و میزنیم به FaaS چون زیر ۳۰ ثانیه به ما جواب میده.

چارت بالایی که میبینید آماری هستش که ما بعد از پیاده سازی سرویس جدیدمون به اسم Dispatcher برای ما رقم زده و تعداد تسک های fail ما رو تقریبا به صفر رسونده.

توی پست های بعدی بیشتر راجب dispatcher صحبت میکنم که چطور کار میکنه.

gpuaigolangتسک
علاقه مند به دنیای استارت آپ و توسعه فردی
شاید از این پست‌ها خوشتان بیاید