حالت تاریک
فصل ۱۰ — دسترسی به داده در معماری توزیعشده
خلاصهٔ تحلیلی — این متن توضیحی مستقل از مفاهیم فصل است، نه ترجمهٔ واژهبهواژه.
مسئله و زمینه
در مونولیت، خواندن دادهٔ مرتبط معمولاً یک join است. پس از برقراری ownership و bounded context، سرویس دیگر نباید مستقیم جدول همسایه را بخواند؛ اما همچنان برای پاسخ به درخواست خود به بخشی از آن داده نیاز دارد. این فصل چهار راه برای حل «دسترسی خواندنی به دادهٔ غیرمالک» را مقایسه میکند.
نقطهٔ شروع، کیفیت مورد نیاز خواندن است: آیا داده باید همان لحظه تازه باشد؟ حجم آن چقدر است؟ نرخ تغییر چقدر است؟ latency و availability چه SLAیی دارند؟ و آیا schema مشترک یا replica، امنیت و ownership را قابلقبول نگه میدارد؟ انتخاب protocol بهتنهایی مسئله را حل نمیکند.
مفاهیم و الگوهای محوری
۱) ارتباط میانسرویسی
سرویس مصرفکننده از owner با REST، gRPC یا پیام request-reply داده میخواهد. از نظر ذهنی ساده و از نظر حجم داده منعطف است، زیرا copy محلی نمیسازد. اما در هر درخواست latency شبکه، authorization و query مقصد جمع میشود. سرویس خواننده به availability و scale سرویس مالک وابسته است؛ بنابراین dependency معنایی و عملیاتی به وجود میآید و contract بین دو طرف لازم است.
این انتخاب برای خواندن کمحجم و کمتکرار، یا جایی که freshness لحظهای مهمتر از استقلال عملیاتی است، معقولتر است؛ نه برای algorithmی که در هر درخواست بارها دادهٔ بیرونی را میخواهد.
۲) تکثیر ستون در schema
مصرفکننده ستونهای موردنیاز را در جدول خود نگه میدارد. query محلی سریع است، سرویسها مستقل scale میشوند و خرابی owner مانع ادامهٔ خواندن نیست. در عوض، تغییرات owner باید با event، queue یا stream به replicaها برسد؛ داده میتواند موقتاً قدیمی شود و باید جلوی write ناخواستهٔ مصرفکننده روی copy را گرفت.
این الگو در reporting، aggregation، نیازهای response بسیار سریع یا fault tolerance بالا قابل بررسی است، ولی برای دادهای که باید فوراً و دائماً دقیق بماند، هزینهٔ synchronization و governance میتواند نامناسب باشد.
۳) replicated in-memory cache
هر service instance نسخهٔ in-memory دادهٔ موردنیاز را دارد و تنها owner مجاز به تغییر cache اصلی است؛ updateها در پسزمینه به replicaهای read-only پخش میشوند. برخلاف distributed cache متمرکز، dependency به یک cache server خارجی و latency remote call حذف میشود. پس از پرشدن cache، مصرفکننده حتی با down شدن owner نیز میتواند کار کند و مستقل scale شود.
محدودیتها روشناند:
- نخستین instance مصرفکننده برای bootstrap به owner یا instance پرشدهٔ دیگر وابسته است.
- دادهٔ بزرگ، با ضرب در تعداد instanceها، memory مصرف میکند.
- دادهٔ پرنوسان ممکن است پیش از رسیدن update بعدی ناسازگار باشد.
- discovery و network configuration در cloud/container محیطی پیچیدهتر است.
پس cache replicated گزینهٔ خوب برای دادهٔ کمحجم، نسبتاً ایستا و پرتکرار است، نه شمارندههای با update زیاد.
۴) data domain مشترک
آخرین گزینه قرار دادن جدولهای لازم در یک schema مشترک است تا سرویسها با SQL محلی و join به داده برسند. این راه latency، dependency سرویس و مشکل scale/throughput تماس راهدور را حذف و foreign key، view و trigger را ممکن میکند. داده هم نیاز به replication ندارد.
اما contract اکنون همان schema است؛ تغییر ستون ممکن است چند سرویس را درگیر کند. bounded context گستردهتر میشود، governance مالکیت write اهمیت مییابد و دسترسی کامل سرویسها میتواند ریسک امنیتی ایجاد کند. این الگو «شکست معماری» نیست، ولی باید با آگاهی از استقلالی که واگذار میشود انتخاب شود.
موازنهها
| هدف غالب | گرایش مناسب | هزینهای که میپذیرید |
|---|---|---|
| سادگی و دادهٔ کاملاً تازه | ارتباط میانسرویسی | latency و وابستگی availability |
| پاسخ سریع از دادهٔ محلی | تکثیر schema | synchronization و consistency نهایی |
| خواندن پرتکرار، کوچک و کمتغییر | replicated cache | bootstrap، memory و پیچیدگی پیکربندی |
| integrity محلی و حجم/تازگیِ نامناسب برای cache | data domain | مرز دامنهٔ وسیعتر و coupling schema |
راهنمای عملی
- نیاز read را بهطور دقیق بنویسید: subset داده، نرخ درخواست، اندازهٔ کل، نرخ update، حداکثر data staleness و رفتار قابلقبول هنگام خرابی owner.
- ارتباط میانسرویسی را baseline ساده بدانید، سپس با اندازهگیری latency و fan-out ثابت کنید که کافی است یا نه.
- در تکثیر یا cache، owner یگانهٔ write، event تغییر، handling پیام تکراری/نامرتب و مسیر بازیابی cache را تعیین کنید.
- برای cache، memory budget را با «اندازهٔ داده × بیشترین تعداد instance» محاسبه کنید و startup order را در deployment طراحی کنید.
- data domain را فقط پس از ردشدن راههای دیگر با دلیل روشن انتخاب کنید؛ دسترسی read/write و تغییر schema را governance کنید.
- پیش از تصمیم نهایی، PoC سازگار با محدودیتهای licensing، availability zone، firewall و container discovery اجرا کنید.
نکات کلیدی فصل
- ownership داده به معنای انحصار write است، نه منع مطلق خواندن؛ خواندن باید از الگوی معماری مناسب عبور کند.
- روش سریعتر معمولاً state محلی بیشتری میخواهد و در نتیجه مسئلهٔ sync و freshness ایجاد میکند.
- cache replicated راهحل عمومی cache نیست؛ اندازه و volatility داده مرز کاربردش را تعیین میکنند.
- data domain مشترک performance و integrity را بهبود میدهد، اما استقلال schema و security boundary را کاهش میدهد.
یادداشتهای مترجم
- نام الگوها (
Interservice Communication،Replicated CacheوData Domain) برای تطبیق با ادبیات معماری بهصورت لاتین در متن آمدهاند. - جدول این خلاصه، جمعبندی تحلیلی trade-offهای فصل است و نقلقول از متن منبع نیست.