انتخاب سطح ایزولاسیون مناسب در PostgreSQL اغلب تعادلی بین یکپارچگی دادهها و عملکرد سیستم است. اگرچه READ COMMITTED حالت پیشفرض است و عملکرد بالایی ارائه میدهد، اما در برابر خواندنهای تکرارناپذیر و خواندنهای فانتوم آسیبپذیر است. در انتهای دیگر طیف، سطح SERIALIZABLE قویترین تضمین را فراهم میکند اما به طور سنتی با هزینه عملکرد شدیدی به دلیل بررسیهای اعتبارسنجی سریالپذیری همراه است.
با این حال، PostgreSQL یک راه حل میانه قدرتمند ارائه میدهد: ایزولاسیون اسنپشات سریالپذیر (SSPI). این پست وبلاگ بررسی میکند که چگونه SSPI به شما امکان میدهد تضمینهای سریالپذیری سختگیرانه را حفظ کنید در حالی که اضافهبار مرتبط با بررسیهای سریالپذیری سنتی را به حداقل میرساند و آن را برای محیطهای با تراکنش بالا مناسب میسازد.
درک ایزولاسیون اسنپشات سریالپذیر
ایزولاسیون سریالپذیر سنتی با قفل کردن سطرها کار میکند که میتواند در سناریوهای همزمانی بالا منجر به رقابت قابل توجهی شود. SSPI که در PostgreSQL نسخه 9.1 معرفی شد و در نسخههای بعدی بهبود یافت، از مکانیسم متفاوتی استفاده میکند. این مکانیسم تضمین میکند که اگر تراکنشها را به صورت موازی اجرا کنید، نتیجه معادل برخی ترتیبهای اجرای سریال خواهد بود، اما این کار را با تشخیص ناهنجاریهای سریالسازی (مانند وابستگیهای خواندن-نوشتن یا نوشتن-نوشتن) و لغو تراکنشهای متعارض به جای مسدود کردن آنها انجام میدهد.
این رویکرد به ویژه برای برنامههای با تراکنش بالا مفید است زیرا از اضافهبار تشخیص بنبست جلوگیری میکند و رقابت قفل را کاهش میدهد. به جای انتظار برای قفلها، تراکنشها ممکن است شکست بخورند و نیاز به تلاش مجدد داشته باشند که اغلب ارزانتر از باز نگه داشتن قفلها است.
پیکربندی SSPI در PostgreSQL
پیادهسازی SSPI ساده است. میتوانید سطح ایزولاسیون تراکنش را به صورت تراکنش به تراکنش یا به صورت سراسری تنظیم کنید. برای بیشتر برنامهها، تنظیم آن در سطح جلسه کافی است، اما کنترل تراکنش فردی دانهبندی دقیقتری ارائه میدهد.
در اینجا نحوه شروع یک تراکنش با SSPI آمده است:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
در عوض، میتوانید آن را برای کل جلسه تغییر دهید:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
مدیریت شکستهای سریالسازی
چالش اصلی با SSPI نه اضافهبار عملکرد خود بررسیها، بلکه ضرورت مدیریت تلاش مجدد تراکنش است. وقتی PostgreSQL یک تعارض سریالسازی را تشخیص میدهد، تراکنش را لغو میکند و کد خطای 40001 SQLSTATE (معمولاً serializable_failure) را برمیگرداند. کد برنامه شما باید طوری طراحی شود که این استثنا خاص را دریافت کرده و تراکنش را مجدداً تلاش کند.
در اینجا یک مثال عملی با استفاده از پایتون و کتابخانه psycopg2 برای مدیریت تلاش مجدد آورده شده است:
import psycopg2
from psycopg2 import errors
def execute_serializable_transaction(conn):
while True:
try:
with conn.cursor() as cur:
cur.execute("BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE")
# عملیات پایگاه داده را اینجا انجام دهید
cur.execute("SELECT balance FROM accounts WHERE id = 1")
row = cur.fetchone()
cur.execute("UPDATE accounts SET balance = %s WHERE id = 1", (row[0] - 10,))
conn.commit()
break
except errors.SerializationFailure:
conn.rollback()
continue
except Exception as e:
conn.rollback()
raise
این الگو تضمین میکند که برنامه شما تعارضات را به صورت شایسته مدیریت کند. از آنجا که SSPI تعارضات را در اواخر چرخه عمر تراکنش تشخیص میدهد، هزینه اصلی خود تلاش مجدد است، نه قفلگذاری در طول تراکنش.
مبادلات عملکرد و بهترین شیوهها
اگرچه SSPI سریعتر از ایزولاسیون سریالپذیر سنتی است، اما همچنان کندتر از READ COMMITTED است. بنابراین، باید با احتیاط از آن استفاده شود. بهترین شیوههای زیر را در نظر بگیرید:
- حداقل کردن دامنه تراکنش: تراکنشها را تا حد امکان کوتاه نگه دارید تا پنجره برای تعارضات کاهش یابد.
- از خواندنهای طولانیمدت خودداری کنید: پرسوجوهای خواندن طولانی میتوانند از پیشرفت تراکنشهای دیگر جلوگیری کنند و احتمال شکستهای سریالسازی را افزایش دهند.
- از قفلگذاری خوشبینانه برای موارد ساده استفاده کنید: اگر فقط نیاز به جلوگیری از بهروزرسانیهای گمشده دارید، در نظر بگیرید که از
SELECT ... FOR UPDATEهمراه با نسخهبندی در سطح برنامه استفاده کنید که سبکتر از SSPI کامل است. - نرخهای تلاش مجدد را پایش کنید: اگر برنامه شما نرخ بالایی از شکستهای سریالسازی را تجربه میکند، ممکن است نیاز به بهینهسازی منطق تراکنش خود یا بازنگری در مدل دادههایتان داشته باشید.
نتیجهگیری
ایزولاسیون اسنپشات سریالپذیر راهی قوی برای تضمین یکپارچگی دادهها در PostgreSQL بدون هزینه عملکرد فلجکننده قفلگذاری سنتی ارائه میدهد. با درک مبادلات و پیادهسازی منطق تلاش مجدد مناسب، توسعهدهندگان میتوانند از SSPI برای ساخت برنامههای همزمان و یکپارچه بالا استفاده کنند. چه با تراکنشهای مالی سروکار داشته باشید و چه با سیستمهای پیچیده موجودی، SSPI یک مسیر مقیاسپذیر برای یکپارچگی قوی در محیطهای با تراکنش بالا ارائه میدهد.