فرض کنید سامانه فروشگاه پس از ثبت سفارش باید هم موجودی انبار را کم کند، هم پیام اطلاع رسانی بفرستد و هم داده را برای تحلیل مالی نگه دارد. اگر هر سه کار در همان درخواست کاربر انجام شوند، کندی یک سرویس می تواند ثبت سفارش را متوقف کند. پیام رسانی این وابستگی زمانی را کاهش می دهد، اما پرسش تازه ای می سازد. هر مصرف کننده از کجا می فهمد کدام پیام را گرفته است و اگر هنگام پردازش قطع شود، چه چیزی دوباره اجرا خواهد شد؟ در Apache Pulsar پاسخ این پرسش در ترکیب Topic، Subscription و Acknowledgment شکل می گیرد. این مقاله مسیر یک پیام را دنبال می کند و نشان می دهد انتخاب نوع اشتراک چگونه بر ترتیب، توزیع کار و بازیابی اثر می گذارد.
یک Topic و چند نگاه مستقل به پیام
Topic نشانی منطقی جریان پیام است. تولید کننده پیام سفارش را در آن منتشر می کند و مصرف کننده از طریق یک اشتراک به آن وصل می شود. اشتراک فقط یک نام برای اتصال نیست. موقعیت مصرف و تأیید پیام ها به آن وابسته است. اگر انبار و حسابداری باید هر دو تمام سفارش ها را ببینند، معمولاً به دو اشتراک متفاوت نیاز دارند. چند مصرف کننده عضو یک اشتراک، بر اساس نوع آن اشتراک، کار را میان خود تقسیم می کنند. این تمایز جلوی یک خطای رایج طراحی را می گیرد. اضافه کردن یک مصرف کننده حسابداری به اشتراک انبار لزوماً یک نسخه مستقل از همه پیام ها برای حسابداری ایجاد نمی کند.
در یک آزمایش آموزشی می توان ده سفارش با شناسه مشخص فرستاد و دو اشتراک جدا ساخت. انتظار قابل آزمون این است که هر اشتراک بتواند آن ده شناسه را مستقل دریافت کند. سپس یکی از اشتراک ها را با دو مصرف کننده اجرا کرد و نحوه توزیع را دید. نتیجه این آزمایش باید با نوع اشتراک تفسیر شود. شمارش اتصال ها به تنهایی توضیح نمی دهد که پیام برای چند کاربرد مستقل نگهداری می شود.
جدایی Broker از لایه ماندگاری
در معماری Pulsar، Broker اتصال تولید کننده و مصرف کننده و مالکیت Topic را مدیریت می کند. ماندگاری پیام های پایدار به لایه ذخیره سازی مبتنی بر Apache BookKeeper متکی است. این جدایی به تیم اجازه می دهد درباره ظرفیت پردازش اتصال ها و ظرفیت ذخیره سازی جداگانه فکر کند. با این حال جدایی اجزا به معنی حذف وابستگی نیست. یک Broker سالم که نتواند عملیات لازم را در لایه ذخیره سازی انجام دهد، الزاماً خدمت سالمی به تولید کننده ارائه نمی کند.
برای عیب یابی باید مسیر کامل نوشتن را دید. زمان انتشار از دید برنامه، خطای Broker، تأخیر ذخیره سازی و وضعیت شبکه میان اجزا چهار شاهد متفاوت هستند. اگر تنها مصرف CPU در Broker اندازه گیری شود، مشکل دیسک یا ارتباط با BookKeeper ممکن است پنهان بماند. در طراحی ظرفیت، تعداد Topicها، نرخ پیام، اندازه پیام و تعداد اشتراک های عقب مانده باید همراه یکدیگر بررسی شوند. افزایش تعداد مصرف کننده ها درمان عمومی همه این فشارها نیست.
Exclusive برای یک مصرف کننده فعال
اشتراک Exclusive برای حالتی است که تنها یک مصرف کننده به اشتراک متصل می شود. این مدل از نظر فهم مسیر ساده است و برای کاری که واقعاً باید در یک جریان مصرف انجام شود مناسب است. سادگی آن ظرفیت پردازش را نامحدود نمی کند. اگر زمان پردازش هر سفارش زیاد شود، صف عقب می افتد و اضافه کردن یک مصرف کننده دوم به همان اشتراک با قرارداد Exclusive سازگار نیست.
پیش از انتخاب این مدل باید تفاوت ترتیب دریافت و ترتیب اثر نهایی روشن شود. حتی اگر پیام ها به ترتیب تحویل شوند، برنامه ای که کارها را در چند اجرای ناهمزمان رها می کند ممکن است نتیجه ها را به ترتیب دیگری ثبت کند. بنابراین تضمین مورد نیاز کسب و کار باید در سطح مشخص نوشته شود. «سفارش ها مرتب هستند» جمله دقیقی نیست. «برای هر حساب، تغییر وضعیت فقط پس از ثبت موفق تغییر قبلی اعمال می شود» قراردادی است که می توان برای آن آزمون ساخت.
Failover و جابه جایی مصرف کننده فعال
در نوع Failover، چند مصرف کننده می توانند عضو اشتراک باشند، اما نقش فعال و آماده به کار اهمیت دارد. با از دست رفتن مصرف کننده فعال، مصرف کننده دیگری ادامه کار را بر عهده می گیرد. برای Topicهای پارتیشن بندی شده، فعال بودن می تواند در سطح پارتیشن توزیع شود. بنابراین نباید از نام این حالت نتیجه گرفت که در همه شکل های استقرار دقیقاً یک پردازشگر برای کل مجموعه کار می کند.
آزمایش مناسب شامل قطع واقعی مصرف کننده فعال در میانه یک کار است. باید ثبت شود آخرین پیامی که اثر آن در پایگاه داده دیده شده کدام است و آخرین تأیید ارسال شده کدام. فاصله میان این دو نقطه امکان پردازش دوباره را ایجاد می کند. Failover دسترس پذیری مصرف را بهبود می دهد، اما به خودی خود عملیات بانکی یا تغییر موجودی را دقیقاً یک بار نمی کند. برنامه همچنان باید تکرار شناسه رویداد را بشناسد و اثر تکراری را کنترل کند.
Shared برای تقسیم کار
در اشتراک Shared، پیام ها میان مصرف کننده های یک اشتراک توزیع می شوند. این مدل برای کارهای مستقلی مانند ساخت تصویر بندانگشتی یا ارسال کارهای جداگانه مفید است. هنگامی که هر پیام مستقل باشد، افزایش تعداد مصرف کننده می تواند ظرفیت را بیشتر کند. سقف واقعی به منابع پایین دست، اندازه کار و شیوه دریافت پیام وابسته است. اگر همه مصرف کننده ها به یک پایگاه داده کوچک فشار بیاورند، افزایش تعداد آن ها ممکن است فقط زمان انتظار و خطا را بیشتر کند.
Shared قرارداد ترتیب سراسری مورد نیاز برای تغییرات وابسته یک حساب را فراهم نمی کند. برای مثال اگر پیام مسدود کردن و سپس آزاد کردن یک حساب میان دو پردازشگر پخش شود، مدت اجرای متفاوت می تواند نتیجه نامطلوبی بسازد. بهتر است پیش از انتخاب نوع اشتراک، وابستگی میان پیام ها روی کاغذ مشخص شود. هرجا دو رویداد می توانند بدون توجه به ترتیب یکدیگر اجرا شوند، تقسیم آزاد کار ساده تر است. هرجا وابستگی وجود دارد، کلیدگذاری یا کنترل نسخه لازم می شود.
Key_Shared و معنای کلید
Key_Shared برای حفظ وابستگی پیام های دارای یک کلید در کنار توزیع کار میان مصرف کننده ها طراحی شده است. انتخاب کلید یک تصمیم دامنه ای است. شناسه مشتری، شناسه سفارش و شناسه دستگاه سه تقسیم بندی متفاوت می سازند. اگر همه پیام ها کلید یکسان داشته باشند، انتظار توزیع گسترده بی معناست. اگر هر رویداد یک کلید تصادفی تازه بگیرد، وابستگی رویدادهای متعلق به یک موجودیت از بین می رود.
مستندات Pulsar درباره سازگاری batching با Key_Shared هشدار می دهند. تنظیم بسته بندی تولید کننده باید با این نوع اشتراک هماهنگ باشد تا پیام های کلیدهای متفاوت به شکلی ناسازگار کنار هم قرار نگیرند. تیم باید رفتار نسخه و کتابخانه خود را بررسی کند و با چند کلید پرتکرار آزمایش بسازد. توزیع یکنواخت روی کاغذ کافی نیست. یک مشتری بسیار پرکار می تواند یک کلید داغ ایجاد کند و بخش بزرگی از بار را روی مسیر محدودی نگه دارد.
تأیید پیام مرز تعهد برنامه است
Acknowledgment به Pulsar اعلام می کند مصرف کننده مسئولیت آن پیام را انجام داده است. این اعلام باید با معنای واقعی موفقیت برنامه هماهنگ باشد. اگر پیش از ثبت تغییر در پایگاه داده تأیید فرستاده شود و فرایند بلافاصله قطع شود، پیام از دید اشتراک انجام شده اما اثر کسب و کار ثبت نشده است. اگر ابتدا تغییر ثبت و سپس تأیید ارسال شود، قطع شدن در فاصله این دو مرحله می تواند تحویل دوباره ایجاد کند.
یک راه عملی برای کنترل این فاصله، ثبت شناسه رویداد در همان تراکنشی است که تغییر اصلی را انجام می دهد. هنگام دریافت دوباره، برنامه می بیند شناسه قبلاً پردازش شده و اثر را دوباره اعمال نمی کند. این الگو باید با محدودیت یکتایی و تراکنش واقعی پشتیبانی شود. بررسی ساده در حافظه یا پرس وجوی جداگانه پیش از نوشتن، در برابر دو پردازش همزمان تضمین کافی ندارد. انتخاب جزئیات به پایگاه داده و ماهیت عملیات وابسته است.
تکرار، پیام خراب و صف خطا
همه شکست ها یکسان نیستند. خطای موقت شبکه ممکن است با تکرار کوتاه حل شود، اما پیام دارای ساختار نامعتبر با هزار بار اجرای دوباره معتبر نمی شود. سیاست تکرار باید تعداد تلاش، فاصله زمانی و مسیر رسیدگی نهایی را مشخص کند. Pulsar امکاناتی مانند تحویل دوباره و سیاست های dead letter دارد، ولی رفتار دقیق و محدودیت آن ها باید با نوع اشتراک و کتابخانه مورد استفاده تطبیق داده شود.
صف خطا پایان مسئولیت نیست. برای آن باید مالک، زمان رسیدگی و روش بازگرداندن پیام تعریف شود. اگر پیام خطادار شامل داده حساس است، دسترسی به آن و مدت نگهداری نیز اهمیت دارد. بازگرداندن یک پیام اصلاح شده بدون حفظ ارتباط با شناسه اصلی می تواند ردگیری رخداد را دشوار کند. بهتر است گزارش عملیاتی مشخص کند پیام چند بار تلاش شده، آخرین خطا چه بوده و چه تصمیم انسانی یا خودکاری برای آن گرفته شده است.
Backlog با Retention و Compaction فرق دارد
Backlog معمولاً به پیام هایی مربوط می شود که یک اشتراک هنوز مصرف و تأیید نکرده است. Retention سیاست نگهداری پیام هایی است که ممکن است دیگر برای اشتراک ها تأیید شده باشند. Compaction نیز نگاه دیگری دارد و برای کلیدها آخرین مقدارهای مرتبط را در نمای فشرده فراهم می کند. این سه مفهوم را نباید با یک تنظیم عمومی «مدت نگهداری صف» جایگزین کرد. هر کدام به پرسش متفاوتی پاسخ می دهد و می تواند اثر متفاوتی بر دیسک و امکان بازخوانی داشته باشد.
برای یک جریان وضعیت دستگاه، نمای فشرده می تواند شروع مصرف را از آخرین وضعیت هر کلید ساده کند. برای دفتر رویداد مالی که تمام تغییرها اهمیت دارند، آخرین وضعیت جای تاریخچه را نمی گیرد. تیم باید روشن کند مصرف کننده تازه به وضعیت فعلی نیاز دارد یا همه رخدادهای گذشته. این انتخاب بر هزینه ذخیره سازی، زمان راه اندازی و امکان حسابرسی اثر می گذارد و بهتر است پیش از بحران کمبود فضا انجام شود.
آزمایش پذیرش برای مسیر سفارش
یک آزمون کوچک اما واقعی می تواند بخش زیادی از ابهام را آشکار کند. مجموعه ای از سفارش های دارای کلید تکرارشونده بسازید، در میانه پردازش یک مصرف کننده را متوقف کنید و پس از بازگشت تعداد اثرهای ثبت شده را با تعداد شناسه های یکتا مقایسه کنید. سپس سرعت پایگاه داده پایین دست را عمداً کاهش دهید و رشد backlog، تأخیر انتها به انتها و رفتار تکرار را مشاهده کنید. این آزمایش باید در محیط مجاز و جدا از داده واقعی کاربران انجام شود.
معیار موفقیت فقط صفر بودن خطا در لاگ نیست. باید معلوم باشد هیچ سفارش گم نشده، هیچ اثر مالی دوبار اعمال نشده و زمان بازیابی در محدوده مورد انتظار است. همچنین باید بتوان یک شناسه سفارش را از تولید تا مصرف و ثبت نهایی دنبال کرد. با چنین شواهدی انتخاب Exclusive، Failover، Shared یا Key_Shared از یک ترجیح اسمی به تصمیم مهندسی قابل دفاع تبدیل می شود.