چگونه پایگاه داده‌ها را در Microserviceها مدیریت کنیم؟

چگونه پایگاه داده‌ها را در Microserviceها مدیریت کنیم؟

نوشته شده توسط: تیم فنی نیک آموز
تاریخ انتشار: ۱۳ دی ۱۴۰۰
آخرین بروزرسانی: ۱۷ مهر ۱۴۰۱
زمان مطالعه: 16 دقیقه
۳.۸
(۴)

مقدمه

در این مقاله میخواهیم در مورد مدیریت داده ها و Data considerations در مایکروسرویس ها صحبت کنیم.
از چه ابزارها، الگوها و اصول هایی می توانیم برای مدیریت داده در مایکروسرویس ها استفاده کنیم؟

مدیریت دیتابیس یک مایکروسرویس کاری چالش برانگیز است و برای حل کردن این چالش باید استراتژی هایی داشته باشیم.
با استفاده از الگوها و Best Practice های موجود در این زمینه میتوانیم بسیاری از این چالش ها را حل کنیم.
موضوع اصلی این مقاله معرفی و توضیح کوتاهی در مورد الگوهایی است که میتوانند مشکلات مربوط data Decentralization را در مایکروسرویس ها حل کنند.
هر مایکرسرویس نیاز دارد که دیتای مورد نیازش را در دیتابیس خودش داشته باشد و با مایکرسرویس های دیگر هم ارتباط و تبادل دیتا داشته باشد.
اما این ارتباط و تبادل دیتا بین مایکروسرویس ها باعث چالش هایی میشود، برای مثال:

  • امکان استفاده از ACID Transactions را نداریم.
  • پیاده سازیQuery هایی که نیاز به Join چند دیتای مختلف از چند دیتابیس مجزا دارند سخت میشود.

در ادامه با ۵ الگو و ۱ ضد الگو در رابطه با مدیریت داده در مایکروسرویس ها آشنا میشویم.

  • The Database-per-Service Pattern
  • The API Composition Pattern
  • The CQRS Pattern
  • The Event Sourcing Pattern
  • The Saga Pattern
  • The Shared Database Anti-Pattern

الگوی Database-per-Service

داشتن یک دیتابیس به ازای هر سرویس یکی از مشخصات اصلی معماری Microservices است.برای اینکه Loose Coupling بین مایکروسرویس ها رعایت شود باید هر مایکروسرویس دیتابیس شخصی خودش را داشته باشد.
در طراحی معماری دیتابیس برای مایکروسرویس ها الگویDatabase per-service pattern همیشه مورد نیاز است و باید از آن استفاده کنیم.

یکی از کارهایی که باید در زمان تبدیل معماری Monolithic به Microservices انجام دهیم، جدا کردن دیتابیس ها از هم دیگر است.بنابر این ما یک دیتابیس بزرگ را به چند دیتابیس کوچک خورد میکنیم و هر دیتابیس کوچک مربوط به یک مایکروسرویس خاص میشود، در واقع با اینکار پترن Database per-service را اجرا میکنیم.

پترن Database per-service دارای فواید زیادی است، برای مثال:

  • هر دیتابیس میتواندبه صورت مستقل Scale شود.
  • قابلیت Development هر مایکروسرویس را آسان تر میکند.
  • امکان تغییر Database schema را بی خطر میکند، تا آنجایی که بتوانیم تغییراتی بدون اثر بد بر روی دیگر مایکروسرویس ها داشته باشیم.

همچنین این پترن معایبی هم دارد، برای مثال فرض کنید که ۴ مایکروسرویس داریم و هر کدام از آن ها دیتابیس مخصوص خودشان را دارند، حالا باید برای مدیرمان یک گزارش بسازیم، این گزارش نیاز به دیتای هر ۴ مایکروسرویس دارد و باید دیتاها را با هم Join کنیم، چطور دیتای ۴ دیتابیس مختلف SQL و NoSQL را با هم Join کنیم؟ (راه حل در الگوی بعدی توضیح داده میشود.)
داشتن یک دیتابیس به ازای هر مایکرسرویس به ما اجازه میدهد که بهترین و بهینه ترین نوع دیتابیس را برای مایکروسرویس هایمان انتخاب کنیم.

انواع دیتابیس

  • Relational
  • Document-oriented
  • Key-Value
  • Graph

همانطور که در تصویر بالا مشاهده میکنید، هر مایکروسرویس دیتابیس خودش را دارد، مایکروسرویس Catalog از MongoDB که یک دیتابیس NoSQL و Document- oriented است استفاده میکند.
مایکروسرویس Shopping Cart از یک دیتابیس Key-Value به عنوان Distributed Cache استفاده میکند.
مایکروسرویس Ordering از یک دیتابیس Relational استفاده میکند تا بتواند داده ها را به صورت رابطه ای ذخیره کند.
بنابراین جداسازی دیتابیس هر سرویس به ما اجازه میدهد که بتوانیم از دیتابیس های مختلف استفاده کنیم و آن ها را با توجه بار موجود بر روی مایکروسرویس به طور مستقل Scale کنیم.

الگوی API Composition

در بالا با الگوی Database per-service آشنا شدیم و متوجه شدیم که اگر دیتای مورد نیاز یک مایکروسرویس از چند دیتابیس بیاید و نیازمند Join باشد با چالش هایی رو به رو میشویم، اما با استفاده از الگوی API Composition می توانیم این مشکل را حل کنیم.
با استفاده از این الگو میتوانیم یک API Composer پیاده سازی کنیم که دیتاهای مورد نیاز را از مایکروسرویس های مختلف دریافت کند و in-memory Join بر روی دیتاها انجام دهد.
بیشتر اوقات API Gateway ها عملیات Composition را برای ما انجام میدهند.

الگوهای مشابه:

API Gateway Pattern

Gateway Routing Pattern

Gateway Aggregation Pattern

Gateway Offloading Pattern

بنابراین وقتی که گزارشی میخواهیم و این گزارش نیازمند چند Query به مایکروسرویس های مختلف است از پترن های بالا استفاده میکنیم تا داده ها را ترکیب کنیم.

الگوی CQRS

الگوی Command Query Responsibility Segregation یا به اختصار CQRS به ما می گوید که Command model و Query model هایمان را از همدیگر جدا کنیم.

Command Model مدلی است که دیتایی را تغییر میدهد، برای مثال فرض کنید یک کلاسی دارید به نام RegisterStudentCommand که پراپرتی هایی مربوط به ثبت نام یک دانشجو در آن قرار گرفته است.
Query Model مدلی است که دیتایی را میخواند و یک DTO بر می گرداند، برای مثال فرض کنید یک کلاسی دارید به نام GetStudentByGradeAndCourse بر اساس مقادیر موجود در پراپرتی های این کلاس شرط Query مشخص میشود و به دیتابیس ارسال میشود.

حالا چرا این دو را از هم جدا کنیم؟

۱. باعث میشود CRUD-based Thinking انجام ندهیم، و بیشتر به سمت Task-based Thinking برویم، برای مثال یک متدی داریم به نام CreateStudent این نام گذاری در گروه CRUD-based قرار میگیرد، ولی حالا نام این متد را به RegisterStudent تغییر میدهیم، اینطوری Task-based Thinking انجام دادیم.
۲. باعث افزایش Security, Performance, Scalability میشود.
۳. باعث کاهش Complexity در پروژه ها میشود، چون Query Model ها از Command model ها جدا میشوند و در نتیجه هر مدلی وظیفه خاص خود را دارد.
۴. باعث میشود اصل SRP در سطح معماری پیاده سازی شود.

همچنین این الگو، الگوی CQS را توسعه داده است.از این الگو در میتوانیم در هر دو معماری Monolithic و Microservices استفاده کنیم.

الگوی Event Sourcing

در بیشتر مواقع ما همیشه اخرین وضعیت یک Domain Entity را در دیتابیس ذخیره میکنیم، برای مثال فرض کنید که میخواهیم اطلاعات کاملی از سبد های خرید کاربران جمع کنیم.

  • چه محصولی در چه زمانی به سبد اضافه شد ؟
  • چه محصولی در چه زمانی از سبد خرید حذف شد؟
  • هر محصول چه مدت زمانی در سبد خرید کاربر مانده است؟
  • کدام محصول که در سبد خرید کاربر مانده بود به جدول Order Line Item راه پیدا کرد؟

الگوی Event Sourcing به ما اجازه میدهد که تمامی Action های صورت گرفته بر یک دیتا را به صورت سریالی ذخیره کنیم. در این الگو از عملیات UPDATE و DELETE استفاده نمیکنیم، فقط INSERT هایی داریم که Atomic هستند.همچنین در بیشتر مواقع از این الگو در کنار الگوی Saga استفاده میکنیم.

الگوی Saga

اولین الگویی که یاد گرفتیم Database per-service بود و این الگو ما را تشویق میکرد که برای هر مایکروسرویس یک دیتابیس شخصی و مناسب داشته باشیم، حالا که دیتابیس ها به صورت Distributed هستند و قابلیت استفاده از ACID Transaction ها را نداریم باید چه کنیم؟
مدیریت Transaction ها در معماری Microservices کمی پیچیده و چالش برانگیز است، برای اینکه بتوانیم Transaction ها را بین چند Microservice پیاده سازی کنیم و ثبات داده ها را حفظ کنیم باید از الگوی Saga استفاده کنیم.Saga لیستی از ACID Transaction ها است.

برای مثال فرض کنید که میخواهیم یک بلیط هواپیما بخریم.

۱. در ابتدا پرواز مورد نظرمان را بر اساس مبدا و مقصد و تاریخ انتخاب میکنیم.
۲. در این مرحله باید اطلاعات مسافران را وارد کنیم.
۳. در این مرحله اطلاعات مسافران به یک مایکروسرویسی ارسال میشود که آن ها را در یک دیتابیس Relational ذخیره کند، حالا این ذخیره کردن باید در قالب یک Transaction انجام شود، و باید مایکروسرویس مربوطه حتما خبر بدهد که آیا عمل ذخیره شدن با موفقیت انجام شد یا نشد.
۴. در این مرحله مایکروسرویس خبر میدهد که Transaction انجام شده است یا خیر، اگر انجام نشده باشد همانجا Saga عملیات را متوقف میکند و دستورات بعدی را به دیگر مایکرسرویس ها نمی فرستد و اگر انجام شده باشد یک Event توسط همان مایکروسرویس که وظیفه ثبت اطلاعات مسافران را داشت توسط Message Broker منتشر میشود و در آن Event یک OrderId به آن مسافران تخصیص میشود تا به دست سرویس بعدی یعنی Payment برسد.
۵. حالا که عملیات ثبت با موفقیت انجام شد، کاربر اقدام به پرداخت هزینه بلیط ها میکند، وقتی که کاربر وارد صفحه درگاه بانکی شود همانجا یک درخواست از طرف مایکروسرویس Payment به سمت سرویس های Reservation می رود و آن سرویس ها برای مسافران مورد نظر صندلی هایی را رزرو میکنند، حال اگر کاربر هزینه را پرداخت کند، Saga دستور بعدی یعنی صادر کردن بلیط ها را به دیگر مایکروسرویس ها میفرستد، و اگر پرداختی انجام نشود دستور لغو Reservation را میدهد و تمامی تراکنش های انجام شده Undo میشوند.

الگوی Saga به طور کلی به ۲ صورت پیاده سازی میشود:

روش اول که Choreography نام دارد که هر مایکروسرویس به ازای هر Transaction یک Domain Event ای از طرف خودش Publish میکند که باعث میشود مایکروسرویس های هدف آن را دریافت کنند و Transaction های خودشان را اجرا کنند.
روش دوم که Orchestration نام دارد که در آن یک کنترل کننده وجود دارد و به ترتیب به مایکروسرویس ها میگوید که کار مربوطه شان را در یک Transaction محلی انجام دهند.

ضد الگوی Shared Database

ضد الگوی Shared Database زمانی اتفاق می افتد که الگوی Database-per-Service را پیاده سازی نکنیم و در چند مایکروسرویس از یک دیتابیس استفاده کنیم.وقتی از یک Shared Database استفاده میکنیم، میتوانیم از ACID Transaction ها بهره ببریم، ولی اینکار علیه طبیعت معماری مایکروسرویس ها است و باعث بروز مشکلات زیادی در آینده میشود.

۱. قابلیت Maintainability مایکروسرویس های شما پایین می آید.
۲. در اخر با یک معماری distributed monolith مواجه می شوید.
۳. قابلیت Independent scalability را در دیتابیس ها و مایکروسرویس ها نخواهید داشت.
۴. دیتابیس شما Single point of failure مایکروسرویس هایتان میشود.

برای اینکه بتوانیم از معماری مایکروسرویس ها بهره ببریم بهتر است که حتما از الگوی Database-per-Service استفاده کنیم.
معماری مایکروسرویس ها به ما اجازه میدهد که برای هر مایکروسرویس یک دیتابیس مناسب انتخاب کنیم یا به زبان دیگر به ما اجازه میدهد که Polyglot Persistence داشته باشیم، هر تیمی میتواند دیتابیس مورد نیاز خودش را انتخاب و استفاده کند.
برای مطالعه بیشتر در مورد Polyglot Persistence از مقاله آقای Martin Fowler می توانید استفاه کنید.

چه رتبه ای می‌دهید؟

میانگین ۳.۸ / ۵. از مجموع ۴

اولین نفر باش

title sign
دانلود مقاله
چگونه پایگاه داده‌ها را در Microserviceها مدیریت کنیم؟
فرمت PDF
11 صفحه
حجم 1 مگابایت
دانلود مقاله
title sign
معرفی نویسنده
تیم فنی نیک آموز
مقالات
402 مقاله توسط این نویسنده
محصولات
0 دوره توسط این نویسنده
تیم فنی نیک آموز
title sign
دیدگاه کاربران