→ بازگشت به نقشه‌های معماری
SPEC ۰۴ · مشخصات فنی سامانه

مهاجرت جریان پرداخت یکپارچه به معماری رویدادمحور

۲۳ مهر ۱۴۰۴

[معماری رویدادمحور][صف پیام][ریزخدمت‌ها]

مسئله و گلوگاه‌های سیستم سنکرون

در پلتفرم‌های پرداخت با هجوم همزمان تراکنش‌ها، پردازش همگام و مونوپلتفرم با مخاطرات جدی پایداری روبرو است:

۱. تایم‌اوت‌های زنجیره‌ای هنگام افزایش بار بانکی: در ساعات پیک ترافیک، تأخیر سوییچ‌های بانکی شاپرک و درگاه‌های PSP به بیش از ۵۰۰۰ میلی‌ثانیه می‌رسید. در معماری همگام، نخ‌های سرور در انتظار پاسخ بیرونی قفل می‌ماندند و باعث تهی‌شدن استخر اتصالات (Connection Pool) در کل کلاستر برنامه می‌شدند. ۲. تراکنش‌های شبح و مغایرت مالی: قطعی شبکه پس از کسر موجودی و پیش از ثبت نهایی تاییدیه، منجر به بروز مغایرت در تسویه و تلاش‌های مجدد تکراری می‌شد. ۳. قفل‌های سطری روی پایگاه داده: به‌روزرسانی مستقیم موجودی حساب‌ها با دستورات جهش‌پذیر پایگاه داده منجر به بن‌بست (Deadlock) و کندی شدید پایگاه داده در تراکنش‌های همزمان می‌شد.

رویکرد معماری و پیاده‌سازی الگوی Outbox

برای قطع وابستگی‌های متوالی و صیانت از تراز دقیق مالی، سیستم با ترکیب الگوی Transactional Outbox و ماشین وضعیت تخصیص دومرحله‌ای بازطراحی شد:

۱. تخصیص دومرحله‌ای موجودی و دفتر کل دوطرفه

به‌جای دستکاری مستقیم ردیف‌ها، جریان حسابداری بر دفتر کل تغییرناپذیر (Append-Only) و ماشین وضعیت دو فاز استوار شد:

  • فاز ۱ (رزرو موقت): موجودی از وضعیت AVAILABLE به RESERVED منتقل می‌شود. این مبلغ بلوکه شده و امکان خرج مضاعف ندارد، اما هنوز از حساب کاربر خارج نشده است.
  • فاز ۲ (تعهد نهایی یا آزادسازی): پس از دریافت فراخوانی معتبر از سوییچ تسویه بانکی، مبلغ رزرو شده کسر و به کیف پول مقصد منتقل می‌شود. در صورت تایم‌اوت یا خطای شبکه، مبلغ دوباره به وضعیت AVAILABLE بازگردانده می‌شود.
  • تراز صفر ریاضی: هر تراکنش حداقل دو رکورد دفتر روزنامه متوازن ایجاد می‌کند: $$\sum_{i=1}^{n} \text{Debit}i - \sum{j=1}^{m} \text{Credit}_j = 0$$

۲. صف‌بندی رویدادمحور بر بستر RabbitMQ

  • انتشار رویداد از Outbox: تغییرات وضعیت و رویدادهای مالی (activity.event) در قالب یک تراکنش واحد دیتابیس در جدول محلی Outbox ثبت می‌شوند.
  • رهگیری با CDC: سرویس Debezium رکوردهای جدول را بدون خطر نوشتن دوگانه (Dual-Write) به کلاستر صف RabbitMQ هدایت می‌کند.
  • جداسازی صف‌ها: ترافیک در دو مسیر مستقل هدایت می‌شود: صف activity.pending برای رصد لحظه‌ای و صف activity.end_state برای ثبت نهایی دفاتر مالی.
  • تضمین تکرارناپذیری (Idempotency): تمامی مصرف‌کنندگان پیام موظف به کنترل شناسه یکتای رهگیری (trackingCode) هستند تا دریافت پیام‌های تکراری شبکه به اختلال حسابداری نینجامد.

۳. مغایرت‌گیری دسته‌ای و خودترمیمی

  • مغایرت‌گیری چندمرحله‌ای شبانه: جاب رصد Spring Batch گزارش‌های تسویه بانکی را از طریق سرور امن SFTP دریافت و سطر به سطر با دفاتر مقایسه می‌کند.
  • سرویس بازپرداخت خودکار (Refund-MNG): در صورت تشخیص کسری بدون تسویه، فرآیند برگشت خودکار وجه فعال شده و از مداخله دستی نیروی انسانی جلوگیری می‌شود.

نتایج عملیاتی در پروداکشن

  • پایداری ۹۹.۹۹ درصدی لایه ورودی: جداسازی کامل فرآیندهای لبه از پاسخ‌های تأخیری شبکه بانکی و عدم قفل‌شدن منابع سرور.
  • مغایرت مالی صفر: حفظ توازن دقیق ریاضی دفتر کل دوطرفه در بیش از ۵۰ هزار رویداد تسویه روزانه.
  • همگامی نهایی زیر ۲۰۰ میلی‌ثانیه: کاهش زمان انتشار و نهایی‌شدن داده‌ها در سراسر میکروسرویس‌ها به زیر ۲۰۰ میلی‌ثانیه.
  • حذف ۹۹.۸ درصدی رفع مغایرت دستی: مدیریت خودکار تراکنش‌های ناموفق با موتور مغایرت‌گیری و خودترمیم.