2011-04-07 37 views
5

हम एक multitenant डेटाबेस को लागू करने के PostgreSQL का उपयोग कर मूल्यांकन कर रहे हैं, वर्तमान में हम एकल डाटाबेस-बहु-स्कीमा मॉडल पर कुछ परीक्षण चल रहे हैं (मूल रूप से, सभी किरायेदारों डाटाबेस वस्तुओं के एक ही सेट है उसी डेटाबेस के भीतर अपने स्वयं के स्कीमा के तहत)। एप्लिकेशन एक कनेक्शन पूल बनाए रखेगा जो सभी किरायेदारों/स्कीमाओं के बीच साझा किया जाएगा।PostgreSQL बैकएंड प्रक्रिया उच्च स्मृति उपयोग मुद्दा

उदा। यदि डेटाबेस में 500 किरायेदार/स्कीमा हैं और प्रत्येक किरायेदारों के पास 200 टेबल/दृश्य हैं, तालिका/दृश्यों की कुल संख्या 500 * 200 = 100,000 होगी।

चूंकि कनेक्शन पूल का उपयोग सभी किरायेदारों द्वारा किया जाएगा, अंत में प्रत्येक कनेक्शन सभी तालिकाओं/विचारों को हिट करेगा।

हमारे परीक्षणों में, जब कनेक्शन अधिक विचारों को हिट करता है, तो हमने पाया कि बैकएंड प्रक्रिया का स्मृति उपयोग काफी तेजी से बढ़ता है और उनमें से अधिकांश निजी स्मृति हैं। कनेक्शन तब तक बंद हो जाएगा जब तक कनेक्शन बंद नहीं हो जाता है।

हमारे पास एक परीक्षण केस है कि एक बैकएंड प्रक्रिया 30 जीबी मेमोरी का उपयोग करती है और अंत में स्मृति त्रुटि से बाहर हो जाती है।

मदद करने के लिए मुद्दे को समझने, मैं एक सरलीकृत परीक्षण मामलों बनाने के लिए कोड लिखा था - MTDB_destroy: किरायेदार स्कीमा स्पष्ट करने के लिए इस्तेमाल किया - MTDB_Initialize: एक multitenant डीबी बनाने के लिए इस्तेमाल - MTDB_RunTests: सरलीकृत परीक्षण का मामला, मूल रूप से सब से चयन किरायेदार एक-एक करके देखता है।

परीक्षण मेरे द्वारा की गई CentOS पर PostgreSQL 9.0.3 पर था 5.4

यकीन है कि मैं एक स्वच्छ वातावरण, मैं फिर से बनाया डेटाबेस क्लस्टर, (केवल एक चीज है और डिफ़ॉल्ट के रूप में बहुमत विन्यास छोड़ बनाने के लिए मैं बदलना होगा

यह है कि मैं क्या इस मुद्दे को दोबारा करने के लिए क्या है के बाद से MTDB_destroy कई वस्तुओं ड्रॉप करने की जरूरत है "max_locks_per_transaction" को बढ़ाने के लिए है):।

  1. एक नया डेटाबेस बनाने
  2. संलग्न कोड का उपयोग कर तीन कार्यों बनाने के नए डाटाबेस बनाया से कनेक्ट और इनिशियलाइज़ स्क्रिप्ट चलाने

    - प्रारंभ

    MTDB_Initialize ('किरायेदार', 100, 100, सच) का चयन करें;

    - यकीन नहीं करता है, तो वैक्यूम विश्लेषण उपयोगी यहाँ, मैं सिर्फ यह

    निर्वात का विश्लेषण चलाने है;

    - जाँच टेबल/विचारों INFORMATION_SCHEMA से

    चुनें TABLE_SCHEMA, TABLE_TYPE, गिनती (*) बनाया।टेबल जहां table_schema table_schema द्वारा 'किरायेदार%' समूह की तरह, table_schema द्वारा table_type ऑर्डर, table_type;

  3. नई बनाई गई डाटाबेस के लिए एक और कनेक्शन खोलने और परीक्षण स्क्रिप्ट चलाने

    - वर्तमान कनेक्शन के लिए

    चयन pg_backend_pid बैकएंड प्रक्रिया आईडी मिल();

    - एक लिनक्स कंसोल खोलें तथा ps -p चलाने के लिए और देखने के VIRT, आरईएस और SHR

    - चलाने के परीक्षण

    चयन MTDB_RunTests ('किरायेदार', 1);

टिप्पणियों:

  1. जब परीक्षण चलाने के लिए कनेक्शन पहले बनाया गया था,

    VIRT = 182MB, आरईएस = 6240K, SHR = 4648K

  2. परीक्षण चलाने के बाद एक बार, (175 सेकंड लिया)

    वीआईआरटी = 1661 एमबी आरईएस = 1.5 जीबी एसएचआर = 55 एमबी

  3. दोबारा चलाता परीक्षण फिर से (167 सेकंड)

    VIRT = 1661MB आरईएस = 1.5GB SHR = 55MB

  4. दोबारा चलाता परीक्षण फिर से

    (165 सेकंड) VIRT = 1661MB आरईएस = 1.5GB SHR = 55MB

के रूप में हम तालिकाओं की संख्या पैमाने, स्मृति उपयोगों के ऊपर परीक्षणों में भी जाना।

क्या कोई यहां बता रहा है कि क्या हो रहा है? क्या कोई तरीका है कि हम PostgreSQL बैकएंड प्रक्रिया के मेमोरी उपयोग को नियंत्रित कर सकते हैं?

धन्यवाद।

शमूएल

-- 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

क्या मैं सही ढंग से समझ रहा हूं कि स्मृति उपयोग केवल तब तक बढ़ता है जब तक आप कनेक्शन खोलते हैं? क्या आप इस से बचने के लिए स्कीमा स्विच करते समय कनेक्शन को बस बंद और दोबारा खोल नहीं सकते? –

+0

हां, अगर हम कनेक्शन बंद करते हैं, तो प्रक्रिया को आवंटित स्मृति ओएस पर वापस आती है। हालांकि, यह आदर्श नहीं है। कनेक्शन पूल का विचार डीबी सर्वर के समवर्ती कनेक्शन की संख्या को कम करना और कनेक्ट/डिस्प्ले लागत को हटा देना है (यदि हम प्रत्येक अनुरोध के लिए इसे करना चाहते हैं तो आसानी से काफी हो सकता है) – Samuel

उत्तर

2

ये कनेक्शन लेन-देन में निष्क्रिय या सिर्फ बेकार कर रहे हैं? अधूरा लेनदेन की तरह लगता है स्मृति पर पकड़ रहे हैं, या शायद आपको स्मृति रिसाव या कुछ मिल गया है।

+0

यहां परीक्षण केस क्वेरी भेज रहा है परीक्षण अवधि के माध्यम से एक ही कनेक्शन। – Samuel

+0

यहां कोई स्पष्ट लेनदेन नहीं है, इसलिए यह निहित लेनदेन मोड चला रहा है, यानी यहां कोई खुले लेनदेन के मुद्दे नहीं होने चाहिए। – Samuel

+0

यह स्मृति की लीकिंग की तरह महसूस नहीं करता है, क्योंकि अगर हम बार-बार परीक्षण फिर से चलाते हैं तो स्मृति उपयोग बढ़ता नहीं रहा है। यह किसी प्रकार की कैशिंग की तरह महसूस करता है, केवल इतना है कि मुझे नहीं पता कि कुल स्मृति उपयोग को नियंत्रित करने का कोई तरीका है ताकि इसे डीबी सर्वर पर सभी मेमोरी (भौतिक + वर्चुअल) को रोका जा सके। – Samuel

1

उन लोगों के लिए जो इस धागे को चारों ओर खोजते समय देखते हैं (जैसा मैंने किया), मैंने पाया कि एक अलग संदर्भ में एक ही समस्या क्या प्रतीत होती है। निष्क्रिय प्रक्रिया धीरे-धीरे अधिक से अधिक स्मृति का उपभोग करती है जब तक ओओएम हत्यारा उन्हें बाहर ले जाता है (आवधिक डीबी दुर्घटनाओं का कारण बनता है)।

हमने समस्या को वास्तव में लंबे समय तक चलने वाली PHP स्क्रिप्ट्स का पता लगाया जो एक कनेक्शन को लंबे समय तक खुला रखता था। हम समय-समय पर कनेक्शन बंद करने और पुनः कनेक्ट करने के द्वारा स्मृति को नियंत्रित करने में सक्षम थे।

पोस्टग्रेज़ जो मैंने पढ़ा है, उससे बहुत सारे कैशिंग होती है, इसलिए यदि आपके पास एक से अधिक टेबल/प्रश्नों को मारने वाला एक सत्र है, तो यह कैश डेटा बढ़ने और बढ़ने के लिए जारी रह सकता है।

-केन

संबंधित मुद्दे