علیرضا ارومند
علیرضا ارومند
خواندن ۱۰ دقیقه·۵ سال پیش

قسمت پنجم میکروسرویس‌ها: آشنایی با Service Discovery

به پنجمین قسمت از مجموعه مقالات آشنایی با میکروسرویس‌ها رسیدیم. در قسمت اول از این مجموعه با هم در مورد کلیات این معماری صحبت کرده و مزایا و معایب این معماری را بررسی کردیم. در دومین قسمت به سراغ API Gatewayها، نقش آن‌ها در توسعه میکروسرویس و باید‌ها و نباید‌های یک API Gateway صحبت کردیم. سپس در قسمت سوم در مورد ارتباط بین سرویس‌ها و انواع روش‌های برقراری ارتباط صحبت کردیم و نهایتا در چهارمین قسمت در مورد تکنولوژی‌های توسعه میکروسرویس‌ها صحبت کردیم. در ادامه قصد داریم در مورد Service Discovery با هم صحبت کنیم.

1. مقدمه:

بیایید فرض کنیم که در حال توسعه یک نرم‌افزار هستیم که نیاز دارد یک API را صدا بزند. فارغ از اینکه یک REST APIرا مورد استفاده قرار می‌دهیم یا Thrift API، نیاز داریم آدرس API مورد نظر را بدانیم. تا چند سال پیش که نرم‌افزار‌ها معمولا در یک سرور نصب می‌شدند آگاهی از آدرس APIها کار مشکلی نبوده و معمولا آدرسی ثابت بود. در چنین شرایطی نهایت آینده نگری که نیاز بود داشته باشیم، قراردادن آدرس API در فایل Config بود که در صورتی که در آینده نیاز به تغییر آدرس داشته باشیم، بتوانیم بدون کامپایل مجدد سورس کد، آدرس را تغییر دهیم.

اما این شرایط در نرم‌افزارهای مدرنی که روی Cloud اجرا می‌شوند و آدرس‌ آن‌ها دائما تغییر می‌کند و در میکروسرویس‌هایی که دائما instanceهای متفاوتی از آن‌ها در آدرس‌های متفاوتی اجرا می‌شود صادق نخواهد بود. یک سرویس ممکن است با توجه به فشار زیادی که روی آن وجود دارد به صورت اتوماتیک scale out شود و در چند آدرس جدید اجرا شود. ممکن است یک سرویس که در یک آدرس وجود دارد به دلیل خطا از دسترس خارج شده و دیگر در آدرس قبلی سرویسی برای ارائه خدمات وجود نداشته باشد.

استفاده کننده‌ها برای یافتن آدرس سرویس‌ها نیاز به راهنمایی دارند
استفاده کننده‌ها برای یافتن آدرس سرویس‌ها نیاز به راهنمایی دارند

با توجه به همه این شرایط می‌توانیم نتیجه بگیریم که دیگر آدرس دهی static بی‌فایده بوده و باید به سراغ راهکاری جدید برای انجام این کار برویم.راهکاری که در این قسمت قصد بررسی آن‌را داریم Service Discovery است.

به طور کلی به دو صورت می‌توانیم این روال را پیاده سازی کنیم که عبارتند از Client-side Discovery و Server-side Discovery، که در ادامه با این دو روش آشنا خواهیم شد.

2. آشنایی با Service Registry:

همانطور که قبلا بیان کردیم تا پیش از این با توجه به ایستا بودن آدرس‌ها، نگهداری آن‌ها در فایل config انجام می‌شد، اما با توجه به تغییرات صورت گرفته، نیاز داریم که وظیفه نگهداری آدرس‌های مختلف از سرویس‌های مختلف را به صورت داینامیک انجام شود. این وظیفه توسط Service Registry انجام می‌شود.

3. آشنایی با الگوی Client-side Discovery

زمانی که از الگوی client-side discovery استفاده می‌کنیم، وظیفه تشخیص محل سرویس‌ها و برقراری توازن در ارسال درخواست به نسخه‌های مختلف یک سرویس، به عهده کلاینت است. در این روش ابتدا کلاینت یک query روی Service Registry اجرا کرده و لیستی از نمونه‌های سرویس دلخواه واکشی می‌کند، سپس با یک الگوریتم توزیع بار، نمونه‌ای از سرویس را انتخاب کرده و درخواست را برای آن ارسال می‌کند. در تصویر زیر نحوه انجام این‌ کار را مشاهده می‌کنید.

پیاده سازی Service Discovery توسط کلاینت
پیاده سازی Service Discovery توسط کلاینت

آدرس نمونه‌های متفاوت از سرویس‌ها هنگام شروع به کار سرویس ثبت شده و با پایان یافتن اجرای یک سرویس آدرس آن نیز از Service Registry حذف می شود. Service Registry در بازه‌های زمانی مشخصی برای بررسی وجود یا عدم وجود سرویس‌های ثبت شده بررسی می شود. به این بازه‌های زمانی را اصطلاحا heartbeat می‌نامیم.

یک پیاده سازی مناسب از این الگو را در Netflix OSS می‌توانید مشاهده کنید.در این نمونه Netflix Eureka به عنوان یک Service registry ایفای نقش می‌کند.Eureka برای ثبت، حذف و جستجوی آدرس سرویس‌ها تعدادی REST API در اختیار استفاده کنندگان قرار می‌دهد. برای پیاده سازی یک روال توزیع بار مناسب نیز می‌توانیم از Netflix Ribbon در کنار سایر ابزار‌ها استفاده کنیم.

استفاده از این روش مزایا و معایب خاص خود را دارد که در ادامه بررسی می‌کنیم. بزرگترین مزیت این روش سادگی آن است. تنها کافیست آدرس Service Registry در اختیار کلاینت قرار بگیرد و کار تمام است. در این روش هر کلاینت می‌تواند الگوی توزیع بار اختصاصی خود را با توجه به شرایط اختصاصی خود پیاده سازی کند. بزرگترین عیب این روش هم می‌تواند وابستگی کامل کلاینت به Service Registry باشد. در نهایت اجبار به پیاده سازی این الگو به ازای هر کلاینت هم در صورتی که کلاینت‌های زیادی داشته باشیم می‌تواند خیلی سریع تبدیل به کابوس هر شب توسعه دهندگان شود.

حال که با پیاده سازی الگوی Service Discovery سمت کلاینت آشنا شدیم به سراغ پیاده سازی این الگو سمت سرور می‌رویم.

4. آشنایی با الگوی Server-Side Discovery:

روش دیگر پیاده سازی الگوی Service Discovery، پیاده سازی آن سمت سرور بوده که می‌توانید در تصویر زیر مشاهده کنید:

پیاده سازی Service Discovery سمت سرور
پیاده سازی Service Discovery سمت سرور

در این روش، کلاینت درخواست‌های خود را برای یک مسیریاب ارسال می‌کند سپس مسیریاب Service Registry را برای یافتن آدرس نمونه‌های ثبت شده از سرویس هدف جستجو می‌کند.در پایان بعد از یافتن نمونه‌های سرویس با یک الگوریتم توزیع مناسب، نمونه‌ای از سرویسانتخاب شده و درخواست برای پردازش به آن سرویس ارسال می‌شود. ثبت و حذف سرویس‌ها در این روش هم، مانند پیاده سازی توسط کلاینت انجام می‌شود.

به عنوان نمونه‌ای از پیاده سازی یک مسیریاب می‌توان بهAWS Elastic Load Balancing اشاره کرد. برای استفاده از این سیستم، درخواست‌های HTTP یا TCP به ELB ارسال می‌شود و با توجه به نمونه‌های ثبت شده از سرویس‌ها متفاوت درخواست‌ها بین آن‌ها توزیع می‌شود.

برخی از محیط‌های توزیع مانند Kubernetes یک پروکسی ایجاد می‌کنند که مسئولیت Server-Side Load Balancer را انجام می‌دهند. در این روش کلاینت‌ها درخواست‌های خود را برای Proxy ارسال ‌می‌کنند و proxy به صورت هوشمند درخواست را برای سرویس‌های در دسترس ارسال می‌کند. پیاده سازی الگوی Service Discovery سمت سرور هم مانند هر روش دیگری مزایا و معایب خودش را دارد که در ادامه بررسی خواهیم کرد.

5. بررسی دقیق Service Registry:

همانطور که قبلا بیان شد قلب الگوی Service Discovery، دیتابیس آدرس‌ها یا Service Registry است. Service Registry دیتابیسی است که آدرس دقیق هر نمونه از سرویس‌ها را نگهداری می‌کند. با توجه به نقش مهم این بخش، Service Registry باید همیشه در دسترس باشد و همیشه به روز باشد. برای افزایش بهره‌وری، کلاینت‌ها می‌توانند آدرس‌های به دست آمده از Service Registry را کش کنند، اما با توجه به اینکه این اطلاعات دائما به روز می‌شود، باید روالی برای به روز رسانی داده‌های کش شده جهت جلوگیری از بروز مشکل سمت کلاینت در نظر گرفته شود.

همانطور که قبلا ذکر شد Netflix Eureka یک نمونه خوب از پیاده سازی Service Registry است. این ابزار یک REST API قوی برای ثبت و مدیریت آدرس سرویس‌ها ارائه می‌کند. برای ثبت یک آدرس جدید باید یک درخواست POST به Eureka ارسال کنیم. برای پیاده سازی الگوی heartbeat و زنده ماندن سرویس به صورت پیش‌فرض سرویس‌ها باید هر 30 ثانیه یک درخواست PUT برای Eureka ارسال کنند. در صورتی که مدتی بیش از 30 ثانیه بگذرد و درخواست PUT ارسال نشود یا اینکه یک درخواست DELETE برای Eureka ارسال شود، سرویس از پایگاه‌داده حذف می‌شود. اگر با سرویس‌های REST آشنا باشید احتمالا تا الان حدس زده‌اید که برای دریافت یک آدرس باید یک درخواست GET برای Eureka ارسال کنیم. با توجه به اهمیت Service Registry و نیاز به دردسترس بود همیشگی این سرویس می‌توان از روال‌های clustering همراه با Eureka استفاده کرد. پیشنهاد می‌کنم حتما برای آشنایی بیشتر با Eureka به مستندات آن مراجعه کنید اما اگر به هر دلیلی تمایل داشتید از ابزار دیگری استفاده کنید می‌توانید از موارد ذیل استفاده کنید:

اولین گزینه etcd است. یک پایگاه داده Key-Value و توزیع شده که برای نگهداری تنظیمات و Service discovery استفاده می‌شود. به عنوان یکی از پروژه‌های مهمی که از این ابزار استفاده می‌کند Kubernetes را می‌توان نام برد.

به عنوان دومین ابزار مهم در این دسته می‌توان از Consul نام برد. این سیستم‌ها مانند بقیه موارد این دسته امکان ثبت و مدیریت سرویس‌ها را به کمک API فراهم می‌کند. به کمک این ابزار و امکانات آن می‌توانید وضعیت سلامتی و به روزبودن سرویس‌های خود را نیز تحت نظر قرار دهید.

و آخرین ابزاری که در این قسمت قابل بررسی است Apache ZooKeeper نام دارد. این ابزار هم یکی از موفق‌ترین نمونه‌های این دسته است که ابتدا به عنوان بخشی از پروژه Hadoop معرفی شد و با گذشت زمان به سرویسی مجزا تبدیل شد.

همانطور که قبلا هم عنوان شد اگر از برخی زیرساخت‌ها مثل Kubernetes یا AWS استفاده کنیم، نیازی به ابزار جداگانه برای Service Registry نداریم این الگو به صورت توکار توسط زیرساخت پشتیبانی می‌شود.

حال که با کلیات Service Registry و ابزارهای آن آشنا شدیم بیاید نگاهی به انواع روش‌های ثبت و مدیریت آدرس سرویس‌ها بیاندازیم.

6. انواع روش‌های مدیریت سرویس‌ها:

همانطور که قبلا توضیح داده شد، باید امکانی داشته باشیم که نمونه‌های جدید سرویس‌ها را در Service Registry ثبت کنیم و در مواقعی که نیاز داریم نمونه‌های ثبت شده را از دیتابیس حذف کنیم. این کارها را به روش‌های متفاوتی می‌توانیم انجام دهیم. اولین گزینه ثبت و مدیریت آدرس نمونه سرویس‌ها توسط خود سرویس‌ها است که به این روش Self Registration گفته می‌شود. اما این کار می‌تواند توسط یک سرویس دیگر انجام شود که به این روش نیز اصطلاحا third-party registration گفته می‌شود. بیایید باهم این روش‌ها را دقیق‌تر بررسی کنیم.

6.1. الگوی Self-Registration:

هنگامی که از این الگو استفاده می‌کنیم، هر سرویس مسئول ثبت و حذف آدرس خود در Service Registry است. در صورت نیاز درخواست‌های heartbeat نیز باید توسط خود سرویس‌ها ارسال شود تا از حذف ناخواسته سرویس از Service Registry جلوگیری کند.

ثبت و مدیریت سرویس‌ها توسط هر نمونه‌ از سرویس
ثبت و مدیریت سرویس‌ها توسط هر نمونه‌ از سرویس

نمونه خوبی از پیاده سازی این الگو را در Netflix OSS Eureka client می‌توانید مشاهده کنید.Eureka Client تمام کارهای مربوط به ثبت، حذف و مدیریت نمونه‌های سرویس‌ها را برای ما انجام می‌دهد.

یکی از مزایای استفاده از این روش سادگی پیاده سازی آن است. در این روش دیگر نیازی به استفاده از ابزار دیگری نیست و هر سرویس خود مسئول مدیریت نمونه‌های خودش می‌باشد. هر چند در کنار این سادگی باید بپذیریم که سرویس‌های ما به جز وظیفه‌ای که در نرم‌افزار ما به عهده دارند باید وظیفه دیگری را نیز به عهده بگیرند. پیاده سازی تکراری روال مدیریت نمونه سرویس‌ها نیز یکی دیگر از مشکلات پیاده سازی به این روش است. ضعف دیگر این روش پیاده سازی هم این است که به ازای هر زبان‌برنامه نویسی و فریم‌ورکی که استفاده می‌کنیم باید بتوانیم این الگو را پیاده سازی کنیم.

6.2. الگوی Third-Party Registration:

هنگامی که از این روش استفاده می‌کنیم دیگر نیازی نیست که هر سرویس به صورت خودمختار و مجزا اقدام به مدیریت نمونه‌های خود بکند. بلکه در این روش یک سرویس دیگر به سیستم اضافه می شود که به آن Service registrar می‌گوییم. در این روش یا سرویس‌ها باید در زمان‌هایی خاص Event هایی را ایجاد کنند که Service Registrar مسئول مدیریت این Eventها است و یا اینکه زیرساخت باید به Service registrar معرفی شود و به طور دائم زیرساخت توسط Service registrar برای اجرای نمونه‌ای جدید از سرویس یا توقف یک نمونه از سرویس بررسی شود. در نهایت به یکی از روش‌های بالا Service registrar از وضعیت سرویس‌ها مطلع می‌شود و نسبت و ثبت و یا حذف سرویس‌ها اقدام می‌کند.

پیاده سازی third-party registration
پیاده سازی third-party registration

پروژه Registrator یکی از نمونه‌های پیاده سازی این روش است. این ابزار به صورت خودکار سرویس‌هایی که توسط Docker مدیریت می‌شوند را ثبت و حذف می‌کند. این ابزار Service Registryهای متعددی از جمله etcd و Consul را پشتبانی می‌کند.

اما این الگو هم مانند هر الگوی دیگری مزایا و معایبی دارد که باید با آن‌ها آشنا باشیم که در مواقع لزوم بتوانیم به درستی ابزار مورد نیاز خود را انتخاب کنیم. جداسازی سرویس‌ها از هر دلمشغولی به جز عملکرد مورد نیاز خودشان بزرگترین مزیت پیاده سازی این الگو است. دیگر نیازی نیست که به ازای هر سرویس منطق مربوط به ثبت و مدیریت سرویس‌ها را پیاده سازی کنیم. به جای همه این کارهای اضافه، انجام عملیات ثبت و مدیریت نمونه‌های سرویس‌ها به صورت مرکزی و خودکار انجام می‌شود. با تمام این مزایایی که ذکر شد باید دقت داشته باشیم که یک سرویس و ابزار جدید به سیستم اضافه می شود که مثل سایر سرویس‌ها نیاز به نگهداری و مدیریت دارد و زیاد شدن این سرویس‌های خدماتی می‌تواند خیلی زود تبدیل به هیولایی غیرقابل کنترل شود.

7. خلاصه:

در میکروسرویس‌ها نمونه‌های نامشخصی از هر سرویس امکان اجرا دارد. با توجه به زیرساخت‌هایی که در میکروسریس‌ها استفاده می‌شود، آدرس‌های آن‌ها نیز دائما احتمالا تغییر دارد و دیگر نگهداری ایستای آدرس‌ها کارساز نخواهد بود و باید این مشکل را به شکلی حل کنیم که در این مطلب به بررسی روش حل همین مشکل پرداختیم.

در قسمت بعد راجع به مدیریت داده‌ها در میکروسرویس‌ها صحبت خواهیم کرد.

ادامه مطلب:

http://vrgl.ir/sWRjx
http://vrgl.ir/8cRfJ
microserviceُservice discoveryُservice registryُمعماری نرم‌افزار
شاید از این پست‌ها خوشتان بیاید