تا به این نکته تعجب کردید که چه چیزی در پشت صحنه رخ می دهد وقتی پیام های مشاوره درباره ی دستورالعمل در یک رزرو تائید شده را دریافت می کنید؟ یا شاید چگونه پس از انجام یک تراکنش پرداخت GrabPay با پاداش یا امتیاز مورد تشویق قرار می گیرید؟ در Grab، هزاران دستورالعمل مشابهی که به میلیون ها کاربر هدف می شوند روزانه توسط یک سرویس پشته به نام Trident اجرا می شود. در این پست ما درباره ی حمایت Trident از کسب و کار روزانه Grab، چالش های مهندسی پشت آن و راه حل های ما برای آن بحث می کنیم.
استعلام: Trident چیست؟
Trident در واقع موتور داخلی برنامه نویسی شده IFTTT (if this, then that) Grab است که اقدامات مختلف جریان کاری کسب و کار را به صورت خودکار انجام می دهد. ماهیت این جریان کارها می تواند به افزایش آگاهی یا تشویق کاربران برای استفاده از سرویس های دیگر Grab باشد.
اگر شما کاربر فعال مجله زیبایی و درمانی آذروت هستید، ممکن است متوجه پاداش ها و پیام های جدیدی شده باشید که در حساب مجله زیبایی و درمانی آذروت شما ظاهر می شوند. احتمالاً این پیام ها از یک کمپین Trident ناشی می شوند. در زیر چند نمونه از انواع کمپین هایی که Trident می تواند حمایت کند را بررسی می کنیم:
- پس از رزرو GrabExpress، Trident یک پیام به کاربر ارسال می کند که به صورتی مانند "از GrabMart هم استفاده کنید" است.Pas از استفاده چندین بار از سفرها روزانه، Trident به کاربر یک پاداش غذایی به عنوان پاداش GrabFood ارسال می کند.پس از رسیدن کاربر به دفتر خود در صبح، Trident به کاربر پاداش سفری را برای استفاده در راه بازگشت به خانه در همان شب هدیه می دهد.اگر سفارش تحویل GrabMart بیش از یک ساعت صبر لازم باشد، Trident به کاربر پاداش تحویل رایگان به عنوان جبران خسارت هدیه می دهد.اگر راننده رزرو را لغو کند، Trident به کاربر امتیازها به عنوان جبران هدیه می دهد.در شرایط فعلی شیوع کووید-19، وقتی یک کاربر یک رزرو سفر می کند، Trident یک پیام به هر دو مسافر و راننده ارسال می کند که درباره پروتکل های کووید یادآوری می کند.
Trident برنامه ها را بر اساس کمپین ها پردازش می کند که در واقع یک پیکربندی منطقی در مورد این است که چه رویدادی باید چه اقدامی را به چه شرایطی ایجاد کند. برای توضیح بهتر این موضوع، بیایید یک کمپین نمونه را که در تصویر زیر نشان داده شده است مورد بررسی قرار دهیم. این تنظیمات کمپین شبیه سازی نیاز داخلی Trident است.
این تنظیمات نمونه در واقع به این معنی است: برای هر کاربر، تعداد سفارشات GrabMart تکمیل شده او را محاسبه کنید. هنگامی که او به 2 سفارش برسد، پیامی را برای او ارسال کنید که می گوید "یک سفارش دیگر برای کسب پاداش انجام دهید". و اگر کاربر به 3 سفارش برسد، به او پاداش داده و پیامی تبریک ارسال کنید. 😁
علاوه بر رویداد پایه، شرایط و اقدامات پایه، Trident اجازه می دهد تنظیمات دقیق تری را مانند حمایت از بودجه کلی یک کمپین، افزودن محدودیت ها برای جلوگیری از ارائه بیش از حد جوایز، آزمایش A/B، تأخیر در اقدامات و غیره پیاده سازی کند.
یک موتور IFTTT چیزی جدید یا شیکی نیست، اما ساختن یک سیستم IFTTT بلادرنگ با توجه به مقیاس عملیاتی Grab یک چالش است. ما باید میلیاردها رویداد را کنترل کنیم و هزاران کمپین را در یک روز معمولی اجرا کنیم. مقدار اقداماتی که توسط Trident تریگر می شود همچنین بسیار زیاد است.
در ماه اکتبر 2020، بیش از 2000 رویداد در هر ثانیه در ساعات اوج پردازش شد. در طول کل ماه، ما تقریباً نیم میلیارد پاداش را اهدا کردیم و بیش از 2.5 میلیارد ارتباط را به کاربران نهایی ارسال کردیم.
حال که اهمیت Trident را برای کسب و کار پوشش دادیم، بیایید به صورت دقیق تر در مورد طراحی سیستم Trident برای کنترل رویدادها در بزرگنمایی بزرگ و چالش های کارایی آن صحبت کنیم.
طراحی معماری
ما معماری Trident را با هدف های زیر طراحی کردیم:
- استقلال: باید مستقل از سرویس های دیگر اجرا شود و بر کارایی سرویس های دیگر تأثیر نگذارد.قوی بودن: همه رویدادها باید دقیقاً یک بار پردازش شوند (بدون از دست دادن رویداد، بدون دوباره پردازش رویداد).قابلیت اطمینان: باید قادر به افزایش قدرت پردازش وقتی حجم رویداد زیاد است و مقاومت در برابر اجرای کمپین های محبوب باشد.
نمودار زیر نشان می دهد چگونه معماری کلی سیستم به نظر می رسد.
Trident از جریان های متعدد Kafka که توسط سرویس های زیرساخت مختلف در Grab (مانند سفارشات GrabFood، سفرهای حمل و نقل، پردازش پرداخت GrabPay، رویدادهای GrabAds) منتشر می شوند، رویدادها را مصرف می کند. با توجه به ماهیت جریان های Kafka، Trident کاملاً مستقل از سایر سرویس های بالادست است.
هر رویداد پردازش شده یک کلید رویداد منحصر به فرد را دریافت کرده و به مدت 24 ساعت در Redis نگهداری می شود. برای هر رویدادی که عملیاتی را تحریک می کند، کلید آن نیز در MySQL ذخیره می شود. قبل از ذخیره سازی رکوردها در Redis و MySQL، اطمینان حاصل می شود که هر رویداد تکراری فیلتر می شود. در کنار تضمین تحویل حداقل یک بار توسط Kafka، ما پردازش رویداد دقیقاً یک بار را دستیابی می کنیم.
مقیاس پذیری چالشی کلیدی برای Trident است. برای دستیابی به عملکرد بالا در حجم رویداد بزرگ، ما باید در سطح سرور و سطح داده ها مقیاس دهیم. نمودار ذهنی زیر خلاصه ای از استراتژی های ما را نشان می دهد.
مقیاس سرورها
منبع رویدادهای ما جریان های Kafka هستند. دو عامل اصلی وجود دارند که می تواند بر بار سیستم ما تأثیر بگذارد:
- تعداد رویدادهای تولید شده در جریان ها (بیشتر سفرها، سفارشات غذایی و غیره باعث افزایش رویدادها برای ما برای پردازش می شوند).تعداد کمپین های درحال اجرا طبیعت کمپین های درحال اجرا. کمپین هایی که عملیات جذب بیشتری را برای کاربران ایجاد می کنند، بار بالاتری روی سیستم ما ایجاد می کنند.
دو نوع رویکرد برای مقیاس بزرگی ظرفیت سرور وجود دارد:
- توزیع بار بین نمونه های سرور.کاهش بار (به عبارت دیگر، کاهش مقدار کار مورد نیاز برای پردازش هر رویداد).
توزیع بار
توزیع بار به نظر می رسد با توازن بار و مقیاس افقی خودکار براساس استفاده از CPU که تامین کنندگان ابری ارائه می دهند، ساده باشد. اما یک سرور اضافی تا زمانی که بتواند از یک پارتیشن Kafka مصرف کند بیکار نشسته است.
هر پارتیشن Kafka تنها توسط یک مصرف کننده در یک گروه مصرف کننده یکسان (در این مورد گروه سرورهای مقیاس خودکار ما) می تواند مصرف شود. بنابراین، هرگونه تغییر اندازه درونی یا بیرونی، مطابقت تنظیمات پارتیشن Kafka با تنظیمات سرورهای مقیاس خودکار را مورد نیاز دارد.
در زیر مثالی از یک مورد بد توزیع بار است:
و در زیر مثالی از توزیع بار خوب است که تنظیمات پارتیشن Kafka و تنظیمات سرورهای مقیاس خودکار را مطابقت داده است:
در هر نمونه سرور، ما همچنین سعی کردیم تا میزان طیف تشخیصی کارایی را افزایش دهیم و در عین حال نرخ استفاده از منابع را کنترل کنیم. هر مصرف کننده پارتیشن Kafka چندین goroutine برای پردازش رویدادها دارد و تعداد goroutine های فعال بر اساس حجم رویداد از پارتیشن و زمان روز (ساعات اوج و غیر اوج) به طور پویا تنظیم می شود.
کاهش بار
ممکن است بپرسید چگونه ما مقدار کار مورد نیاز برای هر رویداد را کاهش دادیم. ابتدا باید ببینیم کجا بیشترین زمان پردازش را صرف کردیم. بعد از انجام برخی از عملیات پروفایلی، متوجه شدیم که منطق ارزیابی قوانین مصرف کننده زمان اصلی را مصرف می کند.
ارزیابی قوانین چیست؟
بازیابی کنید که Trident باید هزاران کمپین را روزانه اجرا کند. هر کمپین دارای مجموعه ای از قوانین است. هنگامی که Trident یک رویداد دریافت می کند، باید تمام قوانین کمپین ها را بررسی کند تا ببیند آیا همان رویدادی وجود دارد یا خیر. این فرایند بررسی را فرآیندارزیابی قوانین می نامند.
به صورت دقیق تر، یک قانون شامل یک یا چند شرط است که با عملگرهای منطقی AND/OR ترکیب شده است. یک شرط شامل یک عملگر با یک طرف چپ (LHS) و یک طرف راست (RHS) است. طرف چپ نام یک متغیر است و طرف راست یک مقدار است. یک قانون نمونه در JSON:
کشور سنگاپور است و نوع تاکسی همانند JustGrab یا GrabCar است. { "operator": "and", "conditions": [ { "operator": "eq", "lhs": "var.country", "rhs": "sg" }, { "operator": "or", "conditions":