2011-04-07 19 views
5

PostgreSQL kullanarak çok bantlı bir veritabanı uygulamak için değerlendirmeler yapıyoruz, Şu anda tek veritabanı-çoklu şema modelinde bazı testler yapıyoruz (tüm kiracılar aynı veritabanı nesnelerine sahiptir) Aynı veritabanı içinde kendi şeması altında). Uygulama, tüm kiracılar/şemalar arasında paylaşılacak bir bağlantı havuzu sağlayacaktır.PostgreSQL backend işlemi yüksek bellek kullanımı sorunu

örn. Veritabanında 500 kiracı/şema varsa ve her kiracının 200 tablo/görüş alanı varsa, toplam tablo/görüntüleme sayısı 500 * 200 = 100.000 olacaktır.

Bağlantı havuzu tüm kiracılar tarafından kullanılacağından, her bağlantı sonunda tüm tablolara/görünümlere çarpacaktır.

Testlerimizde, bağlantı daha fazla görünüme ulaştığında, arka uç işleminin bellek kullanımının oldukça hızlı arttığını ve çoğunun özel bellek olduğunu gördük. Bağlantı kapanana kadar bu hafıza tutulacaktır.

Bir arka uç işlemin 30GB daha fazla bellek kullandığını ve nihayetinde yetersiz bellek hatası aldığını bir test vakamız var. sorunu anlamak yardımcı olmak için

, ben basitleştirilmiş test durumları oluşturmak için kod yazdı - MTDB_destroy: kiracı şemaları temizlemek için kullanılan - MTDB_Initialize: Bir DB multitenant oluşturmak için kullanılan - MTDB_RunTests: basitleştirilmiş test durumda, temelde bütün seçim Kiracı tek tek görüyor. Yaptığım

testler 5.4

Ben (tek şey temiz bir çevre, ben yeniden oluşturulur veritabanı küme vardır ve varsayılan olarak çoğunluk yapılandırmaları terk emin olmak için CentOS üzerinde PostgreSQL 9.0.3 oldu Ben değiştirmeye VAR MTDB_destroy sayıda nesne düşmesi gerekiyor çünkü "max_locks_per_transaction" artırmaktır) Bu benim sorunu yeniden oluşturmak için ne olduğunu

:. yeni bir veritabanı oluşturmak

  1. ; Başlat

    (gerçek 'kiracı', 100, 100) MTDB_Initialize seç - 10

  2. db oluşturulan yeni bağlanmak

  3. ekli kodu kullanarak üç işlevler oluşturmak ve ilklendir geçiri çalıştırmak

    - vakum analiz emin değil ben sadece

    vakum analiz çalıştırmak, burada yararlıdır;

    - check tablolar/görünümler INFORMATION_SCHEMA gelen

    seçme TABLE_SCHEMA TABLE_TYPE, saymak (*) oluşturuldu.table_schema'ın table_schema, table_schema, table_type;

  4. yeni oluşturulan db'ye başka bir bağlantı açmak ve test komut dosyalarını çalıştırmak

    -) (akım bağlantısı için

    SEÇ pg_backend_pid arka uç işlem kimliği almak;

    - Bir Linux konsolu açın ve ps -p çalıştırın ve VIRT, RES ve SHR

    izle - çalıştırmak testler

    seçme MTDB_RunTests ('kiracı', 1);

Gözlemler:

testleri çalıştırmak için bağlantı ilk oluşturulduğu
  1. ,

    VIRT = 182MB, RES = 6240K SHR = 4648K

  2. testler sonrasında bir kere, (175 saniye sürmüştür)

    VIRT = 1661MB RES = 1.5GB SHR = 55MB

  3. yeniden çalıştırmak tekrar test (167 saniye sürmüştür)

  4. yeniden çalıştırmak daha testi

    (165 saniye sürmüştür) VIRT = 1661MB RES = 1.5 GB SHR = 55MB biz tablo sayısını büyütmek olarak VIRT = 1661MB RES = 1.5GB SHR = 55MB

, hafıza kullanımları da testlerde kadar gitmek.

Burada neler olduğunu açıklayan herkes yardımcı olabilir mi? PostgreSQL backend işleminin bellek kullanımını kontrol etmemizin bir yolu var mı?

Teşekkürler.

Samuel

-- MTDB_destroy 
create or replace function MTDB_destroy (schemaNamePrefix varchar(100)) 
returns int as $$ 
declare 
    curs1 cursor(prefix varchar) is select schema_name from information_schema.schemata where schema_name like prefix || '%'; 
    schemaName varchar(100); 
    count integer; 
begin 
    count := 0; 
    open curs1(schemaNamePrefix); 
    loop 
     fetch curs1 into schemaName; 
     if not found then exit; end if;   
     count := count + 1; 
     execute 'drop schema ' || schemaName || ' cascade;'; 
    end loop; 
    close curs1; 
    return count; 
end $$ language plpgsql; 

-- MTDB_Initialize 
create or replace function MTDB_Initialize (schemaNamePrefix varchar(100), numberOfSchemas integer, numberOfTablesPerSchema integer, createViewForEachTable boolean) 
returns integer as $$ 
declare 
    currentSchemaId integer; 
    currentTableId integer; 
    currentSchemaName varchar(100); 
    currentTableName varchar(100); 
    currentViewName varchar(100); 
    count integer; 
begin 
    -- clear 
    perform MTDB_Destroy(schemaNamePrefix); 

    count := 0; 
    currentSchemaId := 1; 
    loop 
     currentSchemaName := schemaNamePrefix || ltrim(currentSchemaId::varchar(10)); 
     execute 'create schema ' || currentSchemaName; 

     currentTableId := 1; 
     loop 
     currentTableName := currentSchemaName || '.' || 'table' || ltrim(currentTableId::varchar(10)); 
     execute 'create table ' || currentTableName || ' (f1 integer, f2 integer, f3 varchar(100), f4 varchar(100), f5 varchar(100), f6 varchar(100), f7 boolean, f8 boolean, f9 integer, f10 integer)'; 
     if (createViewForEachTable = true) then 
      currentViewName := currentSchemaName || '.' || 'view' || ltrim(currentTableId::varchar(10)); 
      execute 'create view ' || currentViewName || ' as ' || 
        'select t1.* from ' || currentTableName || ' t1 ' || 
      ' inner join ' || currentTableName || ' t2 on (t1.f1 = t2.f1) ' || 
      ' inner join ' || currentTableName || ' t3 on (t2.f2 = t3.f2) ' || 
      ' inner join ' || currentTableName || ' t4 on (t3.f3 = t4.f3) ' || 
      ' inner join ' || currentTableName || ' t5 on (t4.f4 = t5.f4) ' || 
      ' inner join ' || currentTableName || ' t6 on (t5.f5 = t6.f5) ' || 
      ' inner join ' || currentTableName || ' t7 on (t6.f6 = t7.f6) ' || 
      ' inner join ' || currentTableName || ' t8 on (t7.f7 = t8.f7) ' || 
      ' inner join ' || currentTableName || ' t9 on (t8.f8 = t9.f8) ' || 
      ' inner join ' || currentTableName || ' t10 on (t9.f9 = t10.f9) ';      
     end if; 
     currentTableId := currentTableId + 1; 
     count := count + 1; 
     if (currentTableId > numberOfTablesPerSchema) then exit; end if; 
     end loop; 

     currentSchemaId := currentSchemaId + 1; 
     if (currentSchemaId > numberOfSchemas) then exit; end if;  
    end loop; 
    return count; 
END $$ language plpgsql; 

-- MTDB_RunTests 
create or replace function MTDB_RunTests(schemaNamePrefix varchar(100), rounds integer) 
returns integer as $$ 
declare 
    curs1 cursor(prefix varchar) is select table_schema || '.' || table_name from information_schema.tables where table_schema like prefix || '%' and table_type = 'VIEW'; 
    currentViewName varchar(100); 
    count integer; 
begin 
    count := 0; 
    loop 
     rounds := rounds - 1; 
     if (rounds < 0) then exit; end if; 

     open curs1(schemaNamePrefix); 
     loop 
     fetch curs1 into currentViewName; 
     if not found then exit; end if; 
     execute 'select * from ' || currentViewName; 
     count := count + 1; 
     end loop; 
     close curs1; 
    end loop; 
    return count; 
end $$ language plpgsql; 
+0

Am doğru olduğunu bellek kullanımı sadece sürece açık bir bağlantı tutmak gibi artar? Bundan kaçınmak için şemaları değiştirdiğiniz her n 'bağlantıyı kapatıp tekrar açamaz mıydınız? –

+0

Evet, bağlantıyı kapatırsak, işlem için ayrılan bellek geri döndürür. Ancak, bu da ideal değil. Bağlantı havuzu fikri, db sunucusuna eşzamanlı bağlantıların sayısını azaltmak ve bağlantı/bağlantı maliyetini kaldırmaktır (her istek için bunu yapmak zorunda kalırsak kolayca hatırlanabilir) – Samuel

cevap

2

işlemde atıl ya da sadece boşta bu bağlantılar mı? Bitmemiş işlemler hafızayı tutuyor gibi görünüyor, ya da belki bir bellek sızıntısı ya da bir şey var.

+0

Buradaki test durumu, Test süresi boyunca aynı tek bağlantı. – Samuel

+0

hiçbir açık işlem burada, bu nedenle örtük işlem moduna çalışıyor, yani burada hiçbir açık işlem sorunları olmalıdır. – Samuel

+0

, bellek sızıntısı gibi hissetmiyor, çünkü testi tekrar tekrar çalıştırırsak bellek kullanımı artmadı. Ben o db tüm sunucu belleği (sanal + fiziksel) yiyip önlemek için toplam bellek kullanımını kontrol etmek var eğer bir yolunu bilmiyorum sadece o, daha önbelleğe çeşit gibi hissediyorum. – Samuel

1

Bu iş parçacığını, etrafta arama yaparken gördüğüm gibi (benim yaptığım gibi), farklı bir bağlamda aynı sorun gibi görünen şeyin ne olduğunu buldum. Boşta OOM katili dışarı çıkana kadar (periyodik DB çökmelerine neden olan) yavaş yavaş daha fazla bellek tüketir.

Uzun bir süredir açık olan bir bağlantıyı uzun süredir devam ettiren PHP betiklerine kadar sorunu takip ettik. Bağlantıyı periyodik olarak kapatarak ve yeniden bağlayarak belleği kontrol altına alabildik.

Postgres okuduğumdan çok fazla önbellekleme yapabildiğinden, çok sayıda farklı tablonun/sorgunun bulunduğu bir oturumunuz varsa bu önbellek verileri büyümeye ve büyümeye devam edebilir.Anlamıyorum

-ken