← شروع آموزش

WIUNIX ACADEMY

autovacuum در PostgreSQL؛ تشخیص عقب‌افتادگی پاک‌سازی و خطر wraparound

صفحهٔ 3 از 3؛ قبل از ادامه، مراحل قبلی و چیزهایی رو که لازم داری مرور کن.

آموزش متناسب با محیط تو

کجا اجرا می‌کنی؟

سیستم‌عامل و نسخهٔ سرورت رو انتخاب کن تا مراحل، دستورها و راه‌حل‌های همون محیط رو ببینی.

Ubuntu 24.04 — کلاینت موجودبررسی‌شده با مستندات رسمی ·

آموزش متناسب با مقادیر تو

تنظیمات این آموزش

مقادیر نمونه رو با مشخصات سرورت عوض کن تا متن و دستورها با هم تغییر کنن. رمز، کلید خصوصی و توکن اینجا وارد نکن. مقدارها فقط توی همین زبانه می‌مونن و به سرور یا لینک اشتراک‌گذاری فرستاده نمی‌شن. قبل از اجرا، DNS، گواهی‌ها و تنظیمات دسترسی شبکه رو روی سرورت بررسی کن.

اگر آی‌پی، دامنه یا پورت‌های نمونه با سرورت فرق دارن، بخش تنظیمات پایین رو باز کن. مقدارها رو عوض کن و «اعمال در آموزش» رو بزن؛ بعد دستورهای تازه رو کپی کن.

تنظیم مقادیر برای محیط من4 مقدار قابل‌تغییر
11

قدم بعدی

در صورت تأیید، فقط همان رابطه رو freeze کنیم

کادر پایین رو در نشست نگهداری و با autocommit روشن اجرا کن؛ نباید داخل تراکنش باز باشی. قبل از ادامه، مقصد چاپ‌شده رو دوباره بخون. FREEZE درخواست freeze تهاجمی می‌ده، ولی باز هم باید افق snapshotهای قدیمی رعایت بشه. با TRUNCATE FALSE از قفل اختیاری کوتاه‌کردن انتهای فایل صرف‌نظر می‌کنیم و قرار نیست انتهای فایل به سیستم‌عامل برگرده.

timeoutهای نمونه برای این کار برنامه‌ریزی‌شده هستن و نسخهٔ بازیابی اضطراری نیستن. حتی این کار هم می‌تونه I/O و WAL زیادی بسازه. از ترمینال مشاهده، کادر پیشرفت رو دوباره بخون. پیام مجوز ناکافی یا ردشدن جدول رو موفقیت حساب نکن؛ VACUUM ممکنه جدول فاقد مجوز رو رد کنه و باز هم برگرده. کنترل پایین مجوز MAINTAIN و جدول غیرموقتِ خارج از schemaهای سیستم رو هم می‌سنجه. بعد از اجرا، سن جدول و TOAST رو دوباره بگیر، نه فقط زمان last_vacuum رو.

با ONLY، جدول‌های فرزندِ inheritance رو وارد این کار نمی‌کنیم؛ پردازش TOAST خود رابطه همچنان طبق حالت پیش‌فرض فعال می‌مونه.

sql

نشست دوم psql با مجوز نگهداری

\conninfo
SELECT current_database(),current_user,pg_is_in_recovery();
\set target_schema 'public'
\set target_table 'orders'
SELECT current_setting('server_version_num')::integer BETWEEN 180000 AND 189999
       AND NOT pg_is_in_recovery()
       AND EXISTS (
         SELECT FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace
         WHERE n.nspname=:'target_schema' AND c.relname=:'target_table'
           AND c.relkind IN ('r','m')
           AND c.relpersistence <> 't'
           AND n.nspname !~ '^pg_' AND n.nspname <> 'information_schema'
           AND has_table_privilege(current_user,c.oid,'MAINTAIN')
       ) AS target_ready \gset
\if :target_ready
\else
\echo 'STOP: require the approved PostgreSQL 18 primary, a non-temporary application table/materialized view and MAINTAIN privilege.'
\quit
\endif
SET lock_timeout='3s';
SET statement_timeout='15min';
VACUUM (VERBOSE, FREEZE, TRUNCATE FALSE) ONLY :"target_schema".:"target_table";
\quit
از کجا بفهمم درست انجام شده؟

کار روی رابطهٔ کاربردی مصوب با مجوز لازم تمام می‌شه یا خطا/هشدار مشخص می‌ده؛ نشست نگهداری بدون تغییر تنظیمات سراسری بسته می‌شه. ردشدن جدول موفقیت نیست.

از همان جایی که خطا داده پیگیری کنیم

کادرهای تشخیص این بخش در نشست مشاهدهٔ فقط‌خواندنی اجرا می‌شن. اگر بستیش، دوباره همان نشست رو باز کن. اطلاعات اتصال و نتیجه‌ها رو خصوصی نگه دار؛ تغییر مجوز، لغو کار و تغییر replication هرکدوم تصمیم مصوب خودشون رو می‌خوان.

مجوز ندارم یا اطلاعات نشست‌های دیگر خالیه

نبود pg_read_all_stats می‌تونه بخشی از اطلاعات دیگران رو پنهان کنه. برای نگهداری، مالکیت جدول یا مجوز مناسب MAINTAIN لازمه. دسترسی فعلی رو ببین و از DBA بخواه همان کار مشخص رو انجام بده یا واگذار کنه؛ superuser عمومی راه‌حل نیست.

sql
SELECT current_user,pg_has_role(current_user,'pg_read_all_stats','USAGE') AS can_read_all_stats;
SELECT c.oid::regclass,c.relowner::regrole,
       has_table_privilege(current_user,c.oid,'MAINTAIN') AS has_maintain
FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace
WHERE n.nspname='public' AND c.relname='orders';
تخمین ردیف مرده یا زمان‌ها عوض نمی‌شن

ممکنه snapshot آمار همین نشست قدیمی باشه یا انتشار آمار کمی تأخیر داشته باشه. فقط snapshot محلی رو کنار می‌ذاریم، زمان reset رو می‌بینیم و بعد از فاصلهٔ معقول دوباره می‌خونیم. شمارندهٔ مشترک reset نمی‌شه و پایان autovacuum هم ممکنه با مشاهده هم‌زمان شده باشه.

sql
SELECT pg_stat_clear_snapshot();
SELECT clock_timestamp(),stats_reset FROM pg_stat_database
WHERE datname=current_database();
SELECT schemaname,relname,n_dead_tup,last_autovacuum,last_vacuum
FROM pg_stat_user_tables
WHERE schemaname='public' AND relname='orders';
کار دستی منتظر موند یا lock_timeout گرفت

timeout به معنی تمام‌شدن freeze نیست، هرچند بخشی از کار انجام‌شده می‌تونه مفید باقی بمونه. مرحله و نگه‌دارندهٔ قفل رو دوباره ببین و زمان اجرا رو از DDL هم‌زمان جدا کن. پشت‌سرهم retry نکن و همهٔ blockerها رو قطع نکن.

sql
SELECT p.pid,p.datname,p.relid,p.phase,
       p.heap_blks_total,p.heap_blks_scanned,p.heap_blks_vacuumed,
       p.index_vacuum_count,a.backend_type,a.wait_event_type,a.wait_event,
       pg_blocking_pids(p.pid) AS blocking_pids
FROM pg_stat_progress_vacuum p
LEFT JOIN pg_stat_activity a USING(pid)
WHERE p.datid=(SELECT oid FROM pg_database WHERE datname=current_database())
ORDER BY p.pid;
دستور موفق شد اما سن هنوز بالاست

نام دقیق جدول و سن TOAST رو دوباره ببین، بعد افق‌های نگه‌داشته‌شده و رابطه‌های قدیمی دیگر رو پیگیری کن. vacuum نمی‌تونه ردیف جدیدتر از افق مجاز رو freeze کنه. حتی اگر این جدول بهتر شده باشه، سن دیتابیس ممکنه متعلق به شیء دیگه‌ای باشه.

sql
\set target_schema 'public'
\set target_table 'orders'
SELECT c.oid,c.relkind,n.nspname,c.relname,c.reloptions,
       age(c.relfrozenxid) AS xid_age,mxid_age(c.relminmxid) AS mxid_age,
       age(t.relfrozenxid) AS toast_xid_age,
       mxid_age(t.relminmxid) AS toast_mxid_age
FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace
LEFT JOIN pg_class t ON t.oid=c.reltoastrelid
WHERE n.nspname=:'target_schema' AND c.relname=:'target_table';
SELECT pid,usename,application_name,backend_type,state,
       clock_timestamp()-xact_start AS transaction_duration,
       age(backend_xid) AS xid_age,age(backend_xmin) AS xmin_age,
       wait_event_type,wait_event
FROM pg_stat_activity
WHERE backend_xid IS NOT NULL OR backend_xmin IS NOT NULL
ORDER BY age(backend_xmin) DESC NULLS LAST LIMIT 30;
SELECT gid,prepared,owner,database,age(transaction) AS xid_age
FROM pg_prepared_xacts ORDER BY age(transaction) DESC;
SELECT slot_name,slot_type,database,active,active_pid,
       age(xmin) AS xmin_age,age(catalog_xmin) AS catalog_xmin_age,
       wal_status
FROM pg_replication_slots ORDER BY age(catalog_xmin) DESC NULLS LAST;

اگر ادامه مناسب نیست، مشکل رو بزرگ‌تر نکنیم

اگر لازم شد کار دستی برنامه‌ریزی‌شده رو متوقف کنی، در همان ترمینال نگهداری از interrupt کلاینت استفاده کن و صبر کن PostgreSQL لغو رو تمام کنه. vacuum کم‌کم پیش می‌ره؛ پاک‌سازی انجام‌شده مثل یک تراکنش rollback نمی‌شه و لازم نیست freeze رو برگردونی. autovacuum رو روشن نگه دار، خطا رو ثبت کن و قبل از نوبت بعدی علت، سن و اثر کار رو دوباره بسنج.

اگر پیام تعداد تراکنش باقی‌مانده تا wraparound اومده یا سرور تخصیص XID جدید رو نمی‌پذیره، فوراً DBA رو وارد رسیدگی کن. باید فشار نوشتن غیرضروری کم بشه، مانع‌های معتبر از مسیر مسئولشان حل بشن و دیتابیس‌های درگیر با مجوز لازم برای کاتالوگ‌ها vacuum بشن. کادر پانزده‌دقیقه‌ای تک‌جدولی این آموزش عمداً جای آن برنامه نیست. restart پیاپی، VACUUM FULL، حذف فایل وضعیت تراکنش یا دست‌کاری سن کاتالوگ راه ادامه نیست.

برای جلوگیری از تکرار، سرعت رشد هر سن و توان workerها رو اندازه بگیر. آستانه‌ها و بودجهٔ هزینه رو متناسب با همان بار کاری و هر بار فقط با یک تغییر قابل برگشت تنظیم کن؛ مقدار قبلی رو ثبت کن. پایین‌آوردن آستانهٔ جدول ممکنه به پاک‌سازی تغییرات کمک کنه، اما snapshot قدیمی رو آزاد نمی‌کنه. worker بیشتر هم می‌تونه فشار I/O رو بالا ببره. نتیجه رو با روند سن و تأخیر برنامه بسنج، نه با یک عدد تنظیم همگانی.

12

قدم بعدی

نشست رو ببندیم و تصمیم روشن تحویل بدیم

بعد از هر نگهداری، کادر سن دیتابیس و کادر جدول دقیق رو دوباره بخون؛ سپس نشست مشاهده رو ببند. یک یادداشت بدون دادهٔ حساس نگه دار: هویت دیتابیس و رابطه، زمان مشاهده، هر دو نوع سن، مانع‌های احتمالی، نتیجهٔ vacuum و مسئول اقدام بعدی.

روشن بگو تصمیم کدومه: ادامهٔ مشاهدهٔ پاک‌سازی عادی، نگهداری برنامه‌ریزی‌شدهٔ جدول، یا رخداد فوری در سطح دیتابیس. این بررسی‌ها آزمون بازیابی بکاپ یا نصب سیستم‌عامل نیستن و حذف همیشگی خطر wraparound رو هم تضمین نمی‌کنن.

sql

همان نشست ثابت psql برای مشاهده

\quit
از کجا بفهمم درست انجام شده؟

نشست تشخیص بسته شده و تصمیم نگهداری شاهد، مسئول و زمان بررسی بعدی داره.

منابع این آموزش

منابع رسمی

بالای صفحه می‌بینی که هر محیط چطور بررسی شده. بررسی مستندات به معنی اجرای عملی همهٔ نسخه‌ها نیست.

ادامهٔ مسیر

قدم بعدی تو

همهٔ آموزش‌های آکادمی ↗