خلاصه: سیستمهای یادگیری ماشین بلادرنگ، نهتنها به مدلهای کارآمد نیاز دارند، بلکه به زیرساختهای قویای نیز نیازمندند که قادر به ارائه ویژگی با تأخیر کم تحت شرایط بار دینامیکی باشند.
در این پست، ما لایه محاسباتی درخواستی ولگا را که یک مؤلفه اصلی برای محاسبه ویژگی در زمان درخواست است، ارزیابی میکنیم. این لایه بر روی Kubernetes (EKS) مستقر شده و با Ray هماهنگ شده است. برای شبیهسازی الگوهای بار دنیای واقعی، از Locust به عنوان چارچوب تست بار و از Redis به عنوان لایه ذخیرهسازی میانی بین اجزای جریان و ارائه استفاده میکنیم.
ما عملکرد سیستم را ارزیابی میکنیم، ویژگیهای تأخیر را تجزیه و تحلیل میکنیم و مقیاسپذیری افقی را در پروفایلهای بار مختلف ارزیابی میکنیم و بر چگونگی تأثیر انتخابهای معماری بر استحکام و کارایی تمرکز میکنیم.
فهرست مطالب:
- پیشینه
- راهاندازی تستها
- نتایج و تحلیل
- نتیجهگیری
پیشینه
ولگا یک سیستم پردازش داده است که برای خطوط لوله مدرن هوش مصنوعی/یادگیری ماشین ساخته شده است و بر مهندسی ویژگی بلادرنگ تمرکز دارد (اطلاعات بیشتر اینجا). لایه محاسباتی درخواستی یکی از دو مؤلفه اصلی ولگا است (در کنار موتور جریان آن) که مسئولیت محاسبه در زمان درخواست را بر عهده دارد—یعنی ارائه ویژگی و محاسبه ویژگی درخواستی.
در هسته خود، لایه محاسباتی درخواستی یک سرویس بدون حالت است که توسط Ray Actors پشتیبانی میشود و هر کارگر یک سرور Starlette را اجرا میکند که منطق تعریفشده توسط کاربر را بر روی دادههای تولید شده توسط موتور جریان اجرا میکند (یا دادههای از پیش محاسبه شده را ارائه میکند). سیستم سرتاسر پشت یک لود بالانسر خارجی قرار دارد و از یک لایه ذخیرهسازی قابل اتصال به عنوان واسطه بین موتور جریان و کارگران درخواستی استفاده میکند.
هدف این پست ارزیابی استحکام معماری در سناریوهای دنیای واقعی، ارزیابی عملکرد لایه درخواستی تحت بار و نشان دادن مقیاسپذیری افقی سیستم است.
راهاندازی تستها
ما تستهای بار را بر روی یک خوشه Amazon EKS با استفاده از نمونههای t2.medium (2 vCPU، 4 گیگابایت رم) اجرا کردیم که هم استقرار Locust و هم خوشه Ray در حال اجرای ولگا را میزبانی میکرد. هر پاد Ray به یک گره EKS واحد نگاشت شد تا از جداسازی منابع اطمینان حاصل شود.
لایه درخواستی ولگا در پشت یک AWS Application Load Balancer مستقر شد، که به عنوان هدف اصلی برای کارگران Locust عمل میکند و درخواستها را به گرههای EKS میزبانی پادهای ولگا هدایت میکند (جایی که سیستم عامل سپس بار را بین کارگران درون همان گره/پاد توزیع میکند).
برای کد راهاندازی همه اینها، مخزن volga-ops را بررسی کنید.
اندازهبندی منابع
از طریق آزمایش، ما تعیین کردیم که:
- یک کارگر درخواستی میتواند تا 1000 RPS را مدیریت کند، با این فرض که توابع تعریفشده توسط کاربر (UDFها) عملیات مسدود کننده CPU را معرفی نکنند.
- یک کارگر Locust میتواند تا 1000 RPS تولید کند بدون اینکه یک گره را بیش از حد بارگذاری کند.
از آنجایی که کارگران ولگا فرآیندهای پایتون سبکوزن هستند (تکرشتهای، محدود به GIL)، ما یک نگاشت مستقیم 1 کارگر = 1 CPU را هنگام تخمین استفاده از منابع فرض میکنیم.
پیکربندی ذخیرهسازی
ما Redis را به عنوان لایه ذخیرهسازی بین موتور جریان و لایه درخواستی به دلیل سادگی و عملکرد بالا انتخاب کردیم.
اگرچه Redis را میتوان با تکرار master-replica پیکربندی کرد، اما به دلیل عدم وجود تضمینهای سازگاری قوی، محیطهای تولیدی باید سیستمهای ذخیرهسازی مانند ScyllaDB، Cassandra یا DynamoDB را برای دوام و سازگاری بهتر در نظر بگیرند.
در ارزیابیهای ما:
- یک پاد Redis واحد بدون تکرار یا شاردینگ مستقر شد و سادگی و جداسازی عملکرد محاسباتی را در اولویت قرار داد.
- موتور جریان در طول آزمایشها غیرفعال بود و ذخیرهسازی یک بار در زمان راهاندازی پر میشد. این رویکرد عملکرد خود ولگا را جدا میکند، اما میتواند در مقایسه با نوشتنهای دینامیکی دنیای واقعی، تأثیر جزئی بر رفتار ذخیرهسازی بگذارد.
ویژگیها برای محاسبه/ارائه
هر ارزیابی یک خط لوله ویژگی بلادرنگ ساده را شبیهسازی کرد که شامل:
test_feature: یک ویژگی خط لوله (جریان)، که از طریق نوشتن دورهای دادههای ساختگی پر میشود.simple_feature: یک ویژگی در زمان درخواست که بهtest_featureوابسته است و یک تبدیل اساسی (ضرب) را اعمال میکند.
# شبیهسازی ویژگی خط لوله جریان
@source(TestEntity)
def test_feature() -> Connector:
return MockOnlineConnector.with_periodic_items(
items=[...], # دادههای نمونه
period_s=0
)
# شبیهسازی تبدیل خطی ساده در زمان درخواست (ضرب) بر اساس دادههای تولید شده توسط 'test_feature'
@on_demand(dependencies=['test_feature'])
def simple_feature(
dep: TestEntity,
multiplier: float = 1.0
) -> TestEntity:
return TestEntity(
id=dep.id,
value=dep.value * multiplier,
timestamp=datetime.datetime.now()
)
نتایج و تحلیل
در طول هر تست بار، ما اندازهگیری کردیم:
- RPS کل (تولید شده توسط Locust و مدیریت شده توسط ولگا)
- تأخیر داخلی لایه درخواستی
- تأخیر خواندن ذخیرهسازی
- تأخیر درخواست سرتاسر (از دیدگاههای ولگا و Locust)
ما همچنین از طریق AWS Container Insights، میزان استفاده از CPU کانتینر را برای تأیید حداکثر استفاده از گره نظارت کردیم.
هر تست از یک افزایش بار مرحلهای پیروی کرد، به طوری که RPS به تدریج هر ~20 ثانیه در طول یک اجرای 3 دقیقهای افزایش مییافت تا به حداکثر پیکربندیشده برسد. (مکانیسم فشار برگشتی داخلی Locust در صورت تجاوز تأخیر از آستانههای قابل قبول، رشد RPS را متوقف میکند.)
تست حداکثر RPS
در بزرگترین پیکربندی (80 کارگر)، ما به این موارد دست یافتیم:
- توان عملیاتی اوج 30,000 RPS
- تأخیر سرتاسر p95 50 میلیثانیه
مقیاسپذیری
ما تستهایی را با 4، 10، 20، 40، 60 و 80 کارگر انجام دادیم و RPS پایدار و معیارهای تأخیر مربوطه را ردیابی کردیم.
نتایج نشان داد:
- مقیاسبندی خطی RPS با تعداد کارگران.
- تأخیرهای پردازش پایدار در مراحل مقیاسبندی.
- عملکرد ذخیرهسازی به عنوان گلوگاه اصلی برای تأخیر باقی ماند و مقیاسپذیری و کارایی داخلی ولگا را دوباره تأیید کرد.
نتیجهگیری
لایه محاسباتی درخواستی ولگا یک مؤلفه حیاتی برای ساخت خطوط لوله مهندسی ویژگی هوش مصنوعی/یادگیری ماشین بلادرنگ ارائه میدهد و به طور قابل توجهی نیاز به کد چسب سفارشی، مدلهای داده اختصاصی و خلاصهسازی API دستی را کاهش میدهد.
ارزیابیهای ما نشان میدهد که لایه درخواستی:
- با تعداد کارگران به صورت افقی مقیاسپذیر است (با فرض اینکه پشتیبان ذخیرهسازی به طور مناسب مقیاسپذیر باشد).
- تأخیرهای درخواست سرتاسر زیر 50 میلیثانیه p95 و میانگین زیر 10 میلیثانیه را حفظ میکند.
- حداقل سربار محاسباتی را اضافه میکند، به طوری که دسترسی به ذخیرهسازی محرک اصلی تأخیر است.
لایه محاسباتی درخواستی ولگا مقیاسپذیری افقی قوی و قابلیتهای ارائه بلادرنگ کارآمد را نشان میدهد. با پشتیبان ذخیرهسازی مناسب، خطوط لوله ویژگی قابل اعتماد با تأخیر کم را در مقیاس بزرگ امکانپذیر میکند.
برای کسب اطلاعات بیشتر یا مشارکت، به مخزن GitHub ولگا مراجعه کنید. با تشکر از خواندن!