MVCC-7. تنظيف السيارات

واسمحوا لي أن أذكرك بأننا بدأنا بمشاكل متعلقة بالعزلة ، وقمنا باستنباط حول تنظيم البيانات على مستوى منخفض ، وتحدثنا بالتفصيل عن إصدارات الصف وكيف يتم الحصول على لقطات من الإصدارات.

ثم نظرنا إلى التنظيف داخل الصفحة (والتحديثات الساخنة) ، والتنظيف المنتظم ، ولكن اليوم ننظر إلى التنظيف التلقائي.

التنظيف التلقائي (فراغ تلقائي)


لقد قلنا بالفعل أن التنظيف العادي في ظل الظروف العادية (عندما لا يحتفظ أي شخص بأفق المعاملة لفترة طويلة) يجب أن يتعامل مع عمله. والسؤال هو كم مرة نسميها.

إذا قمت بتنظيف طاولة تغيير نادراً جدًا ، فستكون أكبر مما تريد. بالإضافة إلى ذلك ، بالنسبة للتنظيف التالي ، قد يستغرق الأمر عدة تمريرات عبر المؤشرات إذا تراكمت تغييرات كثيرة للغاية.

إذا قمت بإلغاء تحديد الجدول كثيرًا ، فبدلاً من العمل المفيد ، سيشارك الخادم باستمرار في الصيانة - وليس جيدًا أيضًا.

لاحظ أن بدء التنظيف المنتظم المجدول لا يحل المشكلة ، لأن الحمل يمكن أن يتغير بمرور الوقت. إذا بدأ تحديث الجدول بشكل أكثر نشاطًا ، فيجب تنظيفه كثيرًا.

التنظيف التلقائي هو مجرد آلية تسمح لك بالبدء في التنظيف ، اعتمادًا على نشاط التغييرات في الجداول.

عند تمكين التنظيف التلقائي (معلمة التكوين التلقائي ) ، تكون عملية تشغيل قاذفة الفراغ التلقائي موجودة دائمًا في النظام ، الذي يخطط للعمل ، وتشارك تدفقات عمل عامل التعبئة التلقائية في التنظيف الحقيقي ، والتي يمكن أن تعمل عدة حالات على التوازي.

تجمع عملية إطلاق autov Vacuum قائمة من قواعد البيانات التي يوجد فيها أي نشاط. يتم تحديد النشاط حسب الإحصاءات ، ولكي يتم جمعها ، يجب تعيين المعلمة track_counts . لا تقم مطلقًا بإيقاف تشغيل autov Vacuum و track_counts ، وإلا فلن يعمل التنظيف التلقائي .

مرة واحدة في autov Vacuum_naptime ، تبدأ عملية قاذفة autov Vacuum (باستخدام عملية مدير مكتب البريد) سير عمل لكل قاعدة بيانات في القائمة. بمعنى آخر ، إذا كان هناك أي نشاط في قاعدة البيانات ، فسوف تأتي سير العمل إليها بفاصل زمني autov Vacuum_naptime . للقيام بذلك ، إذا كان هناك العديد من قواعد البيانات النشطة (قطع N) ، ثم يتم إطلاق عمليات العمل N مرات أكثر من autov Vacuum_naptime . ولكن في الوقت نفسه ، فإن العدد الإجمالي لسير العمل الذي يعمل في وقت واحد محدود بواسطة المعلمة autov Vacuum_max_workers .

بعد بدء التشغيل ، يتصل سير العمل بقاعدة البيانات المحددة به ويبدأ بإنشاء القائمة:

  • جميع الجداول ، وجهات النظر المادية ، وجداول الخبز المحمص التي تحتاج إلى مسح ،
  • جميع الجداول والتمثيلات المادية التي تتطلب تحليلًا (لا يتم تحليل جداول توست ، حيث يتم الوصول إليها دائمًا بواسطة الفهرس).

علاوة على ذلك ، يقوم سير العمل بدوره بتنظيف و / أو تحليل الكائنات المحددة وينتهي عند اكتمال التنظيف.

إذا لم تكمل العملية كل العمل المقصود لـ autov Vacuum_naptime ، فإن عملية إطلاق autov Vacuum ستقوم بإرسال سير عمل آخر إلى نفس قاعدة البيانات وسوف تعمل معًا. تعني كلمة "معاً" ببساطة أن العملية الثانية ستقوم بإنشاء قائمة الجداول الخاصة بها ومتابعتها. وبالتالي ، ستتم معالجة الجداول المختلفة بشكل متوازٍ ، ولكن على مستوى جدول واحد لا يوجد توازٍ - إذا كانت إحدى عمليات العمل تعمل بالفعل على الطاولة ، فسوف يتخطاها الآخر وينتقل.

كان هناك نقاش حول الحاجة إلى المعالجة المتوازية لفترة طويلة ، ولكن لم يتم اعتماد التصحيح بعد.

الآن دعونا نلقي نظرة فاحصة على ما يتطلب "التنظيف" و "يتطلب التحليل".

الجداول التي تحتاج إلى تنظيف


يُعتقد أن التنظيف ضروري إذا كان عدد "الموتى" ، أي إصدارات السلاسل غير ذات صلة ، يتجاوز قيمة العتبة المحددة. يتم تجميع عدد الإصدارات الميتة باستمرار بواسطة أداة تجميع الإحصائيات وتخزينها في جدول pg_stat_all_tables. ويتم تعيين العتبة بواسطة معلمتين:

  • يحدد autov Vacuum_vacuum_threshold القيمة المطلقة (بالقطع) ،
  • يحدد autov Vacuum_vacuum_scale_factor نسبة الصفوف في الجدول.

الصيغة النهائية هي: التنظيف مطلوب إذا كان pg_stat_all_tables.n_dead_tup> = autov Vacuum_vacuum_threshold + autov Vacuum_v Vacuum_scale_factor * pg_class.reltupes.

ضبط الإعدادات الافتراضية autov Vacuum_vacuum_threshold = 50 و
autov Vacuum_vacuum_scale_factor = 0.2. المعلمة الرئيسية هنا ، بالطبع ، هي autov Vacuum_vacuum_scale_factor - من المهم بالنسبة للجداول الكبيرة (وهي أن المشاكل المحتملة مرتبطة بها). يبدو أن قيمة 20 ٪ مبالغ فيها إلى حد كبير ، وعلى الأرجح سوف تحتاج إلى تخفيض كبير.

قد تختلف قيم المعلمات المثلى للجداول المختلفة اعتمادًا على حجمها وطبيعة التغييرات. من المنطقي أن تحدد ، بشكل عام ، قيمًا كافية ، وإذا لزم الأمر - لتكوين المعلمات بشكل خاص على مستوى بعض الجداول باستخدام معلمات التخزين:

  • autov Vacuum_vacuum_threshold and toast.autov Vacuum_v Vacuum_threshold ،
  • autov Vacuum_v Vacuum_scale_factor and toast.autov Vacuum_v Vacuum_scale_factor .

من أجل عدم الخلط ، يجب أن يتم ذلك فقط لعدد صغير من الجداول التي تبرز من بين غيرها من حيث حجم أو شدة التغييرات ، وفقط إذا كانت القيم المحددة عالميا ليست مناسبة.

بالإضافة إلى ذلك ، يمكن إيقاف التنظيف التلقائي على مستوى الطاولة (رغم أنه من الصعب التفكير في سبب ضرورة ذلك):

  • autov Vacuum_enabled و toast.autovacuum_enabled .

على سبيل المثال ، آخر مرة أنشأنا فيها جدولًا مع تعطيل التنظيف التلقائي ، - لأغراض العرض التوضيحي - لإدارة التنظيف اليدوي. يمكن تغيير معلمة التخزين كما يلي:

=> ALTER TABLE vac SET (autovacuum_enabled = off); 

لإضفاء الطابع الرسمي على كل ما سبق ، سننشئ عرضًا يوضح الجداول التي يجب تنظيفها حاليًا. ستستخدم دالة تُرجع القيمة الحالية للمعلمة ، بالنظر إلى أنه يمكن تجاوزها على مستوى الجدول:

 => CREATE FUNCTION get_value(param text, reloptions text[], relkind "char") RETURNS float AS $$ SELECT coalesce( --    ,    (SELECT option_value FROM pg_options_to_table(reloptions) WHERE option_name = CASE --  toast-    WHEN relkind = 't' THEN 'toast.' ELSE '' END || param ), --      current_setting(param) )::float; $$ LANGUAGE sql; 

وهنا الرأي:

 => CREATE VIEW need_vacuum AS SELECT st.schemaname || '.' || st.relname tablename, st.n_dead_tup dead_tup, get_value('autovacuum_vacuum_threshold', c.reloptions, c.relkind) + get_value('autovacuum_vacuum_scale_factor', c.reloptions, c.relkind) * c.reltuples max_dead_tup, st.last_autovacuum FROM pg_stat_all_tables st, pg_class c WHERE c.oid = st.relid AND c.relkind IN ('r','m','t'); 

ما الجداول تحتاج إلى تحليل


مع التحليل التلقائي ، فإن الوضع هو نفسه تقريبا. يُعتقد أنه يلزم إجراء تحليل لتلك الجداول التي يتجاوز فيها عدد الإصدارات التي تم تغييرها (منذ آخر تحليل) للصفوف القيمة الحدية المحددة بواسطة معلمتين متشابهتين: pg_stat_all_tables.n_mod_since_analyze> = autovacuum_analyze_threshold + autovacuum_analyze_scale_factor * pg_class.

تختلف إعدادات التحليل التلقائي الافتراضية قليلاً: autov Vacuum_analyze_threshold = 50 و autov Vacuum_analyze_scale_factor = 0.1. يمكن تعريفها أيضًا على مستوى معلمات التخزين للجداول الفردية:

  • autov Vacuum_analyze_threshold ،
  • autovacuum_analyze_scale_factor

نظرًا لأن جداول توست لا يتم تحليلها ، فلا توجد معايير مقابلة لها.

لنقم بإنشاء طريقة عرض للتحليل:

 => CREATE VIEW need_analyze AS SELECT st.schemaname || '.' || st.relname tablename, st.n_mod_since_analyze mod_tup, get_value('autovacuum_analyze_threshold', c.reloptions, c.relkind) + get_value('autovacuum_analyze_scale_factor', c.reloptions, c.relkind) * c.reltuples max_mod_tup, st.last_autoanalyze FROM pg_stat_all_tables st, pg_class c WHERE c.oid = st.relid AND c.relkind IN ('r','m'); 

مثال


بالنسبة للتجارب ، قمنا بتعيين قيم المعلمات التالية:

 => ALTER SYSTEM SET autovacuum_naptime = '1s'; --     => ALTER SYSTEM SET autovacuum_vacuum_scale_factor = 0.03; -- 3% => ALTER SYSTEM SET autovacuum_vacuum_threshold = 0; => ALTER SYSTEM SET autovacuum_analyze_scale_factor = 0.02; -- 2% => ALTER SYSTEM SET autovacuum_analyze_threshold = 0; 
 => SELECT pg_reload_conf(); 
  pg_reload_conf ---------------- t (1 row) 

الآن قم بإنشاء جدول مشابه للجدول الذي استخدمناه في المرة الأخيرة وأدخل ألف صف فيه. يتم تعطيل التنظيف التلقائي على مستوى الطاولة ، وسنعمل على تشغيله بأنفسنا. إذا لم يتم ذلك ، فلن تكون الأمثلة قابلة للتكرار ، نظرًا لأن التنظيف التلقائي قد يعمل في الوقت الخطأ.

 => CREATE TABLE autovac( id serial, s char(100) ) WITH (autovacuum_enabled = off); => INSERT INTO autovac SELECT g.id,'A' FROM generate_series(1,1000) g(id); 

إليك ما ستظهره طريقة التنظيف لدينا:

 => SELECT * FROM need_vacuum WHERE tablename = 'public.autovac'; 
  tablename | dead_tup | max_dead_tup | last_autovacuum ----------------+----------+--------------+----------------- public.autovac | 0 | 0 | (1 row) 

هناك نقطتان يجب الانتباه إليهما. أولاً ، max_dead_tup = 0 ، على الرغم من أن 3٪ من 1000 سطر هي 30 سطرًا. الحقيقة هي أنه ليس لدينا إحصاءات مطروحة على الطاولة ، لأن INSERT نفسها لا تقوم بتحديثها. حتى يتم تحليل جدولنا ، ستبقى الأصفار ، حيث pg_class.reltuples = 0. ومع ذلك ، دعونا نلقي نظرة على طريقة العرض الثانية للتحليل:

 => SELECT * FROM need_analyze WHERE tablename = 'public.autovac'; 
  tablename | mod_tup | max_mod_tup | last_autoanalyze ----------------+---------+-------------+------------------ public.autovac | 1000 | 0 | (1 row) 

نظرًا لتغيير الجدول (إضافة) 1000 صف ، وهذا أكثر من الصفر ، يجب أن يعمل التحليل التلقائي. تحقق هذا:

 => ALTER TABLE autovac SET (autovacuum_enabled = on); 

بعد توقف قصير ، نرى أن الجدول قد تم تحليله وبدلاً من الأصفار في max_mod_tup ، نرى الأسطر العشرين الصحيحة:

 => SELECT * FROM need_analyze WHERE tablename = 'public.autovac'; 
  tablename | mod_tup | max_mod_tup | last_autoanalyze ----------------+---------+-------------+------------------------------- public.autovac | 0 | 20 | 2019-05-21 11:59:48.465987+03 (1 row) 

 => SELECT reltuples, relpages FROM pg_class WHERE relname = 'autovac'; 
  reltuples | relpages -----------+---------- 1000 | 17 (1 row) 

دعنا نعود إلى التنظيف التلقائي:

 => SELECT * FROM need_vacuum WHERE tablename = 'public.autovac'; 
  tablename | dead_tup | max_dead_tup | last_autovacuum ----------------+----------+--------------+----------------- public.autovac | 0 | 30 | (1 row) 

Max_dead_tup ، كما نرى ، تم إصلاحه بالفعل. النقطة الثانية التي يجب الانتباه إليها هي dead_tup = 0. تُظهر الإحصائيات أنه لا توجد إصدارات ميتة للصفوف في الجدول ... وهذا صحيح. لا يوجد شيء للتنظيف في طاولتنا بعد. لذلك لن يتم مسح أي جدول يتم استخدامه فقط في وضع التذييل فقط ، وبالتالي لن يتم تحديث خريطة الرؤية له. وهذا يجعل من المستحيل استخدام الفهرسة فقط للمسح الضوئي (الفهرسة فقط).

(في المرة القادمة سوف نرى أن التنظيف عاجلاً أم آجلاً سيأتي إلى طاولة الإلحاق فقط ، لكن هذا نادر الحدوث.)

استنتاج عملي: إذا كان من المهم استخدام المسح الضوئي للفهرس فقط ، فقد تحتاج إلى طلب التنظيف اليدوي.

قم الآن بإيقاف تشغيل التنظيف التلقائي مرة أخرى وتحديث السطر 31 - واحد أكثر من قيمة العتبة.

 => ALTER TABLE autovac SET (autovacuum_enabled = off); => UPDATE autovac SET s = 'B' WHERE id <= 31; => SELECT * FROM need_vacuum WHERE tablename = 'public.autovac'; 
  tablename | dead_tup | max_dead_tup | last_autovacuum ----------------+----------+--------------+----------------- public.autovac | 31 | 30 | (1 row) 

الآن شرط الشروع في التنظيف التلقائي راضي. قم بتشغيل التنظيف التلقائي وبعد توقف قصير سنرى أن الجدول قد تمت معالجته:

 => ALTER TABLE autovac SET (autovacuum_enabled = on); => SELECT * FROM need_vacuum WHERE tablename = 'public.autovac'; 
  tablename | dead_tup | max_dead_tup | last_autovacuum ----------------+----------+--------------+------------------------------- public.autovac | 0 | 30 | 2019-05-21 11:59:52.554571+03 (1 row) 

تنظيم الحمل


لا يحظر التنظيف العمليات الأخرى ، لأنه يعمل على أساس كل صفحة على حدة ، ولكنه مع ذلك يخلق عبئًا على النظام ويمكن أن يكون له تأثير ملحوظ على الأداء.

تنظيم للتنظيف المنتظم


من أجل أن تكون قادرة على التحكم في شدة التنظيف ، وبالتالي تأثيره على النظام ، تتناوب العملية بين العمل والتوقع. يؤدي التنظيف تقريبًا إلى وحدات العمل التقليدية من فراغ ، ثم يغفو على مللي ثانية.

الإعدادات الافتراضية تعيين vacuum_cost_limit = 200 ، vacuum_cost_delay = 0. الصفر الأخير يعني في الواقع أن التنظيف (العادي) لا ينام ، وبالتالي فإن القيمة المحددة لـ vacuum_cost_limit لا تلعب أي دور. يتم ذلك لسبب أنه إذا اضطر المسؤول إلى بدء تشغيل VACUUM يدويًا ، فمن المحتمل أنه يريد إجراء عملية التنظيف في أسرع وقت ممكن.

ومع ذلك ، إذا كنت لا تزال تضبط وقت النوم ، فإن مقدار العمل المحدد في vacuum_cost_limit سيتألف من تكلفة العمل مع الصفحات في ذاكرة التخزين المؤقت المخزن المؤقت. يتم تقييم كل وصول للصفحة على النحو التالي:

  • إذا تم العثور على الصفحة في ذاكرة التخزين المؤقت المخزن المؤقت ، ثم vacuum_cost_page_hit = 1 ؛
  • إذا لم يتم العثور على ، ثم vacuum_cost_page_miss = 10 ؛
  • إذا لم تتمكن من العثور عليها ، واضطررت إلى إخراج الصفحة القذرة من المخزن المؤقت ، ثم vacuum_cost_page_dirty = 20.

أي أنه مع إعدادات vacuum_cost_limit افتراضيًا ، يمكن معالجة 200 صفحة من ذاكرة التخزين المؤقت أو 20 صفحة من القرص أو 10 صفحات ذات قذف في جلسة واحدة. من الواضح أن هذه الأرقام تعسفية إلى حد ما ، ولكن لا معنى لتحديدها بشكل أكثر دقة.

تنظيم لتنظيف السيارات


يعمل التحكم في الحمل أثناء التنظيف التلقائي كما يحدث للتنظيف المنتظم. ولكن حتى يعمل التنظيف اليدوي والتنظيف التلقائي بكثافة مختلفة ، فإن العمليات التلقائية لها معاييرها الخاصة: autov Vacuum_vacuum_cost_limit و autov Vacuum_vacuum_cost_delay . إذا كانت هذه المعلمات تأخذ القيمة -1 ، فسيتم استخدام القيمة من vacuum_cost_limit و / أو vacuum_cost_delay .

بشكل افتراضي ، autov Vacuum_vacuum_cost_limit = -1 (أي ، يتم استخدام القيمة vacuum_cost_limit = 200) و autov Vacuum_vacuum_cost_delay = 20ms. على الأجهزة الحديثة التي تحتوي على هذه الأرقام ، ستعمل عملية التنظيف التلقائي ببطء شديد.

في الإصدار 12 ، سيتم تخفيض قيمة autov Vacuum_vacuum_cost_delay إلى 2 مللي ثانية ، وهو ما يمكن اعتباره تقريبًا أوليًا أكثر ملاءمة.

بالإضافة إلى ذلك ، تجدر الإشارة إلى أن الحد الذي تحدده هذه المعلمات شائع في جميع عمليات العمل. بمعنى آخر ، مع تغير عدد عمليات العمل المتزامنة ، سيبقى الحمل الكلي ثابتًا. لذلك ، إذا كانت المهمة هي زيادة أداء التنظيف التلقائي ، فعند إضافة مهام سير العمل ، فإن الأمر يستحق زيادة autov Vacuum_vacuum_cost_limit .

استخدام الذاكرة والمراقبة


في المرة الأخيرة ، نظرنا في كيفية تنظيف ذاكرة الوصول العشوائي من حجم maintenance_work_mem لتخزين معرفات إصدار الصفوف المراد تنظيفها.

التنظيف التلقائي يفعل نفس الشيء. ولكن يمكن أن يكون هناك العديد من العمليات المتزامنة إذا قمت بضبط autov Vacuum_max_workers على قيمة كبيرة. بالإضافة إلى ذلك ، يتم تخصيص جميع الذاكرة على الفور وبشكل كامل ، وليس بالضرورة. لذلك ، بالنسبة لسير عمل التنظيف التلقائي ، يمكنك ضبط القيود الخاصة بك باستخدام المعلمة autov Vacuum_work_mem . بشكل افتراضي ، هذه المعلمة هي -1 ، أي أنها غير مستخدمة.

كما ذكرنا سابقًا ، يمكن أن يعمل التنظيف بأقل قدر ممكن من الذاكرة. ولكن إذا تم إنشاء فهارس على الجدول ، فإن قيمة maintenance_work_mem الصغيرة يمكن أن تؤدي إلى عمليات مسح فهرس متكررة. وينطبق الشيء نفسه على التنظيف التلقائي. من الناحية المثالية ، يجب عليك تحديد الحد الأدنى لقيمة autov Vacuum_work_mem التي لا تحدث فيها عمليات المسح المتكررة.

لقد رأينا أنه لمراقبة التنظيف ، يمكنك استخدام المعلمة VERBOSE (ولكن لا يمكن تحديدها للتنظيف التلقائي) أو طريقة العرض pg_stat_progress_vacuum (لكنها تُظهر المعلومات الحالية فقط). لذلك ، فإن الطريقة الرئيسية لمراقبة التنظيف التلقائي هي المعلمة log_autov Vacuum_min_duration ، والتي تعرض المعلومات في سجل رسائل الخادم. بشكل افتراضي ، يتم إيقاف تشغيله (تعيين إلى -1). هناك سبب لتمكين هذه المعلمة (بقيمة 0 ، سيتم عرض معلومات حول جميع عمليات التنظيف التلقائي) ومراقبة الأرقام.

إليك ما يبدو عليه الإخراج:

 => ALTER SYSTEM SET log_autovacuum_min_duration = 0; => SELECT pg_reload_conf(); 
  pg_reload_conf ---------------- t (1 row) 

 => UPDATE autovac SET s = 'C' WHERE id <= 31; 

 student$ tail -n 7 /var/log/postgresql/postgresql-11-main.log 
 2019-05-21 11:59:55.675 MSK [9737] LOG: automatic vacuum of table "test.public.autovac": index scans: 0 pages: 0 removed, 18 remain, 0 skipped due to pins, 0 skipped frozen tuples: 31 removed, 1000 remain, 0 are dead but not yet removable, oldest xmin: 4040 buffer usage: 78 hits, 0 misses, 0 dirtied avg read rate: 0.000 MB/s, avg write rate: 0.000 MB/s system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s 2019-05-21 11:59:55.676 MSK [9737] LOG: automatic analyze of table "test.public.autovac" system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s 

جميع المعلومات اللازمة موجودة هنا.

تذكر أنه في كثير من الأحيان لا ينبغي أن تزيد من حجم الذاكرة ، ولكن تقليل عتبة التنظيف بحيث تتم معالجة بيانات أقل في وقت واحد.

قد يكون من المنطقي أيضًا مراقبة طول قائمة الجداول التي تحتاج إلى التنظيف باستخدام المشاهدات أعلاه. ستشير الزيادة في طول القائمة إلى أن التنظيف التلقائي ليس لديه وقت للقيام بمهمته وأنه يجب تغيير الإعدادات.

أن تستمر .

Source: https://habr.com/ru/post/ar452762/


All Articles