متادیتای فشرده ویدیو با Protobuf
ورکر دریافت (ingest worker) ما هر دو ساعت هزاران ویدیو ترند را استخراج میکند. ما این دادهها را به سه سرویس میفرستیم: یک سرویس رتبهبندی (ranking service)، یک سرویس گرمکننده کش (cache warmer) و یک وظیفه تحلیل داده (analytics job).
برای مدتی طولانی، از JSON برای انتقال این دادهها استفاده میکردیم. این روش تا زمانی که کار میکرد، خوب بود، اما بالاخره با مشکل مواجه شد.
هر رکورد ویدیو در قالب JSON حدود ۲.۴ کیلوبایت بود. انتقال ۴۰,۰۰۰ رکورد به سه سرویس مختلف به معنای انتقال ۲۸۰ مگابایت متن تکراری در هر دو ساعت بود. این موضوع باعث هدر رفت پهنای باند و کند شدن ورکرهای PHP ما میشد.
ما به Protocol Buffers (Protobuf) مهاجرت کردیم. در ادامه توضیح میدهیم که چرا این کار را انجام دادیم و چگونه سیستم ما را تغییر داد.
سه مشکل اصلی JSON:
- حجم: JSON نام فیلدها را در هر رکورد تکرار میکند. نام فیلدی مانند "viral_score_24h" تنها برای انتقال یک عدد ۸ بایتی، ۱۵ بایت فضا اشغال میکند.
- هزینه تجزیه (Parse Cost): PHP باید کل بلوک JSON را تجزیه کند، حتی اگر یک سرویس فقط به دو فیلد نیاز داشته باشد.
- تغییر ناگهانی طرحواره (Schema Drift): JSON فاقد قرارداد (contract) است. اگر یک سرویس فیلدی را تغییر دهد، سایر سرویسها در زمان اجرا (runtime) بدون هیچ هشداری دچار خطا میشوند.
چگونه Protobuf این مشکل را حل کرد:
Protobuf به جای نام، از شماره فیلدها استفاده میکند. این پروتکل از یک فایل .proto به عنوان تنها منبع حقیقت (single source of truth) استفاده میکند. این فایل کد لازم برای PHP، Python و Go را تولید میکند. اگر طرحواره (schema) را تغییر دهید، کد در مرحله کامپایل با خطا مواجه میشود. این کار باگهای زمان اجرا را به خطاهای زمان کامپایل تبدیل میکند.
نتایج:
ما این تغییرات را طی یک هفته اندازهگیری کردیم:
- حجم داده (Payload size): از ۲.۴ کیلوبایت به ۷۲۰ بایت کاهش یافت (۷۰٪ کاهش).
- زمان کدگذاری (Encode) در PHP: از ۳۱۰ میلیثانیه به ۹۵ میلیثانیه کاهش یافت.
- زمان رمزگشایی (Decode) در Go: از ۱۴۰ میلیثانیه به ۳۸ میلیثانیه کاهش یافت.
- پهنای باند: از ۲۸۰ مگابایت به ۸۴ مگابایت در هر چرخه کاهش یافت.
چه زمانی از Protobuf استفاده کنیم:
از آن برای همه چیز استفاده نکنید. اگر حجم دادههای شما کم است یا نیاز دارید که انسانها بتوانند آنها را به راحتی بخوانند، از همان JSON استفاده کنید. از Protobuf برای ترافیک داخلی با حجم بالا، جایی که سرعت و قراردادهای سختگیرانه بیشترین اهمیت را دارند، استفاده کنید.
APIهای عمومی ما همچنان از JSON استفاده میکنند. سرویسهای داخلی ما از Protobuf استفاده میکنند.