Теги Shard — это новая функция в MongoDB версии 2.2.0. Предполагается, что принудительная запись поступает в локальный центр обработки данных, но его также можно использовать для закрепления коллекции на осколке или наборе осколков.
Примечание: чтобы попробовать это, вам придется использовать 2.2.0-rc0 или выше.
Чтобы поиграть с этой функцией, сначала вам нужно раскрутить кластер:
> sharding = new ShardingTest({shards:3,chunksize:1})
Эта команда запустит 3 шарда, сервер конфигурации и монгос . Он также начнет выпускать журналы со всех серверов в стандартный вывод, поэтому я рекомендую отложить эту оболочку и использовать другую, начиная с этого момента.
Запустите новую оболочку и подключитесь к mongos (по умолчанию это порт 30999) и создайте несколько закрытых коллекций и данных для игры:
> // remember, different shell > conn = new Mongo("localhost:30999") > db = conn.getDB("villains") > > // shard db > sh.enableSharding("villains") > > // shard collections > sh.shardCollection("villains.joker", {jokes:1}); > sh.shardCollection("villains.two-face", {luck:1}); > sh.shardCollection("villains.poison ivy", {flora:1}); > > // add data > for (var i=0; i<100000; i++) { db.joker.insert({jokes: Math.random(), count: i, time: new Date()}); } > for (var i=0; i<100000; i++) { db["two-face"].insert({luck: Math.random(), count: i, time: new Date()}); } > for (var i=0; i<100000; i++) { db["poison ivy"].insert({flora: Math.random(), count: i, time: new Date()}); }
Теперь у нас есть 3 осколка и 3 злодея. Если вы посмотрите, где находятся куски, вы увидите, что они довольно равномерно распределены среди осколков:
> use config > db.chunks.find({ns: "villains.joker"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } > db.chunks.find({ns: "villains.two-face"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } > db.chunks.find({ns: "villains.poison ivy"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0002" } { "shard" : "shard0002" }
Однако злодеи, как правило, не очень хорошо играют с другими, поэтому мы хотели бы разделить коллекции: 1 злодей на осколок. Наша цель:
осколок | Пространство имен |
---|---|
shard0000 | «Villains.joker» |
shard0001 | «Villains.two-лицо» |
shard0002 | «Злодеи. Ядовитый плющ» |
Для этого мы будем использовать теги . Тег описывает свойство шарда, любое свойство (они очень гибкие). Таким образом, вы можете пометить осколок как «быстрый», «медленный», «восточное побережье» или «место в стойке».
В этом примере мы хотим пометить осколок как принадлежащий определенному злодею, поэтому мы добавим псевдонимы злодеев в качестве тегов.
> sh.addShardTag("shard0000", "mr. j") > sh.addShardTag("shard0001", "harv") > sh.addShardTag("shard0002", "ivy")
Это говорит: «Поместите любые куски с пометкой г-н. J ‘на Shard0000. «
Второе, что мы должны сделать, — это создать правило: «Для всех кусков, созданных в коллекции villains.joker, присвойте им тег« mr. у»«. Для этого мы можем использовать помощник addTagRange :
> sh.addTagRange("villains.joker", {jokes:MinKey}, {jokes:MaxKey}, "mr. j")
Это говорит: «Отметьте каждый кусок в villains.joker с помощью« г-н. j ‘tag ”(MinKey — отрицательная бесконечность, MaxKey — положительная бесконечность, поэтому все куски попадают в этот диапазон).
Теперь давайте сделаем то же самое для двух других коллекций:
> sh.addTagRange("villains.two-face", {luck:MinKey}, {luck:MaxKey}, "harv") > sh.addTagRange("villains.poison ivy", {flora:MinKey}, {flora:MaxKey}, "ivy")
Теперь подождите пару минут (потребуется некоторое время, чтобы восстановить баланс), а затем посмотрите на фрагменты этих коллекций.
> use config > db.chunks.find({ns: "villains.joker"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } > db.chunks.find({ns: "villains.two-face"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } > db.chunks.find({ns: "villains.poison ivy"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" }
Масштабирование с тегами
Очевидно, что Two-Face не очень доволен этим соглашением и сразу же запрашивает данные у двух серверов. Мы можем переместить коллекции Joker и Poison Ivy в один осколок и расширить Harvey до двух, манипулируя тегами:
> // move Poison Ivy to shard0000 > sh.addShardTag("shard0000", "ivy") > sh.removeShardTag("shard0002", "ivy") > > // expand Two-Face to shard0002 > sh.addShardTag("shard0002", "harv")
Теперь, если вы подождете пару минут и посмотрите на чанки, вы увидите, что коллекция Two-Face распределена по 2 осколкам, а две другие находятся на shard0000.
> db.chunks.find({ns: "villains.poison ivy"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } { "shard" : "shard0000" } > db.chunks.find({ns: "villains.two-face"}, {shard:1, _id:0}).sort({shard:1}) { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0001" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" } { "shard" : "shard0002" }
Однако, это все еще не совсем правильно для Харви, он хотел бы, чтобы один осколок был хорошим, а другой — плохим. Допустим, мы пользуемся преимуществами нового предложения Amazon и заменяем shard0002 на твердотельные накопители. Затем мы делим трафик: отправляем 50% записей Харви на осколок SSD и 50% на осколок вращающегося диска. Сначала мы добавим теги в шарды, описывая их:
> sh.addShardTag("shard0001", "spinning") > sh.addShardTag("shard0002", "ssd")
Значение поля «luck» находится в диапазоне от 0 до 1, поэтому мы хотим сказать: «Если luck <.5, отправьте это на вращающийся диск. Если удача> = .5, отправьте на SSD ».
> sh.addTagRange("villains.two-face", {luck:MinKey}, {luck:.5}, "spinning") > sh.addTagRange("villains.two-face", {luck:.5}, {luck:MaxKey}, "ssd")
Теперь документы «неудачи» будут записываться на медленный диск, а документы «удачи» записываться на SSD.
Добавляя новые серверы, мы можем контролировать, какую нагрузку они получают. Маркировка дает операторам тонну контроля над тем, какие коллекции идут куда.
Наконец, я написал небольшой скрипт, который добавляет «домашний» метод в коллекции, чтобы прикрепить их к одному тегу. Пример использования:
> // load the script > load("batman.js") > // put foo on bar > db.foo.home("bar") > // put baz on bar > db.baz.home("bar") > // move foo to bat > db.foo.home("bat")