وقتی سفارش ثبت شده ولی صفحه هنوز آن را نشان نمیدهد
در یک فروشگاه، کاربر سفارش میسازد و بلافاصله به صفحه جزئیات آن میرود. نوشتن موفق بوده است، اما صفحه گاهی میگوید سفارش وجود ندارد. اگر سامانه برای نوشتن به نمونه اصلی PostgreSQL و برای خواندن به یک replica وصل شود، یکی از توضیحات ممکن عقب بودن replica است. این رخداد لزوماً به معنای حذف سفارش نیست. مسیر اتصال برنامه و زمان رسیدن تغییر را باید با هم بررسی کرد. CloudNativePG مدیریت نمونهها و سرویسهای PostgreSQL را در Kubernetes بر عهده میگیرد، اما انتخاب مسیر مناسب برای هر خواندن همچنان تصمیم برنامه است.
برای بررسی این مثال، سه مسئله جداگانه مطرح است. نخست اینکه داده روی کدام نمونه پذیرفته شده، دوم اینکه تغییر تا چه مرحلهای روی نمونه دیگر پیش رفته و سوم اینکه درخواست بعدی کاربر به کدام نقطه رسیده است. اگر فقط تعداد پادهای آماده را نگاه کنیم، هیچکدام از این سه پرسش پاسخ کامل نمیگیرند. معماری درست از قراردادی شروع میشود که برنامه درباره تازگی داده، امکان نوشتن و رفتار هنگام قطع اتصال با پایگاه داده دارد.
مدیریت وضعیت و نقش اپراتور
در Kubernetes میتوان خواستهای مانند تعداد نمونههای یک کلاستر PostgreSQL را در منبع Cluster بیان کرد. اپراتور وضعیت مشاهدهشده را با تعریف آن مقایسه میکند و برای نزدیک کردن شرایط واقعی به خواسته اعلامشده اقدام میکند. اما خود PostgreSQL همچنان مسئول تراکنش، سازگاری داده و تکثیر تغییرات است. اپراتور با مدیریت چرخه عمر نمونهها کمک میکند وظایف تکراری عملیاتی قابل کنترل شوند. هیچ تنظیمی روی تعداد پادها بهتنهایی تضمین نمیکند همه نسخهها در لحظه یک داده یکسان در اختیار برنامه دارند.
برای مثال، یک کلاستر سهنمونهای را تصور کنید که روی یک میزبان فیزیکی اجرا میشود. سه پاد میتوانند سه فرایند مستقل داشته باشند، اما خاموش شدن آن میزبان هر سه را با هم از دسترس خارج میکند. برعکس، توزیع پادها روی میزبانهای مختلف هم وقتی همه حجمهای ذخیرهسازی به یک سامانه آسیبپذیر وابستهاند، تمام خطر را برطرف نمیکند. در طراحی باید مسیر برق، شبکه، کنترلپلین، گره اجرا و ذخیرهساز بررسی شود تا معلوم شود کدام خرابی واقعاً مستقل است.
WAL و مسیر رسیدن تغییر به replica
معماری CloudNativePG از قابلیت تکثیر فیزیکی PostgreSQL استفاده میکند. تغییرات پایگاه داده در WAL ثبت میشوند و نمونههای آمادهبهکار میتوانند این تغییرات را دریافت و بازپخش کنند. ثبت روی نمونه اصلی، انتقال روی شبکه و قابل مشاهده شدن نتیجه روی replica رویدادهای یکسانی نیستند. وقتی خواننده به یک replica وصل است، نتیجه پرسوجو به وضعیت بازپخش همان نمونه وابسته است. برای تحلیل تأخیر، زمان و موقعیت دریافت و بازپخش را با توجه به نسخه PostgreSQL و ابزار پایش بررسی کنید.
در تکثیر ناهمگام، سرعت پاسخ نوشتن کمتر به فاصله شبکه تا replica وابسته است، اما در خرابی ناگهانی نمونه اصلی ممکن است بخشی از تغییراتی که هنوز به نمونه دیگر نرسیدهاند در مقصد آماده نباشند. تکثیر همگام میتواند تعهد ثبت را به تأیید نمونههای تعیینشده پیوند دهد، ولی هزینه آن انتظار بیشتر یا کاهش امکان نوشتن هنگام از دست رفتن مسیر تأیید است. معنای دقیق تأیید به تنظیمات PostgreSQL بستگی دارد. انتخاب همگام را نباید بدون مشخص کردن سطح تعهد و مجموعه نمونههای واجد شرایط، معادل یک تضمین کلی برای تمام خواندنها دانست.
سه سرویس با کاربرد متفاوت
طبق راهنمای مدیریت سرویس CloudNativePG، سرویس rw به نمونه اصلی اشاره دارد و برای عملیات نیازمند نوشتن استفاده میشود. سرویس ro به replicaهای موجود اشاره میکند و سرویس r میتواند به هر نمونه مناسب، از جمله نمونه اصلی، برسد. نام پیشفرض از نام کلاستر و پسوند سرویس ساخته میشود. اگر نام کلاستر orders باشد، برنامه معمولاً مقصدهایی مانند orders-rw و orders-ro خواهد داشت. برنامه بهتر است این سرویسها را مصرف کند تا با جابهجایی نقشها وابسته به نشانی یک پاد مشخص نباشد.
تفاوت ro و r در شرایط کمبود ظرفیت مهم است. اگر گزارش سنگین را به r بسپارید، ممکن است بخشی از بار به نمونه اصلی برسد و با نوشتن رقابت کند. اگر آن را به ro بدهید، باید برای زمانی که replica در دسترس نیست رفتار مشخصی داشته باشید. بازگشت خودکار هر گزارش به نمونه اصلی میتواند مشکل اولیه را تشدید کند. در زمان طراحی تصمیم بگیرید کدام گزارش میتواند منتظر بماند، کدام خواندن باید تازه باشد و چه عملیاتی در وضعیت کاهش ظرفیت اجازه اجرا دارد.
مثال خواندن پس از نوشتن
برای مسیر ثبت سفارش، میتوان خواندن بلافاصله پس از نوشتن را به rw فرستاد و گزارشهای تحلیلی با تحمل تأخیر را روی ro اجرا کرد. این یک انتخاب در سطح برنامه است و باید با الگوی بار و نیاز کاربر سنجیده شود. مزیت آن روشن شدن انتظار هر مسیر است. کاربر پس از پرداخت معمولاً به اطلاعات تازه همان تراکنش نیاز دارد، اما نمودار فروش ساعتی احتمالاً میتواند اندکی تأخیر را تحمل کند. یک نام اتصال برای همه سناریوها این تفاوت را پنهان میکند.
در تمرین آزمایشگاهی، یک جدول کوچک با شناسه یکتای رویداد بسازید و از یک اتصال روی rw یک رکورد غیرحساس ثبت کنید. پس از پایان موفق تراکنش، همان شناسه را روی rw و ro جستوجو کنید و زمان مشاهده را ثبت کنید. این آزمایش را چند بار با فاصلهها و بارهای متفاوت تکرار کنید. نتیجه یک بار اجرا سقف تأخیر آینده را ثابت نمیکند، اما به شما نشان میدهد ابزار سنجش و منطق برنامه واقعاً مسیرهای متفاوت را از هم تشخیص میدهند. نام سرویس و شناسه درخواست را در گزارش آزمایش بیاورید.
توزیع نمونهها و شناخت حجم ذخیرهسازی
راهنمای معماری پروژه توزیع در چند ناحیه دسترسپذیری را برای کاهش وابستگی به یک نقطه خرابی بررسی میکند. در محیط داخلی نیز میتوانید همین منطق را با رکها، میزبانها و ذخیرهسازهای متفاوت تحلیل کنید، ولی نامگذاری یک برچسب بهتنهایی استقلال واقعی ایجاد نمیکند. اگر دو گره با برچسب ناحیه متفاوت به یک میزبان مجازیسازی یا یک مسیر شبکه مشترک متکی باشند، خرابی مشترک باقی میماند. قواعد زمانبندی را با نقشه واقعی زیرساخت تطبیق دهید.
به ارتباط حجم پایدار با محل اجرای پاد نیز توجه کنید. یک ذخیرهساز ممکن است فقط در ناحیه مشخصی قابل اتصال باشد یا انتقال آن به گره جدید زمان ببرد. آماده شدن پاد و آماده شدن پایگاه داده برای پذیرش کار دو مرحله جدا هستند. در آزمایش خرابی، زمان تشخیص، زمان آماده شدن نمونه مناسب و زمان اتصال دوباره برنامه را جدا اندازه بگیرید. اگر فقط زمان تغییر وضعیت یک شیء Kubernetes ثبت شود، ممکن است بخش بزرگی از وقفهای که کاربر تجربه کرده دیده نشود.
تغییر نقش و اتصالهای باز
بهروزرسانی مقصد یک Service برای اتصالهای جدید مفید است، اما نشست باز برنامه روی همان سوکت قبلی قرار دارد. هنگام از دست رفتن نمونه یا تغییر نقش، برنامه باید خطای اتصال را تشخیص دهد و اتصال تازه بگیرد. در سامانهای که از pool استفاده میکند، رفتار pool در برابر اتصال ناسالم اهمیت زیادی دارد. تنظیمات زمان انتظار و تعداد تلاش را بر اساس نوع عملیات انتخاب کنید تا یک خرابی کوتاه به انباشته شدن درخواستهای معلق و فشار بیشتر روی سرویس تبدیل نشود.
تکرار یک خواندن اغلب سادهتر از تکرار یک نوشتن است. اگر ارتباط بعد از ارسال درخواست ثبت سفارش قطع شود، برنامه ممکن است نداند تراکنش پذیرفته شده یا خیر. ارسال دوباره بدون شناسه یکتای عملیات میتواند سفارش تکراری بسازد. در طراحی عملی از شناسه درخواست و قید یکتایی مناسب استفاده کنید و پس از نتیجه نامشخص ابتدا وضعیت همان درخواست را بررسی کنید. این قرارداد به رفتار برنامه و مدل داده مربوط است و جابهجایی خودکار نمونه بهتنهایی آن را حل نمیکند.
مرز دسترسی شبکه و مجوز پایگاه داده
سرویسهای پیشفرض معمولاً از نوع ClusterIP هستند. اگر برنامهای روی ماشین مجازی بیرون Kubernetes باید وصل شود، راهنمای پروژه امکان تعریف سرویس اضافی را توضیح میدهد. نوع سرویس و دسترسی شبکه را بر اساس نیاز واقعی انتخاب کنید. یک LoadBalancer الزاماً به معنی اینترنت عمومی نیست؛ رفتار آن به محیط و تنظیمات ارائهدهنده بستگی دارد. مسیر خصوصی، محدودیت مبدأ، احراز هویت PostgreSQL و اعتبارسنجی گواهی باید در کنار هم بررسی شوند.
برای یک اتصال بیرونی، ابتدا مسئله را دقیق تعریف کنید. آیا برنامه قدیمی فقط به خواندن گزارش نیاز دارد یا باید تراکنش بنویسد؟ آیا راه ارتباط خصوصی میان ماشین و کلاستر وجود دارد؟ آیا تیم میتواند هویت گواهی ارائهشده را در برنامه اعتبارسنجی کند؟ پاسخ این سؤالها تعیین میکند کدام مقصد و چه حسابی لازم است. استفاده از یک حساب پرمجوز مشترک برای همه مصرفکنندگان، تشخیص خطا و محدود کردن پیامد افشای اعتبارنامه را دشوار میکند. حساب گزارشخوانی و حساب اجرای تغییرات ساختار داده معمولاً نیازهای متفاوت دارند.
تشخیص اختلال با آزمایشهای کوچک
اگر برنامه خطای فقطخواندنی دریافت کرد، پیش از تغییر مجوز به مقصد اتصال نگاه کنید. ممکن است درخواست نوشتن به سرویس replica فرستاده شده باشد. اگر اتصال برقرار نمیشود، وجود endpointهای سرویس، وضعیت نمونهها و محدودیت شبکه را مرحلهبهمرحله بررسی کنید. اگر نتیجه خواندن قدیمی است، مسیر درخواست و وضعیت بازپخش را ثبت کنید. جایگزین کردن فوری همه مقصدها با IP نمونه اصلی شاید یک نشانه را موقتاً پنهان کند، اما قرارداد اتصال را شکننده خواهد کرد.
در یک محیط آزمایشی میتوان نام سرویس، وضعیت نمونه و نقش PostgreSQL را همزمان ثبت کرد. مثلاً مشاهده خروجی پرسوجوی زیر به تشخیص اینکه نشست روی نمونه در حال بازیابی قرار دارد کمک میکند. آن را در همان نشست برنامه یا آزمایش اجرا کنید تا نتیجه واقعاً درباره همان اتصال باشد.
SELECT pg_is_in_recovery();
نتیجه این پرسوجو را کنار زمان اجرای آزمایش و نام سرویس ثبت کنید. یک پاسخ درست از نشست مدیریتی روی rw دلیل نمیشود برنامه نیز به همان مقصد وصل باشد. اگر برنامه رشته اتصال را از چند منبع مانند تنظیمات محیط، فایل محرمانه یا پیکربندی pool میگیرد، مقدار مؤثر را بدون چاپ رمز بررسی کنید. این روش عیبیابی، اختلاف میان چیزی که تیم تصور میکند و چیزی که برنامه واقعاً مصرف میکند آشکار میسازد.
تکثیر، پشتیبان و آزمون تحویل
Replica به تداوم سرویس کمک میکند، اما حذف منطقی یک جدول یا تغییر اشتباه داده میتواند از راه همان تکثیر منتقل شود. برای بازگشت به وضعیت قبل، راهبرد پشتیبان و نگهداری WAL متناسب با نسخه و روش استقرار لازم است. در تمرین بازیابی، داده را در محیط جدا بازگردانید و نتیجه را با یک پرسوجوی شناختهشده بررسی کنید. فقط دیدن فایلهای پشتیبان یا موفق بودن زمانبند نشان نمیدهد تیم میتواند سرویس را در زمان مورد انتظار بازسازی کند.
برای تحویل کلاستر، یک سناریوی مشخص بنویسید که از دید کاربر قابل اندازهگیری باشد. سفارش آزمایشی ثبت شود، در مسیر مناسب دیده شود، گزارش جداگانه از replica اجرا شود و پس از یک تغییر نقش کنترلشده، برنامه دوباره به مقصد درست وصل شود. سپس یک نسخه قدیمی از داده در محیط جدا بازیابی شود. زمانها، خطاهای مشاهدهشده و نحوه تشخیص نتیجه نامشخص نوشتن را مستند کنید. این شواهد روشن میکنند کدام قسمت را اپراتور مدیریت میکند و کدام بخش هنوز به قرارداد برنامه، طراحی ذخیرهسازی و آمادگی تیم عملیات وابسته است.