Skip to content

فصل ۶ — جداسازی دادهٔ عملیاتی

خلاصهٔ تحلیلی — این متن برداشت و سازمان‌دهی مفاهیم فصل به زبان فارسی است، نه ترجمهٔ واژه‌به‌واژه.

مسئله و زمینه

تفکیک سرویس‌ها بدون بازاندیشی در داده، اغلب فقط یک «مونولیت توزیع‌شده» می‌سازد: سرویس‌ها جدا deploy می‌شوند، اما همگی به یک مدل و یک پایگاه‌دادهٔ مشترک گره خورده‌اند. داده حساس‌ترین دارایی کسب‌وکار است و بریدن آن از کد دشوارتر است؛ زیرا جدول‌ها علاوه بر وابستگی منطقی، با کلید خارجی، view، trigger، procedure و تراکنش به هم متصل‌اند.

هدف فصل این نیست که «database-per-service» را قانون همگانی اعلام کند. پرسش درست این است که کدام فشارها جداسازی را توجیه می‌کنند و کدام فشارها نگه‌داشتن داده در کنار هم را. معماری خوب، مرز bounded context را با مسئولیت نوشتن و نیازهای عملیاتی سازگار می‌کند.

مفاهیم و الگوهای محوری

نیروهای جداساز و یکپارچه‌ساز

دلایل اصلی جداسازی داده عبارت‌اند از:

  • کنترل تغییر: تغییر ناسازگار در schema مشترک همهٔ مصرف‌کنندگان را هم‌زمان درگیر می‌کند. سرویس مالک، با قرارداد API جدا از schema داخلی، اثر این تغییر را محصور می‌سازد.
  • مدیریت اتصال و مقیاس: هر instance سرویس pool خودش را دارد؛ رشد instanceها می‌تواند اتصال‌های یک پایگاه مشترک را اشباع کند. quota اتصال، راه مهار موقت است، نه جایگزین تفکیک درست.
  • تاب‌آوری و quantum معماری: پایگاه مشترک نقطهٔ شکست مشترک و بخشی از coupling ایستا است؛ جداسازی می‌تواند خرابی را به یک دامنه محدود کند.
  • تناسب نوع پایگاه‌داده: همهٔ داده‌ها رفتار یکسان ندارند؛ حفظ اجباری همه در RDBMS ممکن است برای دادهٔ کلید-مقدار، سندی، گراف یا سری زمانی نامناسب باشد.

در برابر این نیروها، رابطهٔ داده‌ها و تراکنش واحد ACID دلیل مهمی برای نزدیک نگه‌داشتن جدول‌ها هستند. اگر جداسازی، foreign key و invariants حیاتی را می‌شکند یا یک فرایند کسب‌وکاری واقعاً به commit/rollback واحد نیاز دارد، هزینهٔ تفکیک می‌تواند از سود آن بیشتر شود.

فرایند تکاملی پنج‌مرحله‌ای

  1. database و وابستگی‌های آن را تحلیل و data domainها را پیدا کنید: مجموعه‌ای از جدول‌ها و artifactهای وابسته که در یک حوزهٔ محدود با هم استفاده می‌شوند.
  2. جدول‌ها و artifactهای هر domain را به schema منطقی خودش منتقل کنید. synonym فقط پلی موقت برای دیدن وابستگی‌هاست، نه مرز نهایی.
  3. اتصال هر سرویس را به domain خودش محدود کنید؛ نیاز به دادهٔ بیرونی باید از سرویس مالک عبور کند، نه با query مستقیم بین schemaها.
  4. schemaهای تثبیت‌شده را به سرورهای مستقل ببرید: backup/restore ساده‌تر ولی مستلزم downtime است؛ replication downtime را کم می‌کند اما هماهنگی بیشتری می‌خواهد.
  5. اتصال قدیمی و schemaهای باقیمانده را حذف کنید تا واحدهای deploy و عملیات واقعاً مستقل شوند.

خروجی مطلوب، حاکمیت داده به‌ازای سرویس است: سرویس می‌تواند schema و فناوری ذخیره‌سازی خود را تغییر دهد، اما بهای آن دسترسی دشوارتر به حجم زیاد دادهٔ بیرونی، از دست‌رفتن referential integrity میان دامنه‌ها، و انتقال منطق stored procedureهای بین‌دامنه‌ای به لایهٔ سرویس است.

انتخاب فناوری ذخیره‌سازی

انتخاب محصول از نام فناوری آغاز نمی‌شود؛ از workload و مدل دسترسی آغاز می‌شود: منحنی یادگیری، مدل‌سازی، read/write throughput، availability/partition tolerance، consistency، بلوغ ابزار و مهارت تیم را کنار هم بسنجید.

  • رابطه‌ای: SQL و ACID، مدل‌سازی آشنا و workload متعادل؛ در مقیاس افقی و partition tolerance معمولاً پرهزینه‌تر است.
  • Key-value و document: aggregate-oriented، مناسب بازیابی با کلید یا سندهای انعطاف‌پذیر؛ طراحی مرز aggregate و الگوی query پیش از انتخاب حیاتی است.
  • Column family: برای حجم بالای read/write و دادهٔ sparse مناسب، اما طراحی row key و مدل ذهنی آن تخصص می‌خواهد.
  • Graph: برای پیمایش رابطه‌ها ارزشمند است، ولی مدل‌سازی و shard کردن graph دشوارتر است.
  • NewSQL: تلاش برای جمع‌کردن SQL/ACID با scale افقی؛ پیچیدگی را حذف نمی‌کند، بلکه بخشی از آن را به پلتفرم می‌سپارد.
  • Cloud-native و time-series: اولی بار عملیاتی را با هزینه و وابستگی سرویس‌دهنده مبادله می‌کند؛ دومی برای رویدادهای timestampدار و append-oriented است، نه ذخیره‌سازی عمومی.

موازنه‌ها

  • استقلال schema و استقرار در برابر حفظ رابطه‌ها و تراکنش محلی.
  • availability و scale مستقل در برابر هزینهٔ انتقال، همگام‌سازی و احتمال ناسازگاری داده.
  • polyglot persistence در برابر هزینهٔ مهارت، عملیات، governance و ابزارهای متعدد.
  • aggregate یکپارچه در document store، خواندن و render ساده‌تری می‌دهد؛ aggregateهای شکسته reuse را بالا می‌برند، اما جمع‌کردن و تغییر آن‌ها را پیچیده‌تر می‌کنند.

راهنمای عملی

  1. پیش از migration، dependency map واقعی بسازید: چه کسی می‌خواند، چه کسی می‌نویسد، و کدام artifactهای database مرزها را می‌شکنند.
  2. محرک‌ها را با معیارهای قابل مشاهده اثبات کنید: connection wait، blast radius خرابی، نرخ تغییر schema و الگوی بار؛ صرف «میکروسرویس بودن» توجیه نیست.
  3. ابتدا schemaهای منطقی را جدا کنید، سپس اتصال‌ها را محدود کنید، و فقط پس از تثبیت مرزها سراغ سرورهای مستقل بروید.
  4. قرارداد سرویس را از طرح جدول جدا نگه دارید تا تغییر نام ستون یا نوع داده به مصرف‌کننده نشت نکند.
  5. برای هر domain، نوع داده، الگوی query، حجم، نرخ تغییر، SLA consistency و توان تیم را مستند کنید؛ سپس انتخاب فناوری را در ADR ثبت کنید.

نکات کلیدی فصل

  • پایگاه‌دادهٔ مشترک می‌تواند استقلال deploy سرویس‌ها را خنثی کند.
  • جداسازی داده یک migration مرحله‌ای و مشترک میان تیم نرم‌افزار و DBA است، نه صرفاً انتقال جدول.
  • مرز داده باید همزمان با مرز مسئولیت نوشتن و نیازهای تراکنشی طراحی شود.
  • «بهترین database» وجود ندارد؛ تطبیق مدل داده و trade-off با مسئله مهم است.

یادداشت‌های مترجم

  • اصطلاح‌های bounded context، schema، aggregate، ACID و polyglot persistence برای حفظ دقت مفهومی لاتین نگه داشته شده‌اند.
  • «حاکمیت داده» در این متن معادل data sovereignty است، نه مالکیت حقوقی داده.