Data Consistency در معماری توزیع شده، یک معما است. شاید اغراق آمیز باشد اگر بگوییم که یک چیز دردناک است. ممکن است در نگاه اول این چندان واضح نباشد، اما Data Consistency هرگز به صورت مجزا وجود ندارد و شدیداً با قابلیت دسترسی(Availability) و Partition Tolerance پیوند خورده است. اگر پیوند آنها عجیب و دور از ذهن به نظر میرسد، نگران نباشید. به زودی به آنها و دوستی آنها خواهیم پرداخت. به دلیل پیوند نزدیک، تغییر در یکی از آنها، به شکل بیسر و صدایی منجر به تغییر در دیگری میشود. این مجموعه تغییرات، مشکلاتی را با مشکلات دیگر جایگزین میکنند. و چیزی که شما دارید این است که، تغییر در فرانت اند، باعث ایجاد مشکلات در بک اند میشود و بالعکس.
در سیستم توزیع شده، یک وابستگی متقابل بین Consistency ، Availability و Partition Tolerance توسط قضیه CAP تعریف شده است. البته این قضیه در اصل توسط اریک ای.بریور برای data store های توزیع شده فرموله شده است، اما برای هر معماری توزیع شده، از جمله معماری مایکروسرویس قابل استفاده است.
من فکر میکنم توضیح کاربرد آن ارزشش را دارد. ما با تعریف معماری مایکروسرویس شروع خواهیم کرد. در این جا یک تعریف بسیار مختصر از معماری سرویسگرا با پیوندهای آزاد با کانتکستهای محدود ارائه می شود.
معماری مایکروسرویس
اگر بخواهم بیشتر توضیح دهم، معماری مایکروسرویس رویکردی است که در آن اپلیکیشن با مجموعهای از سرویسهای قابل استقرار و مستقل ساخته میشود. اصل separation of concerns (تفکیک نگرانیها) برای تعیین مرزهای سرویس استفاده میشود. از این رو هر سرویس هدف مشخصی دارد. یا بدون تابعیت است یا دادههای خود را دارد.
برای یک خوشه (cluster) از سرویسها، غیر معمول نیست که به یک زیرمجموعه از داده علاقه داشته باشد. از آنجایی که قرار است هر سرویس stateful دارای دادههای خود باشد. خوشهای مانند این، مانند یک فضای ذخیرهسازی توزیع شده برای آن زیرمجموعه از دادهها است. این بدان معناست که ما میتوانیم یک قضیه CAP برای آن اعمال کنیم.
قضیه CAP
این قضیه بیان میکند که اگرچه داشتن Consistency ، Availability و Partition Tolerance مطلوب است، اما متأسفانه هیچ سیستمی نمیتواند هر سه اینها را با هم به دست بیاورد. به عبارت دیگر، از بین این سه فاکتور، میتوانیم حداکثر دو فاکتور را انتخاب کنیم .

قبل از تخصیص این قضیه برای مایکروسرویسها، اجازه دهید C ، A و P را تعریف کنیم.
Consistency
Data Consistency در دو نوع ارائه میشود: کاملاً Consistent یا در نهایت Consistent . اگر هر دو سرویس دلخواه در خوشه، که زیرمجموعهای از دادهها را به اشتراک میگذارند، در هر لحظه نسخه یکسانی از دادهها را داشته باشند، دادهها کاملاً Consistent هستند. اگر هر دو سرویس دلخواه در خوشه زیرمجموعهای از دادهها را به اشتراک بگذارند، اما لزوماً نسخه مشابهی از دادهها را در هر لحظه نداشته باشند، دادهها در نهایت سازگار هستند. اما آنها تضمین کردهاند که در نهایت همان نسخه را خواهند داشت.
این قضیه بر Consistency کامل و قوی با این مشخصه دلالت دارد. به عبارت دیگر، اگر معماری شما این ویژگی را داشته باشد، دادههای درونی شما کاملاً Consistent هستند.
Availability
Availability یا در دسترس بودن به این معنی است که هر سرویس دلخواه در هر لحظه، blocked/locked نمیشود. توجه داشته باشید که این یک Availability از منظر uptime (با نام مستعار High-Availability ) نیست، بلکه از منظر سرویسدهی است. این سرویس برای پردازش درخواست در دسترس است، حتی اگر آخرین نسخه داده خود را در هر لحظه نداشته باشد.
Partition Tolerance
در زمینه معماری مایکروسرویس، این ویژگی در واقع یک ویژگی اختیاری نیست، یک مشخصه است. Partition یک وقفه یا تأخیر در ارتباط بین سرویسها است. داشتن Partition Tolerance به این معنی است که شما به اتصال بین سرویسهای خود و زیرساختهای زیرین اطمینان دارید. با توجه به زیرساختهای مدرن، ارائه دهندگان cloud و بیشتر (شاید همه) message broker های مدرن، تحویل پیام را «حداقل یک بار» تضمین میکنند. این برای معماری مایکروسرویس، تقریباً قطعی و غیر قابل مذاکره است.
قضیه Refined CAP (قضیه CA یا CAP تصفیه شده)
بیایید تعریف کلی قضیه CAP را اصلاح کنیم و آن را به یک نسخه معماری مایکروسرویس تبدیل کنیم. از آنجا که Partition Tolerance قطعی و از پیش معین است، ما آن را از تعریف خود حذف خواهیم کرد.
در معماری مایکروسرویس، برای هر خوشه داده شدهای از سرویسها، میتوانیم Consistency قوی یا Availability را تضمین کنیم.

Consistency vs Availability
بیایید ببینیم چگونه میتوانیم یکی از این ویژگیها را در معماری مایکروسرویس تضمین کنیم و به چه قیمتی میتوانیم این کار را انجام دهیم.
اسپویلر! : همانطور که جلو میرویم، مشاهده خواهید کرد که برای معماری مایکروسرویس، این انتخاب از قبل تعریف شده است.
Commit دو فازی
Commit دو فازی (معروف به تراکنش توزیع شده) تلاشی برای Commit / نوشتن / آپدیت یک اطلاعات به اشتراک گذاری شده برای هر سرویس در خوشه است که در دو مرحله انجام میشود. این رویکرد به یک سرویس coordinator نیاز دارد که اجرای هر دو فاز را کنترل کند.
فاز 1 – coordinator هر سرویس را در مورد آمادگی برای انجام تراکنش بررسی میکند. این فاز هر سرویس را بلافاصله بعد از پاسخگویی، lock میکند. این قفل کردن برای اطمینان از اینکه میخواهیم عملیات واقعی را ادامه دهیم، لازم است. (فاز 2). سرویسها به همان شکلی که در این فاز رهایشان کردهایم، باقی میمانند. اگر هر سرویسی آماده نباشد، کل تراکنش را لغو میکنیم و همه سرویسها را unlock میکنیم.
فاز 2 – در این فاز یک عملیات به روز رسانی برای هر سرویس در خوشه انجام میشود. پس از اتمام این مرحله، همه سرویسها unlock میشوند.

بدیهی است که این رویکرد، Consistency را بیشتر از Availability تضمین میکند. (قضیه CA ) همه سرویسهای این خوشه، پس از هر تراکنش 2PC ، دادههای کاملاً consistent را حفظ خواهند کرد. با این حال، آنها در طول کل فرآیند lock خواهند شد. بنابراین در دسترس نیستند.
اگر تصمیم دارید از این رویکرد در معماری مایکروسرویس استفاده کنید، من قویاً توصیه میکنم که سرحدهای تمام سرویسهای موجود در این خوشه را بازنگری کنید. این رویکرد تمام خدمات در سرویس را شدیداً با هم مرتبط میکند و بر خلاف تعریف معماری مایکروسرویس است. همچنین به خوبی در تعریف Monolith توزیع شده جای میگیرد. علاوه بر این، من باور ندارم که هر message broker مدرنی 2PC را به عنوان یک آپشن ارائه میدهد. از این رو شما باید Coordinator خود را بسازید و از آن نگهداری کنید.
Sagas
Saga برخلاف Commit دوفازی، Availability را بیش از Consistency تأمین میکند. به این معنی که دادهها در نهایت (و نه کاملاً) consistent خواهند بود. این رایجترین رویکرد برای اجرای data consistency در معماری مایکروسرویس است.
Saga نشاندهنده یک sequence کنترلشده از تراکنشهای مستقل است که توسط هر سرویس در خوشه اجرا میشود. اگر یکی از سرویسها نتواند تراکنش لازم را اجرا کند، بازگردانی یا rollback با یک sequence از تراکنشهای جبرانی انجام میشود.
Saga در دو مدل ارائه میشود. محصور به اینکه چه کسی اجرای آن را coordinate میکند، میتواند با service choreographed یا service orchestrated انجام میشود.
Service Choreography
Service Choreography مدلی از ترکیب سرویسهای غیرمتمرکز است. دانش Saga و نحوه اجرای آن در بین سرویسهایی که در Saga شرکت میکنند، پخش میشود. هر سرویس میداند که در صورت اجرای موفقیت آمیز تراکنش محلی، باید به کدام سرویس پیام ارسال کند. و همچنین میداند که در صورت شکست تراکنش محلی چگونه یک پیام جبرانی بسازد (و آن را به کجا ارسال کند) یا یک سرویس موفق چگونه یک تراکنش جبرانی بسازد. ما لزوماً از ارتباط مستقیم بین سرویسها (مانند PRC ) استفاده نمیکنیم، بلکه یک صف را ترجیح میدهیم .

Service Orchestration
Service Orchestration مدلی از ترکیب سرویس متمرکز است. Saga توسط یک سرویس ارکستراسیون coordinate میشود. نقش اصلی orchestrator این است که پیام را از فرستنده به همه شرکتکنندگان Saga (معروف به مشترکین پیام) ارسال کند. اغلب یک message broker به عنوان orchestrator منصوب میشود. هم پیامهای general و هم پیامهای جبرانی توسط orchestrator هماهنگ میشود.

سخن پایانی
توصیه میکنم که از Service Orchestrated Sagas با یک Message Broker مدرن به عنوان یک orchestrator برای اجرای data consistency در معماری مایکروسرویس استفاده کنید. Message Broker سرویسها را در خوشه جداسازی میکند. این کار سطح اصطکاک بین سرویسها را کاهش میدهد و برخلاف Service Choreographed Sagas ، آگاهی غیر ضروری را از هر سرویس، چه Saga موفق و چه Saga جبرانی حذف میکند.
منبع: HackerNoon نویسنده: والری اودودوف
Leave feedback about this