دربارهٔ این فصل
یادداشتِ همراه نوارتا حالا به این فکر کردهاید که وقتی در یک پیامرسان پیامی میفرستید، چطور همزمان روی گوشی دوستانتان، نسخه وب و سرورهای مختلف ظاهر میشود و اگر یکی از این سرورها از کار بیفتد، چطور اطلاعات ما گم نمیشود؟ نگه داشتن کپیهای یکسان از دادهها روی چند ماشین مختلف که از طریق شبکه به هم وصل هستند، کار سادهای نیست چون تغییر دادن مداوم این دادهها چالشهای پیچیدهای میسازد. در کتاب «طراحی برنامههای دادهگرا» نوشتهٔ «مارتین کلپمن»، فصل پنجم به موضوع مهم تکثیر (Replication) میپردازد و نشان میدهد چطور میتوان دادهها را در چند گره مختلف مدیریت کرد تا سیستم در برابر خرابیها مقاومت کند.
نخستین و رایجترین روش، معماری رهبر/پیرو (Leader/Follower) است که در آن، یک گره به عنوان رهبر تمام درخواستهای نوشتن را میپذیرد و بقیه گرهها به عنوان پیرو، تغییرات را از رهبر میگیرند تا نسخهای مشابه داشته باشند. برای مثال، در بسیاری از پایگاههای داده رابطه ای، کاربران برای ثبت اطلاعات جدید باید به رهبر مراجعه کنند و پیروان فقط خواندن دادهها را انجام میدهند. انتخاب بین تکثیر همگام (Synchronous) و ناهمگام (Asynchronous) در اینجا یک معامله حیاتی است. در حالت همگام، رهبر تا تأییدیه پیرو را نگیرد به کاربر پاسخ موفقیت نمیدهد که امنیت داده را بالا میبرد، اما اگر آن پیرو قطع شود، کل سیستم متوقف میشود. به همین دلیل بیشتر سیستمها از حالت ناهمگام استفاده میکنند تا کارایی حفظ شود، هرچند اگر رهبر پیش از ارسال تغییرات به پیروان سقوط کند، مقداری از دادهها از دست میرود.
دومین مسئله، نحوهٔ مدیریت قطعی گرهها و فرآیند جایگزینی است. اگر یک پیرو موقتاً از دست برود، پس از اتصال مجدد میتواند از روی لاگ تغییرات، عقبافتادگی خود را جبران کند اما اگر رهبر خراب شود، ماجرای failover پیش میآید که در آن یکی از پیروان باید به رهبر تبدیل شود. این فرآیند خودکار خطراتی مثل تقسیم مغز (Split Brain) دارد؛ حالتی که در آن دو گره همزمان فکر میکنند رهبر هستند و دادهها مخدوش میشوند. به عنوان نمونهای از خطرات عملی، در یک اتفاق واقعی در گیتهاب، ترویج یک پیرو که عقب مانده بود باعث شد شناسههای اصلی تکراری تولید شوند و ناسازگاری به وجود بیاید.
سومین ایده، بروز پدیدهٔ تاخیر تکثیر (Replication Lag) در خواندن از پیروان ناهمگام است که تناقضهای موقتی ایجاد میکند. وقتی دادهها هنوز به پیرو نرسیده باشند، کاربری که اطلاعات خود را بلافاصله پس از ثبت میخواند ممکن است فکر کند دادههایش گم شدهاند که به آن خواندن نوشتنهای خود (Read-Your-Writes) میگویند. برای حل این مشکل، برنامهنویسان گاهی مجبورند خواندن پروفایل خود کاربر را مستقیماً از رهبر انجام دهند و بقیه خواندنها را به پیروان بسپارند تا کاربر احساس نکند زمان به عقب برگشته است.
چهارمین رویکرد، استفاده از چند رهبر (Multi-Leader) است که به درد سناریوهایی مانند چند دیتاسنتر مختلف میخورد تا هر دیتاسنتر بتواند به صورت محلی نوشتنها را بپذیرد و بعداً با بقیه همخوان شود. بزرگترین چالش در این روش، بروز تضاد نوشتن همزمان در دو جای مختلف است؛ مثلاً اگر دو نفر عنوان یک صفحه را در دو دیتاسنتر مختلف همزمان تغییر دهند، دیتابیس باید راهی برای همگرا کردن وضعیت پیدا کند. برخی سیستمها از آخرین نوشتن برنده است (Last Write Wins) استفاده میکنند که با مقایسه زمانسنجها یکی را نگه میدارد، اما این روش خطر جدی از دست رفتن دادهها را به همراه دارد.
پنجمین مدل، معماری بدون رهبر (Leaderless) است که در آن کلاینتها مستقیماً درخواست نوشتن یا خواندن را به چند گره به صورت موازی میفرستند تا به حد نصاب کووروم (Quorum) برسند. در این حالت اگر مجموع تعداد گرههای نوشتن و خواندن از تعداد کل گرهها بیشتر باشد، سیستم تضمین میکند که همیشه دادهٔ بهروز خوانده میشود. با این حال، پدیدههایی مانند خواندن مقادیر کهنه همچنان ممکن است رخ دهند و برای مهار تناقضها، الگوریتمهای پیشرفتهای نیاز است تا مشخص شود کدام عملیات قبل از دیگری رخ داده است.
پیشنهاد شخصی من این است که تا جای امکان از پیچیدگیهای تکثیر چند رهبری یا بدون رهبر دوری کنید، مگر اینکه مقیاس جغرافیایی یا قطع ارتباط اینترنت واقعاً شما را مجبور به این کار کند. در بیشتر پروژهها، استفاده از معماری سادهتر با یک رهبر قابل اعتماد، زندگی مهندسی شما را بسیار آرامتر خواهد کرد.
امیدوارم این بخش از بررسی کتاب به شناخت بهتری از ساختارهای توزیعشده کمک کرده باشد. تا اپیزود بعدی، پیروز و پایدار باشید.