MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Cách lập trình phân tách trước một khóa phân đoạn dựa trên GUID với MongoDB

Chúng tôi biết kích thước dữ liệu intial (120GB) và chúng tôi biết kích thước chunk tối đa mặc định trong MongoDB là 64MB. Nếu chúng ta chia 64MB thành 120GB, chúng ta nhận được 1920 - đó là số lượng khối tối thiểu mà chúng ta nên xem xét để bắt đầu. Vì năm 2048 xảy ra một lũy thừa của 16 chia cho 2 và do GUID (khóa phân đoạn của chúng tôi) dựa trên hệ lục phân, đó là một con số dễ giải quyết hơn nhiều so với 1920 (xem bên dưới).

LƯU Ý: Việc tách trước này phải được thực hiện trước khi bất kỳ dữ liệu nào được thêm vào bộ sưu tập. Nếu bạn sử dụng lệnh enableSharding () trên một tập hợp có chứa dữ liệu, MongoDB sẽ tự phân chia dữ liệu và sau đó bạn sẽ chạy điều này trong khi các phần đã tồn tại - điều này có thể dẫn đến phân phối phân đoạn khá kỳ lạ, vì vậy hãy cẩn thận.

Với mục đích của câu trả lời này, hãy giả sử rằng cơ sở dữ liệu sẽ được gọi là users và bộ sưu tập được gọi là userInfo . Cũng giả sử rằng GUID sẽ được viết vào _id đồng ruộng. Với các tham số đó, chúng tôi sẽ kết nối với mongos và chạy các lệnh sau:

// 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(); 

Bây giờ, theo phép tính ở trên, chúng ta cần chia phạm vi GUID thành 2048 phần. Để làm được điều đó, chúng ta cần ít nhất 3 chữ số hex (16 ^ 3 =4096) và chúng ta sẽ đặt chúng vào các chữ số có nghĩa nhất (tức là 3 chữ số ngoài cùng bên trái) cho các phạm vi. Một lần nữa, điều này phải được chạy từ mongos vỏ

// 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 } } );
    }
  }
}

Sau khi hoàn tất, hãy kiểm tra trạng thái chơi bằng sh.status() người trợ giúp:

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

Chúng tôi có 2048 phần (cộng thêm một phần nhờ các phần tối thiểu / tối đa), nhưng tất cả chúng vẫn ở trên phân đoạn ban đầu vì bộ cân bằng bị tắt. Vì vậy, hãy bật lại trình cân bằng:

sh.startBalancer();

Điều này sẽ ngay lập tức bắt đầu cân bằng và nó sẽ tương đối nhanh chóng vì tất cả các phần đều trống, nhưng vẫn sẽ mất một chút thời gian (chậm hơn nhiều nếu nó đang cạnh tranh với việc di chuyển từ các bộ sưu tập khác). Sau khi một khoảng thời gian trôi qua, hãy chạy sh.status() một lần nữa và ở đó bạn (nên) có nó - tất cả 2048 phần đều được phân tách độc đáo thành 4 phần và sẵn sàng cho tải dữ liệu ban đầu:

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

Bây giờ, bạn đã sẵn sàng để bắt đầu tải dữ liệu, nhưng để hoàn toàn đảm bảo rằng không có hiện tượng chia tách hoặc di chuyển nào xảy ra cho đến khi quá trình tải dữ liệu của bạn hoàn tất, bạn cần phải làm một việc nữa - tắt bộ cân bằng và tự động tách trong thời gian nhập:

  • Để tắt tất cả cân bằng, hãy chạy lệnh này từ mongos:sh.stopBalancer()
  • Nếu bạn muốn để các hoạt động cân bằng khác đang chạy, bạn có thể tắt trên một bộ sưu tập cụ thể. Sử dụng không gian tên ở trên làm ví dụ:sh.disableBalancing("users.userInfo")
  • Để tắt tính năng tự động chia nhỏ trong khi tải, bạn cần khởi động lại từng mongos bạn sẽ sử dụng để tải dữ liệu bằng --noAutoSplit tùy chọn.

Sau khi nhập xong, hãy đảo ngược các bước nếu cần (sh.startBalancer() , sh.enableBalancing("users.userInfo") và khởi động lại mongos không có --noAutoSplit ) để đưa mọi thứ về cài đặt mặc định.

**

Cập nhật:Tối ưu hóa cho tốc độ

**

Cách tiếp cận trên là tốt nếu bạn không vội vàng. Khi mọi thứ đứng yên và bạn sẽ phát hiện ra nếu bạn kiểm tra điều này, bộ cân bằng không nhanh lắm - ngay cả với những khối trống. Do đó, khi bạn tăng số lượng các khối bạn tạo, thì thời gian cân bằng càng mất nhiều thời gian. Tôi đã thấy mất hơn 30 phút để hoàn thành việc cân bằng 2048 phần mặc dù điều này sẽ khác nhau tùy thuộc vào việc triển khai.

Điều đó có thể ổn để thử nghiệm hoặc đối với một cụm tương đối yên tĩnh, nhưng việc tắt bộ cân bằng và không yêu cầu cập nhật nào khác can thiệp sẽ khó đảm bảo hơn nhiều trên một cụm bận. Vậy, làm cách nào để tăng tốc độ?

Câu trả lời là thực hiện một số động tác thủ công sớm, sau đó chia nhỏ các phần khi chúng đã ở trên các phân đoạn tương ứng của chúng. Lưu ý rằng điều này chỉ mong muốn với một số khóa phân đoạn nhất định (như UUID được phân phối ngẫu nhiên) hoặc các mẫu truy cập dữ liệu nhất định, vì vậy hãy cẩn thận để không dẫn đến việc phân phối dữ liệu kém.

Sử dụng ví dụ trên, chúng tôi có 4 phân đoạn, vì vậy thay vì thực hiện tất cả các phân tách, sau đó cân bằng, chúng tôi chia thành 4 thay thế. Sau đó, chúng tôi đặt một đoạn trên mỗi phân đoạn bằng cách di chuyển chúng theo cách thủ công và cuối cùng chúng tôi chia các đoạn đó thành số lượng cần thiết.

Các phạm vi trong ví dụ trên sẽ giống như sau:

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

Chỉ có 4 lệnh để tạo các lệnh này, nhưng vì chúng ta đã có nó, tại sao không sử dụng lại vòng lặp ở trên ở dạng đơn giản hóa / sửa đổi:

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

Đây là cách suy nghĩ trông bây giờ - chúng tôi có 4 phần của chúng tôi, tất cả đều nằm trên 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)                    

Chúng tôi sẽ để lại $min chunk vị trí của nó, và di chuyển ba cái còn lại. Bạn có thể thực hiện việc này theo chương trình, nhưng nó phụ thuộc vào vị trí của các phần ban đầu, cách bạn đặt tên cho các phần của mình, v.v. vì vậy tôi sẽ để lại sổ tay hướng dẫn này ngay bây giờ, nó không quá rắc rối - chỉ cần 3 moveChunk lệnh:

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 }          

Hãy kiểm tra kỹ và đảm bảo rằng các phần đó ở đúng nơi mà chúng ta mong đợi:

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)  

Điều đó phù hợp với các phạm vi được đề xuất của chúng tôi ở trên, vì vậy tất cả đều có vẻ tốt. Bây giờ hãy chạy vòng lặp ban đầu ở trên để chia chúng "tại chỗ" trên mỗi phân đoạn và chúng ta sẽ có một phân phối cân bằng ngay sau khi vòng lặp kết thúc. Thêm một sh.status() nên xác nhận những điều:

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    

Và bạn đã có nó - không cần đợi bộ cân bằng, phân phối đã được đồng đều.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Cách thay thế chuỗi con trong tài liệu mongodb

  2. MongoDB Java Inserting Throws org.bson.codecs.configuration.CodecConfigurationException:Không thể tìm thấy codec cho lớp io.github.ilkgunel.mongodb.Pojo

  3. Chuẩn hóa MongoDB, khóa ngoại và tham gia

  4. Thêm Zeros hàng đầu trong SQL

  5. Cách sử dụng các biến trong hàm bản đồ MongoDB Map-Reduce