Cy Logic Insights

عملیات توزیع‌شده و سازگاری داده‌ها در معماری میکروسرویس

برای تضمین سازگاری داده‌ها در نرم‌افزارهای مالی که به معماری میکروسرویس مهاجرت می‌کنند، پروتکل تایید دو مرحله‌ای و الگوی آوت‌باکس را بررسی می‌کنیم.

عملیات توزیع‌شده و سازگاری داده‌ها در معماری میکروسرویس

مقدمه و تحول معماری

ساختارهای سازمانی به منظور مقیاس‌پذیر ساختن فرآیندهای کسب‌وکار، از ساختارهای یکپارچه (مونولیتیک) به رویکرد معماری میکروسرویس مهاجرت می‌کنند. به ویژه جداسازی ماژول‌های بحرانی مانند سیستم‌های مالی و حسابداری، ضمن فراهم کردن ایزوله‌سازی خطا، چالش‌های فنی جدیدی را در زمینه عملیات توزیع‌شده (distributed transactions) به همراه دارد.

چالش‌های اساسی در عملیات توزیع‌شده

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

پروتکل تایید دو مرحله‌ای (2PC)

یکی از روش‌های کلاسیک مورد استفاده برای حفظ اتمیسیته در سیستم‌های توزیع‌شده، مکانیزم تایید دو مرحله‌ای است. این پروتکل از دو فاز تشکیل شده است:

  • فاز آماده‌سازی (Prepare Phase): سرویس هماهنگ‌کننده از تمام سرویس‌های شرکت‌کننده می‌پرسد که آیا عملیات می‌تواند تکمیل شود یا خیر. شرکت‌کنندگان منابع را قفل کرده و آمادگی خود را اعلام می‌کنند.
  • فاز تایید (Commit Phase): اگر تاییدیه از تمام سرویس‌ها دریافت شود، عملیات دائمی می‌شود؛ در غیر این صورت، تمام تغییرات به حالت قبل بازگردانده می‌شوند (rollback).

معایب 2PC

نرم‌افزارهای مالی به هم‌روندی بالا نیاز دارند. پروتکل 2PC به دلیل مدت زمان قفل کردن (locking) و تاخیرهای شبکه می‌تواند باعث بروز گلوگاه‌های عملکردی در کل سیستم شود. در صورت خرابی سرویس هماهنگ‌کننده نیز قفل ماندن سرویس‌های شرکت‌کننده یک عامل ریسک بزرگ محسوب می‌شود.

رویکرد ناهمگام با الگوی Outbox

الگوی Outbox یک راه حل ناهمگام است که برای از بین بردن هزینه‌های قفل‌گذاری ناشی از پروتکل تایید دو مرحله‌ای طراحی شده است. در این مدل، تراکنش پایگاه داده اصلی و رویدادی (event) که قرار است به بیرون ارسال شود، در یک تراکنش محلی مشترک در جدول آوت‌باکس نوشته می‌شوند.

مراحل اجرایی Outbox

  1. تراکنش محلی: سرویس، قاعده کسب‌وکار را در پایگاه داده خود اعمال می‌کند و همزمان در همان تراکنش، یک رکورد پیام به جدول آوت‌باکس اضافه می‌نماید.
  2. ارسال رویداد: یک فرآیند جداگانه (اسکنر پس‌زمینه یا ابزار CDC - Change Data Capture)، رکوردهای خوانده‌نشده را از جدول آوت‌باکس خوانده و به صف پیام (Message Broker) منتقل می‌کند.
  3. پاکسازی: پیام‌هایی که با موفقیت ارسال شده‌اند، از جدول آوت‌باکس حذف شده یا علامت‌گذاری می‌گردند.

انتخاب رویکرد صحیح

هنگام طراحی عملیات توزیع‌شده، الزامات تجاری سیستم باید به دقت تحلیل شوند. در حوزه‌های حساسی که به همگام‌سازی زمان واقعی نیاز دارند پروتکل‌های دستوری ارزیابی می‌شوند، در حالی که در پروژه‌های نرم‌افزارهای مالی که در آن‌ها عملکرد و مقیاس‌پذیری در اولویت قرار دارد، الگوی آوت‌باکس که سازگاری نهایی (eventual consistency) را فراهم می‌کند یک گزینه امن‌تر ارائه می‌دهد.

مثال کاری فرضی: جریان پرداخت تجارت الکترونیک

در سناریوی ما، فرض کنید مشتری از طریق یک ماژول سفارش که با زیرساخت سیستم‌های مالی و حسابداری یکپارچه شده است، پرداختی را انجام می‌دهد. سرویس سفارش پس از ایجاد سفارش، درخواستی را به سرویس پرداخت ارسال می‌کند و سرویس حسابداری نیز رکورد درآمد را پردازش می‌نماید. در این فرآیند با استفاده از الگوی Outbox از قفل شدن پایگاه داده جلوگیری می‌شود. سرویس سفارش هنگام نوشتن داده در جدول سفارش، همزمان در همان بلوک تراکنش، یک رویداد 'OrderCreated' را نیز به جدول Outbox اضافه می‌کند. یک مکانیزم Change Data Capture (CDC) که در پس‌زمینه کار می‌کند، این جدول را به طور مداوم اسکن کرده و رکوردهای جدید را به یک صف پیام مانند کافکا یا رابی‌ام‌کیو منتقل می‌کند. سرویس پرداخت با مصرف این پیام، عملیات کاهش موجودی خود را انجام می‌دهد. اگر سرویس پرداخت موقتاً غیرقابل دسترس شود، داده‌های منتظر در صف پیام، سیستم را قفل نمی‌کنند؛ بلکه مکانیسم صف، سیاست‌های تلاش مجدد (retry) را فعال می‌کند. به این ترتیب، سیستم در برابر قطعی‌های لحظه‌ای شبکه یا توقف سرویس‌ها مقاومت کسب می‌کند، در حالی که بر اساس اصل سازگاری نهایی، تمام سرویس‌ها به شکلی همگام به نسخه به‌روز داده دسترسی پیدا می‌کنند. این معماری هرچند بار عملیاتی را افزایش می‌دهد، اما زمان پاسخگویی سیستم را حتی تحت ترافیک بالا بهینه می‌کند.

چک‌لیست دقیق اجرا و مدیریت خطا

برای ایجاد یک ساختار پایدار در معماری‌های توزیع‌شده، اجرای کامل مراحل مهندسی خاصی ضروری است. ابتدا، مکانیسم تکرارپذیری (Idempotency) باید به طور حتم در عملیات پایگاه داده طراحی شود. در برابر احتمال دریافت چندین باره یک رویداد از صف‌های پیام، هر عملیات پردازش‌شده باید با یک کلید منحصر به فرد کنترل شود. دوم، پیام‌های خوانده‌شده از جدول Outbox پس از انتقال به صف باید به طور ایمن حذف شوند یا به عنوان 'پردازش شده' علامت‌گذاری گردند تا از تکرار داده‌ها جلوگیری شود. در مرحله مدیریت خطا، ساختار صف نامه مرده (DLQ) باید راه‌اندازی شود؛ پیام‌هایی که در تلاش‌های متوالی ناموفق بوده‌اند باید در اینجا جمع‌آوری شده و تحت بررسی دستی قرار گیرند. مدیران سیستم باید زمان‌های تاخیر و اندازه‌های صف را به صورت لحظه‌ای در این فرآیندها که برای نرم‌افزارهای مالی حیاتی هستند، نظارت کنند. علاوه بر این، قابلیت اجرای الگوی SAGA برای عملیات جبرانی (compensating transactions) باید ارزیابی شود و کتابخانه‌های قطع‌کننده مدار (circuit breaker) برای سناریوی پارتیشن شبکه (network partition) و مهلت زمانی (timeout) ادغام گردند. این چک‌لیست خطر از دست رفتن داده‌ها را در طول عملیات توزیع‌شده به حداقل می‌رساند.

منابع