پرش به محتوای اصلی
پرش به محتوای مقاله

بهینه‌سازی Postgres توان عملیاتی اعلان‌ها را به ۶۰ هزار запись در ثانیه رساند

·۲ مرداد ۱۴۰۵۵ دقیقه مطالعه
معماری pub/sub داخلی PostgreSQL که از طریق دستورات LISTEN/NOTIFY در دسترس است، چگونه در مقیاس بالا عمل می‌کند.
معماری pub/sub داخلی PostgreSQL که از طریق دستورات LISTEN/NOTIFY در دسترس است، چگونه در مقیاس بالا عمل می‌کند.
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

تغییر پارادایم در ارسال اعلان‌های Postgres؛ به‌جای ارسال هر اعلان به‌صورت تراکنشی و سخت‌گیرانه، اعلان‌ها در حافظه بافر شده و به‌صورت دسته‌ای ارسال می‌شوند تا قفل سراسری (Global Lock) دور زده شود.

اگر امروز برای مدیریت جریان داده‌های سریع از Redis یا Kafka استفاده می‌کنید، شاید زمان آن رسیده است که دوباره به Postgres نگاه کنید. یک سرور تک‌گره پستگرس اکنون می‌تواند ۶۰,۰۰۰ запись در ثانیه (stream writes) را با تأخیری در حد چند میلی‌ثانیه پردازش کند.

طبق گزارش DBOS، این دستاورد با دور زدن قفل اعلان‌های داخلی پایگاه‌داده به‌دست آمده است. این یافته، باور رایج در صنعت را که سیستم LISTEN/NOTIFY پستگرس به‌طور ذاتی برای جریان‌های حجیم مقیاس‌ناپذیر است، به چالش می‌کشد؛ شهرتی که تا حد زیادی از یک پست وبلاگی محبوب نشأت گرفته بود که ادعا می‌کرد این قابلیت هرگز مقیاس نمی‌پذیرد.

برای سال‌ها، خرد جمعی در میان مهندسان بک‌اند این بود که از LISTEN/NOTIFY برای رویدادهای با فرکانس بالا اجتناب کنند. اکثر توسعه‌دهندگان از «قفل سراسری» (Global Lock) می‌ترسیدند؛ مکانیزمی که تراکنش‌ها را سریال‌سازی کرده و توان عملیاتی (Throughput) را به‌شدت کاهش می‌دهد. برای مدیریت داده‌های لحظه‌ای، مانند جریان توکن‌های مدل‌های زبانی بزرگ (LLM)، تیم‌ها اغلب به روش Polling (پرس‌وجوی مداوم) روی دیتابیس روی می‌آوردند. همان‌طور که در تحلیل‌های قبلی ما درباره‌ی زیرساخت‌های داده‌ای اشاره کردیم، این روش یا باعث تأخیر شدید می‌شود (اگر بازه زمانی طولانی باشد) یا CPU را با درخواست‌های توخالی و بیهوده اشباع می‌کند (اگر بازه زمانی خیلی کوتاه باشد).

معماری استریم‌های مبتنی بر پستگرس

ساختار پایه این استریم‌ها ساده است: یک جدول اختصاصی برای استریم‌ها ساخته می‌شود و هر تکه از داده (مثلاً یک توکن مجزا از پاسخ یک مدل LLM) به‌عنوان یک ردیف جدید در این جدول ثبت می‌گردد. عملیات نوشتن در این استریم، شامل درج‌های استاندارد (Standard Inserts) در این جدول است.

چالش اصلی در خواندن این تکه‌هاست. چون خواننده‌ها دقیقاً نمی‌دانند توکن بعدی چه زمانی می‌رسد، باید یا به‌طور مداوم پرس‌وجو (Poll) کنند یا منتظر بمانند. قابلیت LISTEN/NOTIFY راهی فراهم می‌کند تا خواننده‌ها در حالت مسدود (Block) قرار گیرند و منتظر اعلان نویسنده بمانند. این امر مانع از هدر رفت منابع توسط خواننده‌ها در اثر Polling مداوم می‌شود و تضمین می‌کند که آن‌ها بلافاصله پس از رسیدن یک تکه جدید، بیدار شده و واکنش نشان دهند.

گلوگاه قفل سراسری

به نقل از گزارش DBOS، فروپاشی عملکرد به این دلیل رخ می‌دهد که پستگرس تضمین می‌کند اعلان‌ها دقیقاً به همان ترتیبی که تراکنش‌ها تایید (Commit) می‌شوند، ارسال شوند. برای اجرای این تضمین، سیستم تمام اعلان‌های خروجی را در یک صف داخلی سراسری ذخیره می‌کند. از آنجایی که ترتیب تایید تا زمانی که تراکنش واقعاً در حال تکمیل نباشد تعریف نمی‌شود، پستگرس از یک قفل انحصاری سراسری (Global Exclusive Lock) برای سریال‌سازی این فرآیند استفاده می‌کند.

این قفل در لحظه شروع تایید تراکنش گرفته می‌شود و تا زمانی که تراکنش به‌طور کامل تایید نشود و محتویات آن با دستور fsync() روی دیسک نوشته نشود، آزاد نمی‌گردد. چون این قفل انحصاری است، پایگاه‌داده نمی‌تواند از بهینه‌سازی‌های «تایید گروهی» (Group Commit) برای پردازش چندین تراکنش به‌صورت همزمان در یک عملیات fsync واحد استفاده کند.

در پیاده‌سازی اولیه که توسط DBOS آزمایش شد، یک Trigger (تریگر) روی جدول استریم‌ها فعال بود تا برای هر write (نوشتن) یک اعلان ارسال کند. این معماری منجر به یک گلوگاه شدید شد:

  • سقف توان عملیاتی: سیستم نمی‌توانست بیش از ۲,۹۰۰ запись در ثانیه را تحمل کند.
  • مصرف نامرئی منابع: این گلوگاه بدون اینکه CPU، رم یا IOPS به‌طور چشم‌گیر مصرف شوند، رخ می‌داد.
  • سریال‌سازی: هر запись استریم مجبور بود قفل سراسری را بگیرد و آن را برای کل مدت زمان تخلیه داده‌ها روی دیسک نگه دارد.

معماری اعلان Postgres: چگونه LISTEN/NOTIFY در مقیاس بالا عمل می‌کند

محدودیت‌های وصله‌های فعلی

بحث‌های آنلاین زیادی درباره یک Patch (وصله) برای پستگرس وجود داشت که قصد داشت این مشکلات را حل کند. این وصله قرار است در نسخه ۱۹ پستگرس منتشر شود. با این حال، طبق تحلیل DBOS، این تغییرات نه قفل سراسری را حذف می‌کنند و نه گلوگاه توان عملیاتی مشاهده شده توسط DBOS را حل می‌کنند. در عوض، این وصله تنها یک مورد خاص و محدودتر را بهینه می‌کند: زمانی که تعداد کانال‌های اعلان بسیار زیاد است و هر شنونده (Listener) فقط منتظر یک کانال خاص است.

راهکار بافری کردن (Buffering)

برای شکستن این گلوگاه، DBOS استراتژی‌ای را پیاده کرد که عملیات «نوشتن داده» را از «ارسال اعلان» جدا (Decouple) می‌کند. بینش کلیدی این است که اعلان صرفاً یک «پینگ» است که به خواننده می‌گوید جدول را چک کند؛ در حالی که خودِ جدول همچنان تنها منبع حقیقت (Source of Truth) باقی می‌ماند. از آنجایی که اعلان‌ها نیازی به ترتیب جهانی یا ماندگاری (Durability) مطلق ندارند، می‌توان آن‌ها را به شکل متفاوتی مدیریت کرد:

  • بافری کردن در حافظه: اعلان‌ها به‌جای ارسال فوری توسط تریگر برای هر ردیف، در یک بافر حافظه ذخیره می‌شوند.
  • تخلیه دسته‌ای (Batch Flushing): این بافر به‌طور دوره‌ای در قالب یک تراکنش دسته‌ای واحد تخلیه می‌شود.
  • کاهش قفل: قفل انحصاری سراسری به‌جای آنکه برای هر تک‌تکِ نوشتن‌های استریم گرفته شود، تنها یک‌بار در زمان تخلیه دسته‌ای فعال می‌شود.

این روش اجازه می‌دهد تا نوشتن‌های جداگانه استریم به‌سرعت پیش بروند و از تمام بهینه‌سازی‌های پستگرس مانند Group Commit برای دستیابی به توان عملیاتی بالا بهره ببرند، در حالی که تخلیه بافر در پس‌زمینه انجام می‌شود.

معماری pub/sub داخلی PostgreSQL که از کانال‌های LISTEN/NOTIFY استفاده می‌کند و چگونگی مقیاس‌پذیری آن در سیستم‌های توزیع‌شده.

قابلیت اطمینان و نتایج

بافری کردن یک ریسک خاص را ایجاد می‌کند: اگر پردازشی در حالی که اعلان‌ها هنوز در بافر هستند کرش کند، آن اعلان‌ها هرگز تحویل داده نمی‌شوند. برای حل این مشکل، DBOS یک مکانیزم Polling با فرکانس پایین به‌عنوان پشتیبان (Fallback) اضافه کرد. خواننده‌ها عمدتاً منتظر اعلان‌ها می‌مانند، اما به‌صورت دوره‌ای دیتابیس را چک می‌کنند تا ببینند آیا استریمی نوشته شده که اعلان مربوطه به آن ارسال نشده باشد.

معماری pub/sub داخلی PostgreSQL که از کانال‌های LISTEN/NOTIFY استفاده می‌کند و چگونه در محیط‌های پرترافیک مقیاس‌پذیری می‌یابد

در هنگام بنچمارک، این رویکرد بهینه شده یک افزایش خیره‌کننده ۲۰ برابری در توان عملیاتی ایجاد کرد. سیستم به ۶۰,۰۰۰ запись در ثانیه رسید، در حالی که تأخیر (Latency) بین ۱۵ تا ۱۰۰ میلی‌ثانیه حفظ شد. نکته حیاتی این است که در این حالت، CPU پستگرس به‌طور کامل مورد استفاده قرار گرفت؛ به این معنی که دیتابیس بالاخره به‌جای توقف به‌دلیل رقابت بر سر قفل (Lock Contention)، توسط کارهای واقعی اشباع شد.

معماری pub/sub داخلی PostgreSQL که از کانال‌های LISTEN/NOTIFY استفاده می‌کند و چگونگی مقیاس‌پذیری آن در سیستم‌های توزیع‌شده.

این تحول نشان می‌دهد که برای اکثر کاربردهای Pub/Sub، اگر از قبل از پستگرس استفاده می‌کنید، دیگر نیازی به خوشه‌های مجزای Redis یا Kafka ندارید. با نگاه به اعلان‌ها به‌عنوان «راهنما» (Hint) به‌جای «لاگ‌های ماندگار»، می‌توانید استک فنی ساده‌تری داشته باشید بدون اینکه عملکرد را فدا کنید. این رویکرد با دیدگاهی همسو است که پستگرس می‌تواند جایگزین چندین پایگاه‌داده تخصصی در پشته‌های نرم‌افزاری شود تا پیچیدگی‌های عملیاتی کاهش یابد.

برای توسعه‌دهندگانی که رابط‌های هوش مصنوعی (AI Interfaces) در زمان واقعی می‌سازند، این به معنای آن است که پستگرس اکنون می‌تواند جریان‌های سریع توکن مورد نیاز برای چت‌های تعاملی در مقیاس بالا را مدیریت کند. این امر دیتابیس را از یک لایه ذخیره‌سازی غیرفعال به یک موتور استریمینگ فعال با تأخیر کم تبدیل می‌کند و به ویژه در سناریوهایی که مدل‌های زبانی بزرگ نیاز به بهینه‌سازی هزینه و سرعت استنتاج توکن‌ها دارند، نقش حیاتی ایفا می‌کند.

اگر یک محیط پستگرس با توان عملیاتی بالا مدیریت می‌کنید، می‌توانید کد کامل بنچمارک را در مخزن گیت‌هاب DBOS به آدرس github.com/dbos-inc/dbos-postgres-benchmark بیابید تا این محدودیت‌ها را روی سخت‌افزار خود تست کنید.

گام بعدی شما

  • اگر از Postgres برای استریم استفاده می‌کنید، کد بنچمارک را در مخزن گیت‌هاب DBOS تست کنید.
  • استراتژی «اعلان به‌عنوان اشاره» (Hint) را به‌جای «اعلان به‌عنوان لاگ» در معماری خود پیاده کنید.
  • بررسی کنید آیا حذف Redis از استک فنی شما، پیچیدگی سیستم را بدون افت عملکرد کاهش می‌دهد؟

اما داستان سخت‌افزاری این تحول حتی شگفت‌انگیزتر است — به تحلیل ما درباره‌ی تراشه‌های Blackwell مراجعه کنید.

چرا این موضوع مهم است؟

این بهینه‌سازی بر اساس تجربه عملی DBOS، اثبات می‌کند که پستگرس می‌تواند جایگزین ابزارهای پیچیده‌ی پیام‌رسانی در مقیاس بالا شود. این یعنی کاهش هزینه‌های عملیاتی و حذف یک لایه از پیچیدگی زیرساختی برای تیم‌های مهندسی.

تأثیر برای ایران

برنامه‌نویسان ایرانی که با محدودیت منابع برای میزبانی Redis یا Kafka در سرورهای داخلی (On-premise) مواجه‌اند، اکنون می‌توانند با استفاده از همین متد، استریم‌های پرسرعت را تنها با Postgres پیاده کنند.

·نگاه ما
تحریریه دات‌هوش

این دستاورد نشان می‌دهد که بسیاری از محدودیت‌های ادراکی ما درباره دیتابیس‌های سنتی، ناشی از استفاده از الگوهای قدیمی است و نه محدودیت ذاتی سخت‌افزار. با تبدیل اعلان‌ها از «سند قطعی» به «اشاره»، لایه‌ی انتقال داده در پستگرس عملاً به یک موتور استریم تبدیل شده است. این رویکرد می‌تواند منجر به موجی از ساده‌سازی در معماری‌های Backend شود تا وابستگی به ابزارهای جانبی مانند Kafka کاهش یابد.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.