हम एक 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" को बढ़ाने के लिए है):।
- एक नया डेटाबेस बनाने
संलग्न कोड का उपयोग कर तीन कार्यों बनाने के नए डाटाबेस बनाया से कनेक्ट और इनिशियलाइज़ स्क्रिप्ट चलाने
- प्रारंभ
MTDB_Initialize ('किरायेदार', 100, 100, सच) का चयन करें;
- यकीन नहीं करता है, तो वैक्यूम विश्लेषण उपयोगी यहाँ, मैं सिर्फ यह
निर्वात का विश्लेषण चलाने है;
- जाँच टेबल/विचारों INFORMATION_SCHEMA से
चुनें TABLE_SCHEMA, TABLE_TYPE, गिनती (*) बनाया।टेबल जहां table_schema table_schema द्वारा 'किरायेदार%' समूह की तरह, table_schema द्वारा table_type ऑर्डर, table_type;
नई बनाई गई डाटाबेस के लिए एक और कनेक्शन खोलने और परीक्षण स्क्रिप्ट चलाने
- वर्तमान कनेक्शन के लिए
चयन pg_backend_pid बैकएंड प्रक्रिया आईडी मिल();
- एक लिनक्स कंसोल खोलें तथा ps -p चलाने के लिए और देखने के VIRT, आरईएस और SHR
- चलाने के परीक्षण
चयन MTDB_RunTests ('किरायेदार', 1);
टिप्पणियों:
जब परीक्षण चलाने के लिए कनेक्शन पहले बनाया गया था,
VIRT = 182MB, आरईएस = 6240K, SHR = 4648K
परीक्षण चलाने के बाद एक बार, (175 सेकंड लिया)
वीआईआरटी = 1661 एमबी आरईएस = 1.5 जीबी एसएचआर = 55 एमबी
दोबारा चलाता परीक्षण फिर से (167 सेकंड)
VIRT = 1661MB आरईएस = 1.5GB SHR = 55MB
दोबारा चलाता परीक्षण फिर से
(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;
क्या मैं सही ढंग से समझ रहा हूं कि स्मृति उपयोग केवल तब तक बढ़ता है जब तक आप कनेक्शन खोलते हैं? क्या आप इस से बचने के लिए स्कीमा स्विच करते समय कनेक्शन को बस बंद और दोबारा खोल नहीं सकते? –
हां, अगर हम कनेक्शन बंद करते हैं, तो प्रक्रिया को आवंटित स्मृति ओएस पर वापस आती है। हालांकि, यह आदर्श नहीं है। कनेक्शन पूल का विचार डीबी सर्वर के समवर्ती कनेक्शन की संख्या को कम करना और कनेक्ट/डिस्प्ले लागत को हटा देना है (यदि हम प्रत्येक अनुरोध के लिए इसे करना चाहते हैं तो आसानी से काफी हो सकता है) – Samuel