MongoDB Sharding: покроковий практичний посібник

Шардинг — це процес поділу великого масштабу наборів даних на фрагменти менших наборів даних у кількох екземплярах MongoDB у розподіленому середовищі.

Що таке шардинг?

Шардинг MongoDB надає нам масштабоване рішення для зберігання великої кількості даних на кількох серверах, а не на одному сервері.

З практичної точки зору неможливо зберігати експоненціально зростаючі дані на одній машині. Запит величезної кількості даних, що зберігаються на одному сервері, може призвести до високого використання ресурсів і може не забезпечити задовільну пропускну здатність читання та запису.

В основному існує два типи методів масштабування, які існують для збільшення даних із системою:

Вертикальне масштабування працює з підвищенням продуктивності одного сервера шляхом додавання потужніших процесорів, оновлення оперативної пам’яті або збільшення дискового простору в системі. Але існують можливі наслідки застосування вертикального масштабування в практичних випадках використання існуючої технології та апаратних конфігурацій.

Горизонтальне масштабування працює з додаванням додаткових серверів і розподілом навантаження на кілька серверів. Оскільки кожна машина оброблятиме підмножину цілого набору даних, це забезпечує кращу ефективність і економічне рішення замість розгортання апаратного забезпечення високого класу. Але це вимагає додаткового обслуговування складної інфраструктури з великою кількістю серверів.

Шардинг Mongo DB працює на основі техніки горизонтального масштабування.

Компоненти шардингу

Для досягнення шардингу в MongoDB потрібні наступні компоненти:

Shard — це екземпляр Mongo для обробки підмножини вихідних даних. Шарди потрібно розгорнути в наборі реплік.

Mongos є екземпляром Mongo і діє як інтерфейс між клієнтською програмою та сегментованим кластером. Він працює як маршрутизатор запитів до шардів.

Config Server — це екземпляр Mongo, який зберігає метадані та деталі конфігурації кластера. MongoDB вимагає, щоб конфігураційний сервер був розгорнутий як набір реплік.

Архітектура шардингу

Кластер MongoDB складається з кількох наборів реплік.

Кожен набір реплік складається щонайменше з 3 або більше екземплярів mongo. Шардований кластер може складатися з кількох екземплярів сегментів mongo, і кожен екземпляр шарда працює в межах набору реплік сегментів. Додаток взаємодіє з Mongos, який, у свою чергу, спілкується з шардами. Тому в Sharding програми ніколи не взаємодіють безпосередньо з вузлами сегментів. Маршрутизатор запитів розподіляє підмножини даних між вузлами фрагментів на основі ключа фрагментів.

Реалізація шардингу

Виконайте наведені нижче дії для шардингу

Крок 1

  • Запустіть конфігураційний сервер у наборі реплік і ввімкніть реплікацію між ними.

mongod –configsvr –порт 27019 –replSet rs0 –dbpath C:datadata1 –bind_ip локальний хост

mongod –configsvr –порт 27018 –replSet rs0 –dbpath C:datadata2 –bind_ip локальний хост

mongod –configsvr –порт 27017 –replSet rs0 –dbpath C:datadata3 –bind_ip локальний хост

Крок 2

  • Ініціалізуйте набір реплік на одному з конфігураційних серверів.

rs.initiate( { _id : “rs0”, configsvr: true, члени: [   { _id: 0, host: “IP:27017” },   { _id: 1, host: “IP:27018” },   { _id: 2, host: “IP:27019” }    ] })

rs.initiate( { _id : "rs0",  configsvr: true,  members: [   { _id: 0, host: "IP:27017" },   { _id: 1, host: "IP:27018" },   { _id: 2, host: "IP:27019" }    ] })
{
        "ok" : 1,
        "$gleStats" : {
                "lastOpTime" : Timestamp(1593569257, 1),
                "electionId" : ObjectId("000000000000000000000000")
        },
        "lastCommittedOpTime" : Timestamp(0, 0),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593569257, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1593569257, 1)
}

Крок 3

  • Розпочніть шардинг серверів у наборі реплік і ввімкніть реплікацію між ними.
  10 способів виправити випадкове відключення контролера Xbox One

mongod –shardsvr –порт 27020 –replSet rs1 –dbpath C:datadata4 –bind_ip локальний хост

mongod –shardsvr –порт 27021 –replSet rs1 –dbpath C:datadata5 –bind_ip локальний хост

mongod –shardsvr –порт 27022 –replSet rs1 –dbpath C:datadata6 –bind_ip локальний хост

MongoDB ініціалізує перший сервер шардингу як основний, щоб перемістити використання основного сервера шардингу movePrimary метод.

Крок 4

  • Ініціалізуйте набір реплік на одному з сегментованих серверів.

rs.initiate( { _id : “rs0”, члени: [   { _id: 0, host: “IP:27020” },   { _id: 1, host: “IP:27021” },   { _id: 2, host: “IP:27022” }    ] })

rs.initiate( { _id : "rs0",  members: [   { _id: 0, host: "IP:27020" },   { _id: 1, host: "IP:27021" },   { _id: 2, host: "IP:27022" }    ] })
{
        "ok" : 1,
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593569748, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        },
        "operationTime" : Timestamp(1593569748, 1)
}

Крок 5

  • Почніть манго для розділеного кластера

mongos –порт 40000 –configdb rs0/localhost:27019,localhost:27018, localhost:27017

Крок 6

  • Підключіть сервер маршруту mongo

mongo –порт 40000

  • Тепер додайте сервери шардингу.

sh.addShard( “rs1/localhost:27020,localhost:27021,localhost:27022”)

sh.addShard( "rs1/localhost:27020,localhost:27021,localhost:27022")
{
        "shardAdded" : "rs1",
        "ok" : 1,
        "operationTime" : Timestamp(1593570212, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570212, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Крок 7

  • В оболонці mongo увімкніть сегментування БД і колекцій.
  • Увімкнути шардинг у БД

sh.enableSharding(“geekFlareDB”)

sh.enableSharding("geekFlareDB")
{
        "ok" : 1,
        "operationTime" : Timestamp(1591630612, 1),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1591630612, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Крок 8

  • Щоб розділити колекцію, потрібен шард-ключ (описано далі в цій статті).

Синтаксис: sh.shardCollection(“dbName.collectionName”, { “key” : 1 } )

sh.shardCollection("geekFlareDB.geekFlareCollection", { "key" : 1 } )
{
        "collectionsharded" : "geekFlareDB.geekFlareCollection",
        "collectionUUID" : UUID("0d024925-e46c-472a-bf1a-13a8967e97c1"),
        "ok" : 1,
        "operationTime" : Timestamp(1593570389, 3),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570389, 3),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Зверніть увагу, якщо колекція не існує, створіть її таким чином.

db.createCollection("geekFlareCollection")
{
        "ok" : 1,
        "operationTime" : Timestamp(1593570344, 4),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593570344, 5),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Крок 9

Вставте дані в колекцію. Журнали Mongo почнуть зростати, що вказуватиме на те, що балансувальник працює та намагається збалансувати дані між сегментами.

Крок 10

Останнім кроком є ​​перевірка статусу шардингу. Статус можна перевірити, виконавши наведену нижче команду на вузлі маршруту Mongos.

Статус шардингу

Перевірте статус сегментування, виконавши наведену нижче команду на вузлі маршруту mongo.

sh.status()

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5ede66c22c3262378c706d21")
  }
  shards:
        {  "_id" : "rs1",  "host" : "rs1/localhost:27020,localhost:27021,localhost:27022",  "state" : 1 }
  active mongoses:
        "4.2.7" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  5
        Last reported error:  Could not find host matching read preference { mode: "primary" } for set rs1
        Time of Reported error:  Tue Jun 09 2020 15:25:03 GMT+0530 (India Standard Time)
        Migration Results for the last 24 hours:
                No recent migrations
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "geekFlareDB",  "primary" : "rs1",  "partitioned" : true,  "version" : {  "uuid" : UUID("a770da01-1900-401e-9f34-35ce595a5d54"),  "lastMod" : 1 } }
                geekFlareDB.geekFlareCol
                        shard key: { "key" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1
                        { "key" : { "$minKey" : 1 } } -->> { "key" : { "$maxKey" : 1 } } on : rs1 Timestamp(1, 0)
                geekFlareDB.geekFlareCollection
                        shard key: { "product" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs1     1
                        { "product" : { "$minKey" : 1 } } -->> { "product" : { "$maxKey" : 1 } } on : rs1 Timestamp(1, 0)
        {  "_id" : "test",  "primary" : "rs1",  "partitioned" : false,  "version" : {  "uuid" : UUID("fbc00f03-b5b5-4d13-9d09-259d7fdb7289"),  "lastMod" : 1 } }

mongos>

Розподіл даних

Маршрутизатор Mongos розподіляє навантаження між шардами на основі ключа сегмента та для рівномірного розподілу даних; балансир вступає в дію.

  Як додати Dropbox і Google Drive до MS Office 2016 Save Locations

Ключовим компонентом для розподілу даних між фрагментами є

  • Балансувальник відіграє певну роль у балансуванні підмножини даних серед сегментованих вузлів. Балансувальник запускається, коли сервер Mongos починає розподіляти навантаження між шардами. Після запуску Balancer розподіляв дані рівномірніше. Щоб перевірити стан балансувальника, запустіть sh.status() або sh.getBalancerState() абоsh.isBalancerRunning().
mongos> sh.isBalancerRunning()
true
mongos>

АБО

mongos> sh.getBalancerState()
true
mongos>

Після вставлення даних ми могли помітити певну активність у демоні Mongos, яка стверджувала, що він переміщує деякі фрагменти для конкретних сегментів тощо, тобто балансир буде працювати, намагаючись збалансувати дані між шардами. Запущений балансир може призвести до проблем з продуктивністю; отже, пропонується запустити балансир протягом певного вікно балансира.

mongos> sh.status()
--- Sharding Status ---
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("5efbeff98a8bbb2d27231674")
  }
  shards:
        {  "_id" : "rs1",  "host" : "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022",  "state" : 1 }
        {  "_id" : "rs2",  "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",  "state" : 1 }
  active mongoses:
        "4.2.7" : 1
  autosplit:
        Currently enabled: yes
  balancer:
        Currently enabled:  yes
        Currently running:  yes
        Failed balancer rounds in last 5 attempts:  5
        Last reported error:  Could not find host matching read preference { mode: "primary" } for set rs2
        Time of Reported error:  Wed Jul 01 2020 14:39:59 GMT+0530 (India Standard Time)
        Migration Results for the last 24 hours:
                1024 : Success
  databases:
        {  "_id" : "config",  "primary" : "config",  "partitioned" : true }
                config.system.sessions
                        shard key: { "_id" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs2     1024
                        too many chunks to print, use verbose if you want to force print
        {  "_id" : "geekFlareDB",  "primary" : "rs2",  "partitioned" : true,  "version" : {  "uuid" : UUID("a8b8dc5c-85b0-4481-bda1-00e53f6f35cd"),  "lastMod" : 1 } }
                geekFlareDB.geekFlareCollection
                        shard key: { "key" : 1 }
                        unique: false
                        balancing: true
                        chunks:
                                rs2     1
                        { "key" : { "$minKey" : 1 } } -->> { "key" : { "$maxKey" : 1 } } on : rs2 Timestamp(1, 0)
        {  "_id" : "test",  "primary" : "rs2",  "partitioned" : false,  "version" : {  "uuid" : UUID("a28d7504-1596-460e-9e09-0bdc6450028f"),  "lastMod" : 1 } }

mongos>
  • Ключ фрагмента визначає логіку розподілу документів шардованої колекції між сегментами. Ключ фрагмента може бути індексованим полем або індексованим складеним полем, яке повинно бути присутнім у всіх документах колекції, яку потрібно вставити. Дані будуть розділені на частини, і кожна частина буде пов’язана з ключем фрагмента на основі діапазону. На основі запиту діапазону маршрутизатор вирішить, який шард зберігатиме фрагмент.

Ключ фрагмента можна вибрати, враховуючи п’ять властивостей:

  • Кардинальність
  • Написати розподіл
  • Прочитайте розподіл
  • Читайте націлювання
  • Прочитайте місцевість

Ідеальний шард-ключ змушує MongoDB рівномірно розподіляти навантаження між усіма шардами. Вибір хорошого шард-ключа надзвичайно важливий.

Зображення: MongoDB

Видалення вузла шарда

Перш ніж видаляти шарди з кластера, користувач повинен забезпечити безпечну міграцію даних до інших сегментів. MongoDB піклується про безпечне перенесення даних на інші вузли сегментів перед видаленням потрібного вузла сегментів.

Виконайте наведену нижче команду, щоб видалити необхідний сегмент.

Крок 1

По-перше, нам потрібно визначити ім’я хоста фрагмента, який потрібно видалити. У наведеній нижче команді буде показано список усіх шардів, наявних у кластері, а також стан шарду.

db.adminCommand( { listShards: 1 } )

mongos> db.adminCommand( { listShards: 1 } )
{
        "shards" : [
                {
                        "_id" : "rs1",
                        "host" : "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022",
                        "state" : 1
                },
                {
                        "_id" : "rs2",
                        "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",
                        "state" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1593572866, 15),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593572866, 15),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Крок 2

Виконайте наведену нижче команду, щоб видалити потрібний фрагмент із кластера. Після випуску балансир піклується про видалення фрагментів із виснажливого шард-вузла, а потім балансує розподіл решти фрагментів серед решти шард-вузлів.

db.adminCommand( { removeShard: “shardedReplicaNodes” } )

mongos> db.adminCommand( { removeShard: "rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022" } )
{
        "msg" : "draining started successfully",
        "state" : "started",
        "shard" : "rs1",
        "note" : "you need to drop or movePrimary these databases",
        "dbsToMove" : [ ],
        "ok" : 1,
        "operationTime" : Timestamp(1593572385, 2),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593572385, 2),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Крок 3

Щоб перевірити стан дренажного фрагмента, видайте ту саму команду ще раз.

db.adminCommand( { removeShard: “rs1/127.0.0.1:27020,127.0.0.1:27021,127.0.0.1:27022” } )

Нам потрібно дочекатися завершення зливу даних. Поля msg і стан покажуть, чи було завершено злив даних, як показано нижче

"msg" : "draining ongoing",
"state" : "ongoing",

Ми також можемо перевірити статус за допомогою команди sh.status(). Після видалення шардований вузол не відображатиметься у виводі. Але якщо злив триватиме, сегментований вузол матиме статус зливу як true.

Крок 4

Продовжуйте перевіряти стан зливу за допомогою тієї ж команди, наведеної вище, доки потрібний фрагмент не буде повністю видалено.
Після завершення вихідні дані команди відображатимуть повідомлення та стануть завершеними.

"msg" : "removeshard completed successfully",
"state" : "completed",
"shard" : "rs1",
"ok" : 1,

Крок 5

Нарешті, нам потрібно перевірити фрагменти, що залишилися в кластері. Щоб перевірити статус, введіть sh.status() або db.adminCommand( { listShards: 1 } )

mongos> db.adminCommand( { listShards: 1 } )
{
        "shards" : [
                {
                        "_id" : "rs2",
                        "host" : "rs2/127.0.0.1:27023,127.0.0.1:27024,127.0.0.1:27025",
                        "state" : 1
                }
        ],
        "ok" : 1,
        "operationTime" : Timestamp(1593575215, 3),
        "$clusterTime" : {
                "clusterTime" : Timestamp(1593575215, 3),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
        }
}

Тут ми бачимо, що видаленого фрагмента більше немає в списку фрагментів.

Переваги шардингу перед реплікацією

  • Під час реплікації основний вузол обробляє всі операції запису, тоді як вторинні сервери повинні підтримувати резервні копії або обслуговувати операції лише для читання. Але в шардингу разом із наборами реплік навантаження розподіляється між кількома серверами.
  • Один набір реплік обмежений 12 вузлами, але немає обмежень щодо кількості сегментів.
  • Для реплікації потрібне апаратне забезпечення високого класу або вертикальне масштабування для обробки великих наборів даних, що занадто дорого в порівнянні з додаванням додаткових серверів у сегментації.
  • У реплікації продуктивність читання можна підвищити, додавши більше підлеглих/вторинних серверів, тоді як у шардингу продуктивність як читання, так і запису буде покращена шляхом додавання більшої кількості вузлів сегментів.

Обмеження шардингу

  • Кластер Sharded не підтримує унікальне індексування шардів, доки перед унікальним індексом не буде повний ключ сегмента.
  • Усі операції оновлення сегментованої колекції для одного або кількох документів мають містити сегментований ключ або поле _id у запиті.
  • Колекції можна шардувати, якщо їх розмір не перевищує вказане порогове значення. Цей поріг можна оцінити на основі середнього розміру всіх сегментних ключів і налаштованого розміру фрагментів.
  • Шардинг включає робочі обмеження щодо максимального розміру колекції або кількості розділень.
  • Вибір неправильних ключів фрагментів може призвести до погіршення продуктивності.

Висновок

MongoDB пропонує вбудований шардинг для реалізації великої бази даних без шкоди для продуктивності. Сподіваюся, наведене вище допоможе вам налаштувати шардинг MongoDB. Далі ви можете ознайомитися з деякими часто використовуваними командами MongoDB.