PostgreSQL'de Agresif Otovacuum


42

PostgreSQL'in agresif bir şekilde veritabanımı otomatik olarak süpürmesini sağlamaya çalışıyorum. Şu anda otomatik vakumu şu şekilde yapılandırdım:

  • autovacuum_vacuum_cost_delay = 0 # Maliyete dayalı vakumu kapat
  • autovacuum_vacuum_cost_limit = 10000 #Maks değeri
  • autovacuum_vacuum_threshold = 50 #Default değeri
  • autovacuum_vacuum_scale_factor = 0.2 #Default değeri

Otomatik boşluğun sadece veri tabanı yüklenmediğinde devreye girdiğini fark ettim, bu yüzden canlı kayıtlardan çok daha fazla ölü delik olduğu durumlara giriyorum. Örnek için ekteki ekran görüntüsüne bakın. Masalardan birinde 23 canlı tup var, ancak 16845 ölü tup boşluk bekliyor. Delilik bu!

Çok sayıda Ölü Tuples

Test işlemi bittiğinde ve veritabanı sunucusu boşta kaldığında otomatik vakum devreye giriyor; bu, ölü tuple sayısı% 20'lik canlı tuples + 50'yi aştığında otomatik vakumun tekmelemesini istediğim gibi değil. yapılandırdı. Sunucu boştayken otomatik vakum yapma bana, üretim sunucusunun sürekli bir süre boyunca 1000 saniyelik güncelleme / sn'ye ulaşması bekleniyor, bu yüzden sunucu yüklenirken bile otomatik vakum kullanmam gerekiyor.

Kaybettiğim bir şey var mı? Sunucu ağır yük altındayken otomatik vakum çalışmasını nasıl zorlarım?

Güncelleme

Bu kilitleme sorunu olabilir mi? Söz konusu tablolar, bir son ekleme tetiği ile doldurulmuş özet tablolardır. Bu tablolar, aynı satıra eşzamanlı yazmaları önlemek için PAYLAŞMA REKLAMI ÖZEL modunda kilitlenir.

Yanıtlar:


40

Eelke, kilitlemenizin otovakuumu bloke ettiği neredeyse kesinlikle doğru. Autovacuum, kasıtlı olarak kullanıcı aktivitesine yol vermek için tasarlanmıştır. Bu tablolar kilitliyse, otomatik boşluk onları süpüremez.

Bununla birlikte, posterity için, hiper agresif otovakuum için örnek bir ayar seti vermek istedim, çünkü verdiğiniz ayarlar tam olarak yapmıyor. Bununla birlikte, otovakumu daha agresif hale getirmenin probleminizi çözme ihtimalinin düşük olduğunu unutmayın. Ayrıca, varsayılan otomatik ortam ayarlarının, optimum bir ayar kombinasyonu arayan DBT2 kullanılarak yapılan 200'den fazla test çalıştırmasına dayandığını unutmayın; bu nedenle, aksi halde düşünmek için sağlam bir nedeniniz yoksa veya veritabanınız önemli ölçüde dışarda değilse, varsayılanların iyi olduğu varsayılmalıdır. OLTP veritabanları için ana akım (örneğin, saniyede 10 K güncellemesi alan küçük bir veritabanı veya 3 TB veri ambarı).

Öncelikle, günlüğe kaydetmeyi açın, böylece autovacuum'un düşündüğünüzü yapıp yapmadığını kontrol edebilirsiniz:

log_autovacuum_min_duration = 0

Öyleyse daha fazla otovac işçisi yapalım ve tabloları daha sık kontrol ettirelim:

autovacuum_max_workers = 6
autovacuum_naptime = 15s

Daha erken tetiklemek için otomatik vakum ve otomatik analiz eşiklerini düşürelim:

autovacuum_vacuum_threshold = 25
autovacuum_vacuum_scale_factor = 0.1

autovacuum_analyze_threshold = 10
autovacuum_analyze_scale_factor = 0.05 

Öyleyse, autovacuum'u daha az kesintiye uğratalım, bu nedenle daha hızlı tamamlanır, ancak eşzamanlı kullanıcı etkinliği üzerinde daha büyük bir etkiye sahip olmak pahasına:

autovacuum_vacuum_cost_delay = 10ms
autovacuum_vacuum_cost_limit = 1000

Genel olarak agresif otovakumite için tam bir program var, bu da çok yüksek bir güncelleme oranına sahip olan küçük bir veritabanına uygun olabilir ancak eşzamanlı kullanıcı etkinliği üzerinde çok büyük bir etkisi olabilir.

Ayrıca, autovacuum parametrelerinin tablo başına ayarlanabileceğini unutmayın; bu, autovacuum'un davranışını ayarlama ihtiyacı için neredeyse her zaman daha iyi bir cevaptır.

Yine de, asıl sorununuzu çözmeniz pek mümkün değil.


36

Yalnızca hangi tabloların otomatik boşluk için uygun olduğunu görmek için, aşağıdaki sorgu kullanılabilir ( http://www.postgresql.org/docs/current/static/routine-vacuuming.html temelinde ). Ancak, sorgunun tabloya özel ayarları aramayacağını unutmayın:

 SELECT psut.relname,
     to_char(psut.last_vacuum, 'YYYY-MM-DD HH24:MI') as last_vacuum,
     to_char(psut.last_autovacuum, 'YYYY-MM-DD HH24:MI') as last_autovacuum,
     to_char(pg_class.reltuples, '9G999G999G999') AS n_tup,
     to_char(psut.n_dead_tup, '9G999G999G999') AS dead_tup,
     to_char(CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
         + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
            * pg_class.reltuples), '9G999G999G999') AS av_threshold,
     CASE
         WHEN CAST(current_setting('autovacuum_vacuum_threshold') AS bigint)
             + (CAST(current_setting('autovacuum_vacuum_scale_factor') AS numeric)
                * pg_class.reltuples) < psut.n_dead_tup
         THEN '*'
         ELSE ''
     END AS expect_av
 FROM pg_stat_user_tables psut
     JOIN pg_class on psut.relid = pg_class.oid
 ORDER BY 1;

11

Evet bu bir kilitleme sorunudur. Bu sayfaya göre (dolu değil) VAKUM, kullandığınız kilit seviyesi tarafından engellenen PAYLAŞIM GÜNCELLEŞTİRMESİ erişimine ihtiyaç duyar.

Bu kilide ihtiyacın olduğundan emin misin? PostgreSQL ACID uyumludur, bu nedenle aynı anda yazılanlar çoğu durumda sorun değildir, çünkü PostgreSQL bir seri hale getirme ihlali oluşması durumunda işlemlerden birini iptal edecektir.

Ayrıca , tüm tablo yerine satırları kilitlemek için SELECT FOR UPDATE kullanarak satırları kilitleyebilirsiniz.

Kilitlemesiz başka bir alternatif seri hale getirilebilir işlem yalıtım seviyesini kullanmak olacaktır . Ancak bu, diğer işlemlerin performansını etkileyebilir ve daha fazla seri hale getirme hatası için hazırlıklı olmalısınız.


Bunun nedeni, özet tablolarının kilitlenmesidir, çünkü bunlar PAYLAŞIM ORTA ÖZEL MODU kullanılarak kilitlenir. Kilidi olmayan eşzamanlı yazma başarılı olabilir, ancak kesinlikle yanlış değerlerle sonuçlanacaktır. X tipinde bir N sayısı tuttuğumu düşünün. Eğer eşzamanlı olarak 2 tip X satırı eklersem, kilitlemeden, N + 2 yerine özet tablomda N + 1 ile bitirdim. Özet tabloları veritabanımda elle boşaltan bir cron işine sahip olmak. İyi çalışıyor ve önerilen yaklaşım gibi görünüyor, ancak bana bir hack gibi hissediyor.
CadentOrange,

6

Otovakum işlemlerinin sayısının arttırılması ve nap zamanı azaltılması muhtemelen yardımcı olacaktır. İşte, PostgreSQL 9.1 için, yedekleme bilgilerini depolayan ve bunun sonucunda çok fazla ekleme etkinliği olan bir sunucuda kullandığım yapılandırma.

http://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html

autovacuum_max_workers = 6              # max number of autovacuum subprocesses
autovacuum_naptime = 10         # time between autovacuum runs
autovacuum_vacuum_cost_delay = 20ms     # default vacuum cost delay for

Ayrıca cost_delayvakumlamayı daha agresif hale getirmek için indirmeyi deneyeceğim .

Ayrıca pgbench kullanarak otomatik aralıklarını da test edebiliyorum.

http://wiki.postgresql.org/wiki/Pgbenchtesting

Yüksek çekişmeli örnek:

Bench_replication veritabanı oluştur

pgbench -i -p 5433 bench_replication

Pgbench'i çalıştır

pgbench -U postgres -p 5432 -c 64 -j 4 -T 600 bench_replication

Otomatik ortam durumunu kontrol et

psql
>\connect bench_replicaiton
bench_replication=# select schemaname, relname, last_autovacuum from pg_stat_user_tables;
 schemaname |     relname      |        last_autovacuum        
------------+------------------+-------------------------------
 public     | pgbench_branches | 2012-07-18 18:15:34.494932+02
 public     | pgbench_history  | 
 public     | pgbench_tellers  | 2012-07-18 18:14:06.526437+02
 public     | pgbench_accounts | 

6

Mevcut "autovacuum için hak" betiği çok faydalıdır, ancak (doğru şekilde belirtildiği gibi) tabloya özgü seçenekler eksikti. İşte bu seçenekleri göz önünde bulunduran değiştirilmiş versiyonu:

WITH rel_set AS
(
    SELECT
        oid,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_threshold=', 2), ',', 1)::BIGINT
        END AS rel_av_vac_threshold,
        CASE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)
            WHEN '' THEN NULL
        ELSE split_part(split_part(array_to_string(reloptions, ','), 'autovacuum_vacuum_scale_factor=', 2), ',', 1)::NUMERIC
        END AS rel_av_vac_scale_factor
    FROM pg_class
) 
SELECT
    PSUT.relname,
    to_char(PSUT.last_vacuum, 'YYYY-MM-DD HH24:MI')     AS last_vacuum,
    to_char(PSUT.last_autovacuum, 'YYYY-MM-DD HH24:MI') AS last_autovacuum,
    to_char(C.reltuples, '9G999G999G999')               AS n_tup,
    to_char(PSUT.n_dead_tup, '9G999G999G999')           AS dead_tup,
    to_char(coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples, '9G999G999G999') AS av_threshold,
    CASE
        WHEN (coalesce(RS.rel_av_vac_threshold, current_setting('autovacuum_vacuum_threshold')::BIGINT) + coalesce(RS.rel_av_vac_scale_factor, current_setting('autovacuum_vacuum_scale_factor')::NUMERIC) * C.reltuples) < PSUT.n_dead_tup
        THEN '*'
    ELSE ''
    END AS expect_av
FROM
    pg_stat_user_tables PSUT
    JOIN pg_class C
        ON PSUT.relid = C.oid
    JOIN rel_set RS
        ON PSUT.relid = RS.oid
ORDER BY C.reltuples DESC;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.