MongoDB
 sql >> डेटाबेस >  >> NoSQL >> MongoDB

MongoDB के साथ GUID आधारित शार्ड कुंजी को प्रोग्रामेटिक रूप से पूर्व-विभाजित कैसे करें

हम प्रारंभिक डेटा आकार (120 जीबी) जानते हैं और हम जानते हैं कि मोंगोडीबी में डिफ़ॉल्ट अधिकतम खंड आकार 64 एमबी है। यदि हम 64MB को 120GB में विभाजित करते हैं तो हमें 1920 मिलता है - इसलिए यह न्यूनतम संख्या है जिसे हमें शुरू करना चाहिए। जैसा कि 2048 होता है, 16 की शक्ति को 2 से विभाजित किया जाता है, और यह देखते हुए कि GUID (हमारी शार्ड कुंजी) हेक्स आधारित है, यह 1920 की तुलना में निपटने के लिए बहुत आसान संख्या है (नीचे देखें)।

नोट: यह पूर्व-विभाजन पहले . किया जाना चाहिए कोई भी डेटा संग्रह में जोड़ा जाता है। यदि आप डेटा वाले संग्रह पर इनेबलशर्डिंग () कमांड का उपयोग करते हैं, तो MongoDB डेटा को स्वयं विभाजित कर देगा और आप इसे तब चला रहे होंगे जब चंक्स पहले से मौजूद हों - जिससे काफी अजीब चंक वितरण हो सकता है, इसलिए सावधान रहें।

इस उत्तर के प्रयोजनों के लिए, मान लेते हैं कि डेटाबेस को users . कहा जा रहा है और संग्रह को userInfo . कहा जाता है . आइए यह भी मान लें कि GUID को _id . में लिखा जाएगा खेत। उन मापदंडों के साथ हम एक mongos . से कनेक्ट होंगे और निम्न आदेश चलाएँ:

// first switch to the users DB
use users;
// now enable sharding for the users DB
sh.enableSharding("users"); 
// enable sharding on the relevant collection
sh.shardCollection("users.userInfo", {"_id" : 1});
// finally, disable the balancer (see below for options on a per-collection basis)
// this prevents migrations from kicking off and interfering with the splits by competing for meta data locks
sh.stopBalancer(); 

अब, ऊपर की गणना के अनुसार, हमें GUID रेंज को 2048 विखंडू में विभाजित करने की आवश्यकता है। ऐसा करने के लिए हमें कम से कम 3 हेक्स अंक (16 ^ 3 =4096) की आवश्यकता है और हम उन्हें श्रेणियों के लिए सबसे महत्वपूर्ण अंकों (यानी 3 सबसे बाईं ओर) में डाल देंगे। फिर से, इसे mongos . से चलाया जाना चाहिए खोल

// Simply use a for loop for each digit
for ( var x=0; x < 16; x++ ){
  for( var y=0; y<16; y++ ) {
  // for the innermost loop we will increment by 2 to get 2048 total iterations
  // make this z++ for 4096 - that would give ~30MB chunks based on the original figures
    for ( var z=0; z<16; z+=2 ) {
    // now construct the GUID with zeroes for padding - handily the toString method takes an argument to specify the base
        var prefix = "" + x.toString(16) + y.toString(16) + z.toString(16) + "00000000000000000000000000000";
        // finally, use the split command to create the appropriate chunk
        db.adminCommand( { split : "users.userInfo" , middle : { _id : prefix } } );
    }
  }
}

एक बार यह हो जाने के बाद, आइए sh.status() . का उपयोग करके खेल की स्थिति की जांच करें सहायक:

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "version" : 3,
        "minCompatibleVersion" : 3,
        "currentVersion" : 4,
        "clusterId" : ObjectId("527056b8f6985e1bcce4c4cb")
}
  shards:
        {  "_id" : "shard0000",  "host" : "localhost:30000" }
        {  "_id" : "shard0001",  "host" : "localhost:30001" }
        {  "_id" : "shard0002",  "host" : "localhost:30002" }
        {  "_id" : "shard0003",  "host" : "localhost:30003" }
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "users",  "partitioned" : true,  "primary" : "shard0001" }
                users.userInfo
                        shard key: { "_id" : 1 }
                        chunks:
                                shard0001       2049
                        too many chunks to print, use verbose if you want to force print

हमारे पास हमारे 2048 भाग हैं (न्यूनतम/अधिकतम भाग के लिए एक अतिरिक्त धन्यवाद), लेकिन वे सभी अभी भी मूल शार्क पर हैं क्योंकि बैलेंसर बंद है। तो, चलिए बैलेंसर को फिर से सक्षम करते हैं:

sh.startBalancer();

यह तुरंत संतुलन बनाना शुरू कर देगा, और यह अपेक्षाकृत जल्दी होगा क्योंकि सभी भाग खाली हैं, लेकिन इसमें अभी भी थोड़ा समय लगेगा (यदि यह अन्य संग्रहों से माइग्रेशन के साथ प्रतिस्पर्धा कर रहा है तो बहुत धीमा)। एक बार कुछ समय बीत जाने के बाद, sh.status() चलाएं बार-बार आपके पास (चाहिए) - 2048 विखंडू सभी अच्छी तरह से 4 शार्क में विभाजित हो गए और एक प्रारंभिक डेटा लोड के लिए तैयार:

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "version" : 3,
        "minCompatibleVersion" : 3,
        "currentVersion" : 4,
        "clusterId" : ObjectId("527056b8f6985e1bcce4c4cb")
}
  shards:
        {  "_id" : "shard0000",  "host" : "localhost:30000" }
        {  "_id" : "shard0001",  "host" : "localhost:30001" }
        {  "_id" : "shard0002",  "host" : "localhost:30002" }
        {  "_id" : "shard0003",  "host" : "localhost:30003" }
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "users",  "partitioned" : true,  "primary" : "shard0001" }
                users.userInfo
                        shard key: { "_id" : 1 }
                        chunks:
                                shard0000       512
                                shard0002       512
                                shard0003       512
                                shard0001       513
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0002" }

अब आप डेटा लोड करना शुरू करने के लिए तैयार हैं, लेकिन पूरी तरह से गारंटी देने के लिए कि आपका डेटा लोड पूरा होने तक कोई विभाजन या माइग्रेट नहीं होता है, आपको एक और काम करने की ज़रूरत है - आयात की अवधि के लिए बैलेंसर और ऑटोस्प्लिटिंग बंद करें:

  • सभी संतुलन को अक्षम करने के लिए, इस आदेश को mongos से चलाएँ:sh.stopBalancer()
  • यदि आप अन्य संतुलन संचालन को चालू रखना चाहते हैं, तो आप एक विशिष्ट संग्रह पर अक्षम कर सकते हैं। एक उदाहरण के रूप में उपरोक्त नाम स्थान का उपयोग करना:sh.disableBalancing("users.userInfo")
  • लोड के दौरान ऑटो विभाजन को बंद करने के लिए, आपको प्रत्येक mongos को पुनरारंभ करना होगा आप --noAutoSplit . के साथ डेटा लोड करने के लिए उपयोग कर रहे होंगे विकल्प।

एक बार आयात पूरा हो जाने पर, आवश्यकतानुसार चरणों को उलट दें (sh.startBalancer() , sh.enableBalancing("users.userInfo") , और mongos . को पुनरारंभ करें बिना --noAutoSplit . के ) सब कुछ डिफ़ॉल्ट सेटिंग्स पर वापस करने के लिए।

**

अपडेट:गति के लिए अनुकूलन

**

यदि आप जल्दी में नहीं हैं तो ऊपर का तरीका ठीक है। जैसे ही चीजें खड़ी होती हैं, और जैसा कि आप पाएंगे कि यदि आप इसका परीक्षण करते हैं, तो बैलेंसर बहुत तेज नहीं है - यहां तक ​​​​कि खाली टुकड़ों के साथ भी। इसलिए जैसे-जैसे आप अपने द्वारा बनाए गए विखंडू की संख्या बढ़ाते हैं, इसे संतुलित करने में उतना ही अधिक समय लगेगा। मैंने देखा है कि 2048 विखंडू को संतुलित करने में 30 मिनट से अधिक समय लगता है, हालांकि यह परिनियोजन के आधार पर अलग-अलग होगा।

यह परीक्षण के लिए, या अपेक्षाकृत शांत क्लस्टर के लिए ठीक हो सकता है, लेकिन बैलेंसर बंद होने और किसी अन्य अपडेट की आवश्यकता नहीं होने से व्यस्त क्लस्टर पर सुनिश्चित करना बहुत कठिन होगा। तो, हम चीजों को कैसे गति देते हैं?

इसका उत्तर कुछ मैनुअल चालों को जल्दी करना है, फिर एक बार अपने संबंधित शार्क पर होने के बाद विखंडू को विभाजित करें। ध्यान दें कि यह केवल कुछ शार्प कुंजियों (जैसे बेतरतीब ढंग से वितरित यूयूआईडी), या कुछ डेटा एक्सेस पैटर्न के साथ वांछनीय है, इसलिए सावधान रहें कि परिणामस्वरूप आप खराब डेटा वितरण के साथ समाप्त न हों।

ऊपर दिए गए उदाहरण का उपयोग करते हुए हमारे पास 4 शार्क हैं, इसलिए सभी विभाजन करने के बजाय, संतुलन बनाने के बजाय, हम 4 में विभाजित हो जाते हैं। फिर हम मैन्युअल रूप से प्रत्येक शार्प पर एक चंक डालते हैं, और फिर अंत में हम उन हिस्सों को आवश्यक संख्या में विभाजित करते हैं।

ऊपर के उदाहरण की श्रेणियां इस तरह दिखेंगी:

$min --> "40000000000000000000000000000000"
"40000000000000000000000000000000" --> "80000000000000000000000000000000"
"80000000000000000000000000000000" --> "c0000000000000000000000000000000"
"c0000000000000000000000000000000" --> $max     

इन्हें बनाने के लिए केवल 4 कमांड हैं, लेकिन चूंकि हमारे पास यह है, इसलिए ऊपर दिए गए लूप को सरलीकृत/संशोधित रूप में फिर से उपयोग क्यों न करें:

for ( var x=4; x < 16; x+=4){
    var prefix = "" + x.toString(16) + "0000000000000000000000000000000";
    db.adminCommand( { split : "users.userInfo" , middle : { _id : prefix } } ); 
} 

थिंक अब कैसा दिखता है - हमारे पास हमारे 4 भाग हैं, सभी shard0001 पर:

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "version" : 4,
    "minCompatibleVersion" : 4,
    "currentVersion" : 5,
    "clusterId" : ObjectId("53467e59aea36af7b82a75c1")
}
  shards:
    {  "_id" : "shard0000",  "host" : "localhost:30000" }
    {  "_id" : "shard0001",  "host" : "localhost:30001" }
    {  "_id" : "shard0002",  "host" : "localhost:30002" }
    {  "_id" : "shard0003",  "host" : "localhost:30003" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0001" }
    {  "_id" : "users",  "partitioned" : true,  "primary" : "shard0001" }
        users.userInfo
            shard key: { "_id" : 1 }
            chunks:
                shard0001   4
            { "_id" : { "$minKey" : 1 } } -->> { "_id" : "40000000000000000000000000000000" } on : shard0001 Timestamp(1, 1) 
            { "_id" : "40000000000000000000000000000000" } -->> { "_id" : "80000000000000000000000000000000" } on : shard0001 Timestamp(1, 3) 
            { "_id" : "80000000000000000000000000000000" } -->> { "_id" : "c0000000000000000000000000000000" } on : shard0001 Timestamp(1, 5) 
            { "_id" : "c0000000000000000000000000000000" } -->> { "_id" : { "$maxKey" : 1 } } on : shard0001 Timestamp(1, 6)                    

हम $min . छोड़ देंगे जहां वह है, वहां चकनाचूर करें और अन्य तीन को स्थानांतरित करें। आप इसे प्रोग्रामिक रूप से कर सकते हैं, लेकिन यह इस बात पर निर्भर करता है कि शुरुआत में चंक्स कहाँ रहते हैं, आपने अपने शार्क का नाम कैसे रखा है आदि। इसलिए मैं इस मैनुअल को अभी के लिए छोड़ दूँगा, यह बहुत कठिन नहीं है - बस 3 moveChunk आदेश:

mongos> sh.moveChunk("users.userInfo", {"_id" : "40000000000000000000000000000000"}, "shard0000")
{ "millis" : 1091, "ok" : 1 }
mongos> sh.moveChunk("users.userInfo", {"_id" : "80000000000000000000000000000000"}, "shard0002")
{ "millis" : 1078, "ok" : 1 }
mongos> sh.moveChunk("users.userInfo", {"_id" : "c0000000000000000000000000000000"}, "shard0003")
{ "millis" : 1083, "ok" : 1 }          

आइए दोबारा जांचें, और सुनिश्चित करें कि विखंडू वहीं हैं जहां हम उनसे होने की उम्मीद करते हैं:

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "version" : 4,
    "minCompatibleVersion" : 4,
    "currentVersion" : 5,
    "clusterId" : ObjectId("53467e59aea36af7b82a75c1")
}
  shards:
    {  "_id" : "shard0000",  "host" : "localhost:30000" }
    {  "_id" : "shard0001",  "host" : "localhost:30001" }
    {  "_id" : "shard0002",  "host" : "localhost:30002" }
    {  "_id" : "shard0003",  "host" : "localhost:30003" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0001" }
    {  "_id" : "users",  "partitioned" : true,  "primary" : "shard0001" }
        users.userInfo
            shard key: { "_id" : 1 }
            chunks:
                shard0001   1
                shard0000   1
                shard0002   1
                shard0003   1
            { "_id" : { "$minKey" : 1 } } -->> { "_id" : "40000000000000000000000000000000" } on : shard0001 Timestamp(4, 1) 
            { "_id" : "40000000000000000000000000000000" } -->> { "_id" : "80000000000000000000000000000000" } on : shard0000 Timestamp(2, 0) 
            { "_id" : "80000000000000000000000000000000" } -->> { "_id" : "c0000000000000000000000000000000" } on : shard0002 Timestamp(3, 0) 
            { "_id" : "c0000000000000000000000000000000" } -->> { "_id" : { "$maxKey" : 1 } } on : shard0003 Timestamp(4, 0)  

यह ऊपर हमारी प्रस्तावित श्रेणियों से मेल खाता है, इसलिए सब कुछ अच्छा लगता है। अब ऊपर दिए गए मूल लूप को प्रत्येक शार्क पर "जगह में" विभाजित करने के लिए चलाएं और जैसे ही लूप समाप्त होता है, हमारे पास संतुलित वितरण होना चाहिए। एक और sh.status() चीजों की पुष्टि करनी चाहिए:

mongos> for ( var x=0; x < 16; x++ ){
...   for( var y=0; y<16; y++ ) {
...   // for the innermost loop we will increment by 2 to get 2048 total iterations
...   // make this z++ for 4096 - that would give ~30MB chunks based on the original figures
...     for ( var z=0; z<16; z+=2 ) {
...     // now construct the GUID with zeroes for padding - handily the toString method takes an argument to specify the base
...         var prefix = "" + x.toString(16) + y.toString(16) + z.toString(16) + "00000000000000000000000000000";
...         // finally, use the split command to create the appropriate chunk
...         db.adminCommand( { split : "users.userInfo" , middle : { _id : prefix } } );
...     }
...   }
... }          
{ "ok" : 1 }
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "version" : 4,
    "minCompatibleVersion" : 4,
    "currentVersion" : 5,
    "clusterId" : ObjectId("53467e59aea36af7b82a75c1")
}
  shards:
    {  "_id" : "shard0000",  "host" : "localhost:30000" }
    {  "_id" : "shard0001",  "host" : "localhost:30001" }
    {  "_id" : "shard0002",  "host" : "localhost:30002" }
    {  "_id" : "shard0003",  "host" : "localhost:30003" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0001" }
    {  "_id" : "users",  "partitioned" : true,  "primary" : "shard0001" }
        users.userInfo
            shard key: { "_id" : 1 }
            chunks:
                shard0001   513
                shard0000   512
                shard0002   512
                shard0003   512
            too many chunks to print, use verbose if you want to force print    

और वहां आपके पास है - बैलेंसर की प्रतीक्षा नहीं, वितरण पहले से ही है।




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB और C#:केस असंवेदनशील खोज

  2. स्प्रिंग डेटा MongoDB में प्रश्नों के लिए एक गाइड

  3. mongodb में $match _id . में एग्रीगेट का उपयोग कैसे करें

  4. ClusterControl में अपने क्लस्टर टोपोलॉजी को विज़ुअलाइज़ करना

  5. मोंगोडीबी गिनती दस्तावेज़ ()