در این پست میخوام فهم خودمو از API Gateway با شما درمیان بذارم. اگه نظری داشتید یا مشکلی دیدید ، لطفا در نظرات برامون بنویسید.
انتظار دارم تو این پست بتونم به سوالات زیر پاسخ بدم
- معنی API Gateway رو چی هست؟
- برای حل چه مشکلی ارائه شد؟
- چه مزایا و معایبی با خودش به همراه داره ؟
- چه از ابزار های متن باز (open source) و معروفی تو این زمینه وجود داره؟
در ایران کدوم شرکت ها در این زمینه خدماتی ارائه می دن؟
خوب بیاید شروع کنیم :
همانطور که میدونید API مخفف Application Programming Interface (یا به فارسی رابط برنامه نویسی اپلیکیشن ) است. وژاه دوم gateway به معنای دروازه است .در گذشته در اطراف بسیاری از شهر ها و قلعه ها دیوار می کشیدند تا افراد برای ورود از دروازه عبور کنند. نگهبانان در کنار دروازه می ایستادند و با کمک این تکنیک ورود و خروج رو کنترل میکردند و امنیت شهرها و قلعه ها تامین میشد.
حالا بیاید با یه مثال نقش API Gateway در معماری میکروسرویس ببینیم
اول در چند خط معماری میکروسرویس را مرور کنیم بعد ببینیم API Gateway چه چیزی به آن اضافه کرده
برای نمونه یک سایت فروشگاهی را در نظر بگیرید . در چنین سایتی احتمالا سرویس های مختلفی وجود دارد مثلا، افراد میتوانند ثبت نام کنند، کالا ها را مشاهده کنند ، کالا ها را نسبت به هم مقایسه کنند ، محصول را سفارش بدهند و پرداخت انجام دهند.
در معماری Monolithic همه این سرویس ها در یک برنامه بصورت متمرکز در یک هسته مرکزی پیاده سازی میشود گرچه ممکن است این هسته بخش بندی شده (ماژولار) باشد اما همه در یک پلتفرم واحد در کنار هم هستند و جداسازی آنها بسیار سخت یا غیرممکن است.
این پیاده سازی چند مشکل جدی داشت :
- سرویس ها و کامپوننتها را به سادگی نمیتوان با یک معماری جدیدتر و بهینهتر جایگزین کرد چرا که کل معماری نرمافزار را باید تغییر داد.
- یک خطا در یکی از سرویس، به احتمال زیاد کل برنامه را مختل خواهد کرد
- کل اعضا مجبور هستند با زبان برنامه نویسی و تکنولوژی های مشترک استفاده کنند
موارد بالا نگهداری و ارتقا برنامه ها را بسیار سخت میکرد معماری میکروسرویس برای حل این مشکلات ارائه شد.
میکروسرویس یک روش به منظور تقسیمبندی کردن یک اپلیکیشن (نرمافزار) به بخشها یا سرویسهای کوچک، مستقل از یکدیگر است. این سرویس ها به منظور مدیریت کردن یک وظیفه خاص طراحی میشوند مثلا میکروسرویس پرداخت، ثبت سفارش ، مشاهده کالا و ...
این سرویس ها عموما به وسیله API از نوع Rest یا SOAP با یکدیگر ارتباط برقرار میکنند.
به کمک این معماری سرویس های مختلف از هم جدا شدند میتوانند بصورت مستقل توسعه پیدا کنند. در واقع اگر ما وظیفه پیاده سازی یک سرویس بر عهده داشته باشیم دیگر به جزییات پیاده سازی بقیه سرویس ها اهمیت نمیدهیم . فقط در قالب مشخص شده سرویس میدهیم و با دیگر سرویس اربتاط خواهیم داشت.
این معماری تقریبا مشکلاتی که در بالا مطرح کردیم برطرف میکند اما یک مشکل جدید بوجود می آید . فرض کنید شرکت ما یک اپلیکیشن برای موبایل های اندروید و یکی برای ios یک وب دارد طبیعتا هر یک از نرم افزار ها بخواهد به میکروسرویس ها درخواست ارسال کند و داده دریافت کند. باتوجه به اینکه هر یک از میکروسرویس ها استاندارد متفاوتی دارند کار برای پیاده سازی اپلیکیشن و وب بسیار سخت خواهد شد و به شدت به ماکروسرویس ها وابسته خواهند شد و این باز باعث سخت شدن توسعه نرم افزار می شود
بیایید تصور کنیم که در حال توسعه یک کلاینت موبایل برای یک برنامه خرید هستید. این احتمال وجود دارد که شما نیاز به پیاده سازی صفحه جزئیات محصول داشته باشید که اطلاعات مربوط به هر محصول را نمایش می دهد.
به عنوان مثال، نمودار زیر نشان می دهد که هنگام پیمایش جزئیات محصول در برنامه تلفن همراه اندروید آمازون، چه چیزی را خواهید دید.
حتی اگر این یک برنامه کاربردی گوشی هوشمند است، صفحه جزئیات محصول اطلاعات زیادی را نشان می دهد. به عنوان مثال، نه تنها اطلاعات اولیه محصول (مانند نام، توضیحات و قیمت) وجود دارد، بلکه این صفحه همچنین نشان می دهد:
هنگام استفاده از معماری برنامه یکپارچه، یک کلاینت تلفن همراه با برقراری یک تماس REST ( ) با برنامه، این داده ها را بازیابی می کند. یک متعادل کننده بار درخواست را به یکی از N نمونه برنامه یکسان هدایت می کند. سپس برنامه از جداول پایگاه داده مختلف پرس و جو می کند و پاسخ را به مشتری برمی گرداند.GET
api.company.com/productdetails/productId
در مقابل، هنگام استفاده از معماری میکروسرویس، داده های نمایش داده شده در صفحه جزئیات محصول متعلق به چندین میکروسرویس است. در اینجا برخی از میکروسرویسهای بالقوه که دادههای خود را در صفحه جزئیات محصول نمونه نمایش میدهند، آمده است:
ما باید تصمیم بگیریم که مشتری موبایل چگونه به این خدمات دسترسی دارد. بیایید به گزینه ها نگاه کنیم.
در تئوری، یک مشتری میتواند مستقیماً به هر یک از میکروسرویسها درخواست بدهد. هر میکروسرویس یک نقطه پایانی عمومی ( https:// serviceName .api.company.name ) خواهد داشت. این URL به بار متعادل کننده میکروسرویس نگاشت می شود، که درخواست ها را در نمونه های موجود توزیع می کند. برای بازیابی جزئیات محصول، مشتری تلفن همراه برای هر یک از خدمات ذکر شده در بالا درخواست می دهد.
متأسفانه، این گزینه چالش ها و محدودیت هایی دارد. یکی از مشکلات عدم تطابق بین نیازهای مشتری و API های ریز دانه ای است که توسط هر یک از میکروسرویس ها در معرض دید قرار می گیرند. مشتری در این مثال باید هفت درخواست جداگانه ارائه دهد. در برنامههای پیچیدهتر، ممکن است نیاز به ساخت خیلی بیشتر باشد. به عنوان مثال، آمازون توضیح می دهد که چگونه صدها سرویس در ارائه صفحه محصول خود نقش دارند. در حالی که یک کلاینت می تواند این تعداد درخواست را از طریق یک شبکه LAN انجام دهد، احتمالاً از طریق اینترنت عمومی بسیار ناکارآمد خواهد بود و قطعاً از طریق شبکه تلفن همراه غیرعملی خواهد بود. این رویکرد همچنین کد مشتری را بسیار پیچیده تر می کند.
مشکل دیگر مشتری که مستقیماً با میکروسرویس ها تماس می گیرد این است که برخی ممکن است از پروتکل هایی استفاده کنند که وب پسند نیستند. یک سرویس ممکن است از Thrift باینری RPC استفاده کند در حالی که سرویس دیگری ممکن است از پروتکل پیام رسانی AMQP استفاده کند. هیچکدام از پروتکلها بهخصوص برای مرورگر یا فایروال مناسب نیستند و بهتر است به صورت داخلی استفاده شوند. یک برنامه کاربردی باید از پروتکل هایی مانند HTTP و WebSocket خارج از فایروال استفاده کند.
یکی دیگر از اشکالات این روش این است که بازسازی میکروسرویس ها را دشوار می کند. با گذشت زمان ممکن است بخواهیم نحوه پارتیشن بندی سیستم به سرویس ها را تغییر دهیم. برای مثال، ممکن است دو سرویس را ادغام کنیم یا یک سرویس را به دو یا چند سرویس تقسیم کنیم. با این حال، اگر مشتریان مستقیماً با خدمات ارتباط برقرار کنند، انجام این نوع بازسازی می تواند بسیار دشوار باشد.
به دلیل این نوع مشکلات، به ندرت منطقی است که مشتریان مستقیماً با میکروسرویس ها صحبت کنند.
معمولاً یک رویکرد بسیار بهتر استفاده از چیزی است که به عنوان دروازه API شناخته می شود . API Gateway سروری است که تنها نقطه ورود به سیستم است. این شبیه به الگوی نما از طراحی شی گرا است. API Gateway معماری سیستم داخلی را محصور می کند و یک API را ارائه می دهد که برای هر مشتری طراحی شده است. ممکن است مسئولیتهای دیگری مانند احراز هویت، نظارت، تعادل بار، ذخیرهسازی، شکلدهی و مدیریت درخواست، و مدیریت پاسخ استاتیک داشته باشد.
نمودار زیر نشان می دهد که چگونه یک API Gateway به طور معمول در معماری قرار می گیرد:
دروازه API مسئول مسیریابی درخواست، ترکیب و ترجمه پروتکل است. تمام درخواست های مشتریان ابتدا از طریق دروازه API انجام می شود. سپس درخواست ها را به میکروسرویس مناسب هدایت می کند. API Gateway اغلب یک درخواست را با فراخوانی چندین میکروسرویس و جمعآوری نتایج انجام میدهد. می تواند بین پروتکل های وب مانند HTTP و WebSocket و پروتکل های غیردوستانه وب که به صورت داخلی استفاده می شوند ترجمه کند.
در API Gateway همچنین می تواند برای هر مشتری یک API سفارشی ارائه کند. معمولاً یک API درشت دانه را برای مشتریان تلفن همراه نشان می دهد. به عنوان مثال، سناریوی جزئیات محصول را در نظر بگیرید. دروازه API می تواند یک نقطه پایانی ( /productdetails?productid= xxx ) ارائه دهد که به مشتری موبایل امکان می دهد تمام جزئیات محصول را با یک درخواست بازیابی کند. API Gateway با فراخوانی خدمات مختلف - اطلاعات محصول، توصیهها، بررسیها و غیره - و ترکیب نتایج، درخواست را مدیریت میکند.
یک نمونه عالی از یک دروازه API، دروازه API Netflix است . سرویس پخش جریانی Netflix در صدها نوع مختلف دستگاه از جمله تلویزیون، ست تاپ باکس، تلفن های هوشمند، سیستم های بازی، تبلت ها و غیره در دسترس است. در ابتدا، Netflix تلاش کرد یک API یک اندازه برای سرویس پخش خود ارائه دهد. با این حال، آنها متوجه شدند که به دلیل طیف متنوع دستگاه ها و نیازهای منحصر به فرد آنها، به خوبی کار نمی کند. امروزه، آنها از یک دروازه API استفاده می کنند که با اجرای کد آداپتور مخصوص دستگاه، یک API متناسب با هر دستگاه ارائه می دهد. یک آداپتور معمولاً هر درخواست را با فراخوانی به طور متوسط 6 تا 7 سرویس باطن انجام می دهد. دروازه API Netflix به میلیاردها درخواست در روز رسیدگی می کند.
همانطور که انتظار دارید، استفاده از API Gateway هم مزایا و هم معایبی دارد. مزیت اصلی استفاده از دروازه API این است که ساختار داخلی برنامه را محصور می کند. مشتریان به جای درخواست از خدمات خاص، به سادگی با دروازه صحبت می کنند. API Gateway برای هر نوع کلاینت یک API خاص ارائه می کند. این باعث کاهش تعداد رفت و برگشت بین مشتری و برنامه می شود. همچنین کد مشتری را ساده می کند.
در API Gateway نیز دارای اشکالاتی است. این یکی دیگر از مؤلفههای بسیار در دسترس است که باید توسعه، مستقر و مدیریت شود. همچنین این خطر وجود دارد که دروازه API به یک گلوگاه توسعه تبدیل شود. توسعه دهندگان باید API Gateway را به روز کنند تا نقاط پایانی هر میکروسرویس را در معرض دید قرار دهند. مهم است که روند به روز رسانی API Gateway تا حد امکان سبک باشد. در غیر این صورت، توسعه دهندگان برای به روز رسانی دروازه مجبور خواهند شد در صف منتظر بمانند. با وجود این اشکالات، برای اکثر برنامه های کاربردی دنیای واقعی، استفاده از دروازه API منطقی است.
اکنون که به انگیزه ها و مبادلات استفاده از دروازه API نگاه کردیم، بیایید به مسائل طراحی مختلفی که باید در نظر بگیرید نگاه کنیم.
تنها تعداد انگشت شماری از شرکت ها در مقیاس نتفلیکس فعالیت می کنند و نیاز به رسیدگی به میلیاردها درخواست در روز دارند. با این حال، برای اکثر برنامه ها عملکرد و مقیاس پذیری API Gateway معمولا بسیار مهم است. بنابراین منطقی است که API Gateway را بر روی پلتفرمی بسازیم که از ورودی/خروجی ناهمزمان و غیر مسدود کننده پشتیبانی کند. انواع مختلفی از فناوری های مختلف وجود دارد که می توان از آنها برای پیاده سازی یک API Gateway مقیاس پذیر استفاده کرد. در JVM میتوانید از یکی از چارچوبهای مبتنی بر NIO مانند Netty، Vertx، Spring Reactor یا JBoss Undertow استفاده کنید. یکی از گزینه های محبوب غیر JVM Node.js است که پلتفرمی است که بر روی موتور جاوا اسکریپت کروم ساخته شده است. گزینه دیگر استفاده از NGINX Plus است. NGINX Plus یک وب سرور بالغ، مقیاس پذیر و با کارایی بالا و پروکسی معکوس ارائه می دهد که به راحتی مستقر، پیکربندی و برنامه ریزی می شود. NGINX Plus میتواند احراز هویت، کنترل دسترسی، درخواستهای متعادلسازی بار، پاسخهای ذخیرهسازی را مدیریت کند و بررسیها و نظارت بر سلامت آگاهانه از برنامه را ارائه میدهد.
در API Gateway برخی از درخواست ها را به سادگی با مسیریابی آنها به سرویس Backend مناسب رسیدگی می کند. با فراخوانی چندین سرویس پشتیبان و جمعآوری نتایج، سایر درخواستها را مدیریت میکند. با برخی از درخواستها، مانند درخواست جزئیات محصول، درخواستهای مربوط به خدمات پشتیبان مستقل از یکدیگر هستند. به منظور به حداقل رساندن زمان پاسخ، API Gateway باید درخواست های مستقل را همزمان انجام دهد. با این حال، گاهی اوقات، وابستگی هایی بین درخواست ها وجود دارد. API Gateway ممکن است ابتدا نیاز داشته باشد تا درخواست را با فراخوانی یک سرویس احراز هویت، قبل از مسیریابی درخواست به یک سرویس باطن، تأیید کند. به طور مشابه، برای واکشی اطلاعات در مورد محصولات در لیست خواسته های مشتری، دروازه API ابتدا باید نمایه مشتری حاوی آن اطلاعات را بازیابی کند و سپس اطلاعات مربوط به هر محصول را بازیابی کند.شبکه ویدئویی نتفلیکس .
نوشتن کد ترکیب API با استفاده از رویکرد برگشت به تماس ناهمزمان سنتی به سرعت شما را به جهنم پاسخ به تماس سوق می دهد. کد درهم، درک آن دشوار و مستعد خطا خواهد بود. یک روش بسیار بهتر این است که کد API Gateway را با استفاده از رویکرد واکنشی به سبک اعلانی بنویسید. نمونه هایی از انتزاعات واکنشی عبارتند از Future در Scala، CompletableFuture در جاوا 8 و Promise در جاوا اسکریپت. افزونههای Reactive نیز وجود دارد(همچنین Rx یا ReactiveX نامیده می شود)، که در ابتدا توسط مایکروسافت برای پلت فرم دات نت توسعه داده شد. نتفلیکس RxJava را برای JVM به طور خاص برای استفاده در دروازه API خود ایجاد کرد. RxJS برای جاوا اسکریپت نیز وجود دارد که هم در مرورگر و هم در Node.js اجرا می شود. استفاده از یک رویکرد واکنشی شما را قادر می سازد تا کد API Gateway ساده و در عین حال کارآمد بنویسید.
یک برنامه کاربردی مبتنی بر میکروسرویس یک سیستم توزیع شده است و باید از مکانیزم ارتباط بین فرآیندی استفاده کند. دو سبک ارتباط بین فرآیندی وجود دارد. یکی از گزینه ها استفاده از مکانیزم ناهمزمان و مبتنی بر پیام است. برخی از پیاده سازی ها از یک واسطه پیام مانند JMS یا AMQP استفاده می کنند. سایرین، مانند Zeromq، بدون واسطه هستند و خدمات به طور مستقیم ارتباط برقرار می کنند. سبک دیگر ارتباط بین فرآیندی یک مکانیسم همزمان مانند HTTP یا Thrift است. یک سیستم معمولاً از هر دو سبک ناهمزمان و سنکرون استفاده می کند. حتی ممکن است از چندین پیاده سازی از هر سبک استفاده کند. در نتیجه، API Gateway باید از مکانیسمهای ارتباطی مختلفی پشتیبانی کند.
در API Gateway باید مکان (آدرس IP و پورت) هر میکروسرویسی که با آن در ارتباط است را بداند. در برنامههای سنتی، احتمالاً میتوانید مکانها را سیمکشی کنید، اما در برنامههای میکروسرویس مدرن مبتنی بر ابر، این یک مشکل غیر ضروری است. سرویسهای زیرساخت، مانند کارگزار پیام، معمولاً دارای یک مکان ثابت هستند که میتواند از طریق متغیرهای محیط سیستم عامل مشخص شود. با این حال، تعیین مکان یک سرویس برنامه چندان آسان نیست. سرویسهای برنامه دارای مکانهایی به صورت پویا هستند. همچنین مجموعه ای از نمونه های یک سرویس به دلیل مقیاس خودکار و ارتقاء به صورت پویا تغییر می کند. در نتیجه، دروازه API، مانند هر سرویس گیرنده دیگری در سیستم، باید از مکانیسم کشف سرویس سیستم استفاده کند: یا کشف سمت سرور یاکشف سمت مشتری . مقاله بعد خواهد کشف سرویس با جزئیات بیشتر توضیح می دهیم. در حال حاضر، شایان ذکر است که اگر سیستم از کشف سمت مشتری استفاده میکند، درگاه API باید بتواند رجیستری سرویس را که پایگاه دادهای از تمام نمونههای میکروسرویس و مکانهای آنها است، جستجو کند.
یکی دیگر از مسائلی که باید هنگام پیاده سازی یک API Gateway به آن بپردازید، مشکل شکست جزئی است. این موضوع در همه سیستم های توزیع شده زمانی که یک سرویس با سرویس دیگری تماس می گیرد که یا کند پاسخ می دهد یا در دسترس نیست، ایجاد می شود. دروازه API هرگز نباید به طور نامحدود منتظر یک سرویس پایین دستی را مسدود کند. با این حال، نحوه رسیدگی به خرابی به سناریوی خاص و اینکه کدام سرویس در حال شکست است بستگی دارد. به عنوان مثال، اگر سرویس توصیه در سناریوی جزئیات محصول پاسخگو نباشد، API Gateway باید بقیه جزئیات محصول را به مشتری برگرداند زیرا هنوز برای کاربر مفید هستند. توصیهها میتوانند خالی باشند یا مثلاً با یک لیست ده برتر سیمکشی شده جایگزین شوند. با این حال، اگر سرویس اطلاعات محصول پاسخگو نباشد، API Gateway باید یک خطا را به مشتری بازگرداند.
در API Gateway همچنین میتواند دادههای کش شده را در صورت موجود بودن بازگرداند. به عنوان مثال، از آنجایی که قیمت محصول به ندرت تغییر می کند، در صورتی که سرویس قیمت گذاری در دسترس نباشد، API Gateway می تواند داده های قیمت گذاری ذخیره شده را برگرداند. داده ها را می توان توسط خود API Gateway ذخیره کرد یا در یک کش خارجی مانند Redis یا Memcached ذخیره کرد. با برگرداندن داده های پیش فرض یا داده های حافظه پنهان، API Gateway تضمین می کند که خرابی های سیستم بر تجربه کاربر تأثیر نمی گذارد.
در Netflix Hystrix یک کتابخانه فوق العاده مفید برای نوشتن کدی است که خدمات از راه دور را فراخوانی می کند. Hystrix تماس هایی را که از آستانه تعیین شده فراتر می روند، دفع می کند. این یک الگوی قطع کننده مدار را اجرا می کند ، که مشتری را از انتظار بیهوده برای یک سرویس بی پاسخ باز می دارد. اگر میزان خطای یک سرویس از آستانه مشخص شده فراتر رود، Hystrix مدار شکن را خاموش می کند و همه درخواست ها بلافاصله برای یک دوره زمانی مشخص با شکست مواجه می شوند. Hystrix به شما این امکان را میدهد تا زمانی که درخواستی با شکست مواجه میشود، یک عمل بازگشتی تعریف کنید، مانند خواندن از حافظه پنهان یا برگرداندن یک مقدار پیشفرض. اگر از JVM استفاده می کنید، حتما باید از Hystrix استفاده کنید. و اگر در یک محیط غیر JVM در حال اجرا هستید، باید از یک کتابخانه معادل استفاده کنید.
برای اکثر برنامههای کاربردی مبتنی بر میکروسرویس، پیادهسازی یک API Gateway که به عنوان یک نقطه ورودی واحد در یک سیستم عمل میکند، منطقی است. دروازه API مسئول مسیریابی درخواست، ترکیب و ترجمه پروتکل است. به هر یک از مشتریان برنامه یک API سفارشی ارائه می کند. API Gateway همچنین میتواند با برگرداندن دادههای ذخیرهشده یا پیشفرض، خرابیهای سرویسهای پشتیبان را پنهان کند. در مقاله بعدی این مجموعه به ارتباط بین سرویس ها خواهیم پرداخت.
«این مطلب، بخشی از تمرینهای درس معماری نرمافزار در دانشگاه شهیدبهشتی است»