معماری مجدد برنامه ها برای مقیاس. نحوه استفاده Coinbase از Relay و GraphQL… | توسط Coinbase | مه، 2022
چگونه Coinbase از Relay و GraphQL برای فعال کردن hypergrowth استفاده می کند توسط کریس اریکسون و ترنس بزمن کمی بیش از یک سال پیش، کوین بیس انتقال اپلیکیشن موبایل اولیه ما به React Native را تکمیل کرد. در طول مهاجرت، متوجه شدیم که رویکرد موجود ما به دادهها (نقاط پایانی REST و یک کتابخانه
چگونه Coinbase از Relay و GraphQL برای فعال کردن hypergrowth استفاده می کند
توسط کریس اریکسون و ترنس بزمن
کمی بیش از یک سال پیش، کوین بیس انتقال اپلیکیشن موبایل اولیه ما به React Native را تکمیل کرد. در طول مهاجرت، متوجه شدیم که رویکرد موجود ما به دادهها (نقاط پایانی REST و یک کتابخانه واکشی دادههای REST ساختهشده) با رشدی که بهعنوان یک شرکت تجربه میکردیم، مطابقت ندارد.
“Hypergrowth” واژهای است که بیش از حد استفاده میشود، بنابراین بیایید منظورمان را در این زمینه روشن کنیم. در 12 ماه پس از مهاجرت به برنامه React Native، ترافیک API ما 10 برابر افزایش یافت و تعداد دارایی های پشتیبانی شده را 5 برابر افزایش دادیم. در همان بازه زمانی، تعداد مشارکت کنندگان ماهانه در برنامه های اصلی ما سه برابر شد و به 300 نفر رسید. با این افزودهها، ویژگیها و آزمایشهای جدید افزایش یافت، و ما شاهد کاهش سرعت این رشد به این زودیها نیستیم (تنها امسال به دنبال استخدام 2000 نفر دیگر در بخش محصولات، مهندسی و طراحی هستیم).
برای مدیریت این رشد، تصمیم گرفتیم برنامه های خود را به GraphQL و Relay منتقل کنیم. این تغییر ما را قادر می سازد تا برخی از بزرگترین چالش هایی را که در رابطه با تکامل API، صفحه بندی تو در تو و معماری برنامه ها با آن مواجه بودیم، به طور کلی حل کنیم.
GraphQL در ابتدا به عنوان رویکردی برای کمک به تکامل API و تجمیع درخواست ها پیشنهاد شد.
قبلاً، به منظور محدود کردن درخواستهای همزمان، نقاط پایانی مختلفی برای جمعآوری دادهها برای یک نمای خاص (مثلاً داشبورد) ایجاد میکردیم. با این حال، با تغییر ویژگیها، این نقاط پایانی به رشد خود ادامه دادند و فیلدهایی که دیگر استفاده نمیشدند را نمیتوان با خیال راحت حذف کرد – زیرا غیرممکن بود که بفهمیم آیا یک مشتری قدیمی هنوز از آنها استفاده میکند یا خیر.
در حالت پایانی آن، ما توسط یک سیستم ناکارآمد محدود شدیم، همانطور که توسط چند حکایت نشان داده شده است:
- یک نقطه پایانی داشبورد وب موجود برای صفحه اصلی جدید تغییر کاربری داده شد. این نقطه پایانی مسئول 14٪ از کل بار پشتیبان ما بود. متأسفانه داشبورد جدید فقط از این نقطه پایانی برای یک فیلد بولی واحد استفاده می کرد.
- نقطه پایانی کاربر ما آنقدر متورم شده بود که تقریباً 8 مگابایت پاسخ داشت – اما هیچ مشتری واقعاً به همه این داده ها نیاز نداشت.
- اپلیکیشن موبایل هنگام راهاندازی باید ۲۵ تماس API موازی برقرار میکرد، اما در آن زمان React Native ما را به ۴ تماس موازی محدود میکرد که باعث ایجاد یک آبشار غیرقابل کاهش شد.
هر یک از اینها را میتوان به صورت مجزا و با استفاده از تکنیکهای مختلف (فرایند بهتر، نسخهسازی API و غیره) حل کرد، که اجرای آنها در حالی که شرکت با چنین سرعتی در حال رشد است، چالش برانگیز است.
خوشبختانه، این دقیقاً همان چیزی است که GraphQL برای آن ایجاد شده است. با GraphQL، مشتری میتواند یک درخواست تکی واکشی کند فقط داده هایی که برای نمایی که نشان می دهد نیاز دارد. (در واقع با Relay می توانیم نیاز آنها فقط دادههای مورد نیاز خود را درخواست کنید — بعداً در مورد آن بیشتر توضیح خواهیم داد.) این منجر به درخواستهای سریعتر، کاهش ترافیک شبکه، بار کمتر در سرویسهای باطن ما و به طور کلی برنامه سریعتر میشود.
زمانی که Coinbase از 5 دارایی پشتیبانی میکرد، برنامه میتوانست چند درخواست داشته باشد: یکی برای دریافت داراییها (5) و دیگری برای دریافت آدرس کیف پول (تا 10) برای آن داراییها و پیوند آنها بر روی مشتری. با این حال، زمانی که یک مجموعه داده به اندازه کافی بزرگ می شود که نیاز به صفحه بندی داشته باشد، این مدل به خوبی کار نمی کند. یا اندازه صفحه غیرقابل قبول بزرگی دارید (که عملکرد API شما را کاهش می دهد)، یا با API های دست و پا گیر و درخواست های آبشاری روبرو می شوید.
اگر آشنا نیستید، یک آبشار در این زمینه زمانی اتفاق میافتد که مشتری ابتدا باید صفحهای از داراییها را بخواهد (10 دارایی اول پشتیبانی شده را به من بدهید)، و سپس باید کیف پولها را بخواهد. برای آن دارایی ها (کیف پول هایی برای «BTC»، «ETH»، «LTC»، «DOGE»، «SOL»، و … به من بدهید). از آنجایی که درخواست دوم به درخواست اول وابسته است، یک آبشار درخواست ایجاد می کند. هنگامی که این درخواست های وابسته از مشتری انجام می شود، تأخیر ترکیبی آنها می تواند به عملکرد وحشتناکی منجر شود.
این یکی دیگر از مشکلاتی است که GraphQL حل میکند: به دادههای مرتبط اجازه میدهد تا در درخواست تودرتو شوند و این آبشار را به سرور پشتیبان منتقل کند که میتواند این درخواستها را با تأخیر بسیار کمتری ترکیب کند.
ما Relay را به عنوان کتابخانه مشتری GraphQL خود انتخاب کردیم که تعدادی از مزایای غیرمنتظره را ارائه کرده است. مهاجرت از این جهت چالش برانگیز بوده است که تکامل کد ما برای پیروی از روشهای اصطلاحی Relay بیش از حد انتظار طول کشیده است. با این حال، مزایای رله (همسویی، جداسازی، حذف آبشارهای مشتری، عملکرد، و چکشخواری) تأثیر مثبتتری نسبت به آنچه که قبلاً پیشبینی میکردیم، داشته است.
به زبان ساده، Relay در میان کتابخانه های سرویس گیرنده GraphQL منحصر به فرد است که چگونه به یک برنامه اجازه می دهد تا برای مشارکت کنندگان بیشتری مقیاس شود و در عین حال انعطاف پذیر و کارآمد باقی بماند.
این مزایا از الگوی Relay در استفاده از قطعات برای همسویی وابستگیهای داده در اجزایی که دادهها را ارائه میکنند، ناشی میشود. اگر یک جزء به داده نیاز دارد، باید از طریق نوع خاصی از پروپوزال منتقل شود. این پایهها غیرشفاف هستند (مولفه اصلی فقط میداند که باید یک {ChildComponentName}Fragment را بدون دانستن محتوای آن ارسال کند)، که جفت شدن بین مؤلفهها را محدود میکند. قطعات همچنین تضمین می کنند که یک جزء فقط فیلدهایی را می خواند که صریحاً درخواست کرده است، و جفت شدن با داده های اساسی را کاهش می دهد. این امر چکش خواری، ایمنی و عملکرد را افزایش می دهد. کامپایلر Relay به نوبه خود قادر است قطعات را در یک پرس و جو جمع کند، که از آبشار مشتری و درخواست چندین بار داده های مشابه جلوگیری می کند.
همه اینها کاملاً انتزاعی است، بنابراین یک مؤلفه ساده React را در نظر بگیرید که داده ها را از یک REST API واکشی می کند و یک لیست ارائه می دهد (این شبیه به چیزی است که با استفاده از React Query، SWR یا حتی Apollo می سازید):
چند نکته:
- مولفه AssetList قرار است باعث ایجاد یک درخواست شبکه شود، اما این برای مؤلفه ای که آن را ارائه می دهد، غیر شفاف است. این امر باعث می شود که بارگذاری اولیه این داده ها با استفاده از تجزیه و تحلیل استاتیک تقریبا غیرممکن باشد.
- به همین ترتیب، AssetPriceAndBalance باعث تماس شبکه دیگری میشود، اما همچنین باعث آبشار میشود، زیرا تا زمانی که مؤلفههای والد واکشی دادههای آن و ارائه موارد فهرست را به پایان نرسانند، درخواست شروع نمیشود. (تیم React وقتی درباره «واکشی روی رندر» بحث میکند، درباره این موضوع صحبت میکند)
- AssetList و AssetListItem کاملاً جفت شده اند – AssetList باید یک شیء دارایی را ارائه دهد که شامل تمام فیلدهای مورد نیاز درخت فرعی باشد. همچنین، AssetHeader نیاز به انتقال کل دارایی دارد، در حالی که فقط از یک فیلد استفاده می کند.
- هر زمان که دادههای مربوط به یک دارایی تغییر کند، کل فهرست دوباره ارائه میشود.
در حالی که این یک مثال بیاهمیت است، میتوان تصور کرد که چگونه چند مولفه مانند این بر روی یک صفحه نمایش ممکن است برای ایجاد تعداد زیادی آبشار دادههای بارگذاری کننده اجزا ایجاد کنند. برخی از رویکردها سعی میکنند این مشکل را با انتقال همه تماسهای واکشی داده به بالای درخت مؤلفه حل کنند (مثلاً مرتبط کردن آنها با مسیر). با این حال، این فرآیند دستی و مستعد خطا است و وابستگیهای دادهها تکراری هستند و احتمالاً از همگامسازی خارج میشوند. همچنین مشکلات کوپلینگ و عملکرد را حل نمی کند.
رله این نوع مسائل را با طراحی حل می کند.
بیایید به همان چیزی که با Relay نوشته شده است نگاه کنیم:
مشاهدات قبلی ما چگونه است؟
- AssetList دیگر وابستگی داده های پنهانی ندارد: به وضوح این واقعیت را آشکار می کند که از طریق ابزارهای خود به داده نیاز دارد.
- از آنجایی که کامپوننت در مورد نیاز خود به داده شفاف است، همه داده های مورد نیاز برای یک صفحه را می توان با هم گروه بندی کرد و قبل از شروع رندر درخواست کرد. این کار آبشارهای مشتری را بدون نیاز به مهندسین در مورد آنها از بین می برد.
- در حالی که نیاز است که داده ها از طریق درخت به عنوان پایه منتقل شوند، Relay اجازه می دهد تا این کار را به روشی انجام دهد. نه جفت اضافی ایجاد کنید (زیرا فیلدها هستند فقط قابل دسترسی توسط مؤلفه فرزند). AssetList می داند که باید AssetListItem را به AssetListItemFragmentRef ارسال کند، بدون اینکه بداند چی که شامل (این مورد را با بارگیری داده مبتنی بر مسیر مقایسه کنید، جایی که داده های مورد نیاز روی اجزا و مسیر تکرار می شوند و باید هماهنگ باشند.)
- این باعث میشود کد ما انعطافپذیرتر و آسانتر تکامل یابد – یک آیتم فهرست را میتوان به صورت مجزا و بدون دست زدن به هیچ بخش دیگری از برنامه تغییر داد. اگر به فیلدهای جدید نیاز دارد، آنها را به قطعه خود اضافه می کند. وقتی دیگر نیازی به فیلد ندارد، بدون نگرانی از اینکه قسمت دیگری از برنامه را خراب می کند، آن را حذف می کند.. همه اینها از طریق چک کردن نوع و قوانین پرز اعمال می شود. این همچنین مشکل تکامل API را که در ابتدای این پست ذکر شد حل میکند: مشتریان درخواست داده را زمانی که دیگر استفاده نمیشوند متوقف میکنند و در نهایت میتوان فیلدها را از طرح حذف کرد.
- از آنجایی که وابستگیهای داده به صورت محلی اعلام شدهاند، React و Relay میتوانند رندرینگ را بهینه کنند: اگر قیمت یک دارایی تغییر کند، فقط مؤلفههایی که واقعاً آن قیمت را نشان میدهند باید دوباره ارائه شوند.
در حالی که در یک برنامه بی اهمیت، این مزایا ممکن است معامله بزرگی نباشند، دشوار است که تأثیر آنها را روی یک پایگاه بزرگ کد با صدها مشارکت کننده هفتگی اغراق کنیم. شاید بهتر باشد این عبارت از سخنرانی اخیر ReactConf Relay دریافت شود: Relay به شما امکان می دهد “به صورت محلی فکر کنید و در سطح جهانی بهینه سازی کنید.”
مهاجرت برنامه های ما به GraphQL و Relay فقط شروع است. ما کارهای زیادی برای انجام دادن داریم تا به گسترش GraphQL در Coinbase ادامه دهیم. در اینجا چند مورد در نقشه راه وجود دارد:
API GraphQL Coinbase به بسیاری از خدمات بالادستی وابسته است – که برخی از آنها کندتر از سایرین هستند. بهطور پیشفرض، GraphQL تا زمانی که همه دادهها آماده نشود، پاسخ خود را ارسال نمیکند، به این معنی که یک پرسوجو به سرعت کندترین سرویس بالادستی خواهد بود. این می تواند برای عملکرد برنامه مضر باشد: یک عنصر UI با اولویت پایین که دارای یک backend کند است می تواند عملکرد کل صفحه را کاهش دهد.
برای حل این مشکل، جامعه GraphQL روی یک دستورالعمل جدید به نام @defer استانداردسازی کرده است. این اجازه می دهد تا بخش هایی از یک پرس و جو به عنوان “اولویت کم” علامت گذاری شوند. سرور GraphQL به محض آماده شدن تمام داده های مورد نیاز، اولین تکه را ارسال می کند و قسمت های معوق را در صورت موجود بودن به پایین پخش می کند.
برنامههای کوینبیس معمولاً دادههای زیادی دارند که به سرعت در حال تغییر هستند (مثلاً قیمتها و موجودی ارزهای دیجیتال). به طور سنتی، ما از چیزهایی مانند Pusher یا سایر راه حل های اختصاصی برای به روز نگه داشتن داده ها استفاده می کردیم. با GraphQL، میتوانیم از اشتراکها برای ارائه بهروزرسانیهای زنده استفاده کنیم. با این حال، ما احساس میکنیم که اشتراکها ابزار ایدهآلی برای نیازهای ما نیستند، و قصد داریم استفاده از Live Queries را بررسی کنیم (در این مورد در یک پست وبلاگ در ادامه مسیر).
کوین بیس به افزایش آزادی اقتصادی جهانی اختصاص دارد. برای این منظور، ما در تلاش هستیم تا محصولات خود را بدون توجه به جایی که زندگی میکنید، از جمله مناطقی با اتصال داده کند، کارآمد کنیم. برای کمک به تحقق این امر، میخواهیم یک لایه حافظه پنهان سراسری، ایمن، قابل اعتماد و ثابت بسازیم تا کل زمان رفت و برگشت را برای همه درخواستها کاهش دهیم.
تیم Relay کار فوقالعادهای انجام داده است و ما بهطور باورنکردنی از کار اضافی آنها برای استفاده جهان از آموختههای آنها در Meta سپاسگزاریم. در ادامه، مایلیم این رابطه یک طرفه را به یک رابطه دو طرفه تبدیل کنیم. از سه ماهه دوم، Coinbase منابعی را برای کمک به کار بر روی Relay OSS وام می دهد. ما بسیار هیجان زده هستیم که به جلو بردن رله کمک کنیم!
آیا علاقه مند به حل مشکلات بزرگ در مقیاسی رو به رشد هستید؟ بیا به ما ملحق شو!
آموزش مجازی مدیریت عالی حرفه ای کسب و کار Post DBA + مدرک معتبر قابل ترجمه رسمی با مهر دادگستری و وزارت امور خارجه | آموزش مجازی مدیریت عالی و حرفه ای کسب و کار DBA + مدرک معتبر قابل ترجمه رسمی با مهر دادگستری و وزارت امور خارجه | آموزش مجازی مدیریت کسب و کار MBA + مدرک معتبر قابل ترجمه رسمی با مهر دادگستری و وزارت امور خارجه |
مدیریت حرفه ای کافی شاپ | حقوقدان خبره | سرآشپز حرفه ای |
آموزش مجازی تعمیرات موبایل | آموزش مجازی ICDL مهارت های رایانه کار درجه یک و دو | آموزش مجازی کارشناس معاملات املاک_ مشاور املاک |
برچسب ها :Coinbase ، GraphQL ، Relay ، از ، استفاده ، برای ، برنامه ، توسط ، مجدد ، معماری ، مقیاس ، مه ، نحوه ، ها
- نظرات ارسال شده توسط شما، پس از تایید توسط مدیران سایت منتشر خواهد شد.
- نظراتی که حاوی تهمت یا افترا باشد منتشر نخواهد شد.
- نظراتی که به غیر از زبان فارسی یا غیر مرتبط با خبر باشد منتشر نخواهد شد.
ارسال نظر شما
مجموع نظرات : 0 در انتظار بررسی : 0 انتشار یافته : ۰