English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Введение
В MongoDB (версия 3.2.9) шarded кластер (sharded cluster) является методом горизонтального расширения производительности базы данных, который позволяет 分布式存储 данные на различных shard, каждый shard хранит только часть данных набора, MongoDB гарантирует, что данные между shard не дублируются, сумма данных, сохраненных на всех shard, составляет полный набор данных. Распределенное хранение данных на shard позволяет распределить нагрузку между несколькими shard, каждый shard отвечает только за чтение/запись части данных, что充分利用了 системные ресурсы shard и提高了数据库 системы производительность.
Набор данных разбивается на блоки данных (chunk), каждый из которых содержит несколько doc, блоки данных распределены по шардам в кластере. MongoDB отвечает за отслеживание распределения блоков данных на shard, данные блоки на каждом shard называются метаданными shard, сохраняются в базе данных config на config server, обычно используется 3 config server, все базы данных config на всех config server должны быть полностью идентичны. Через mongos можно напрямую обращаться к базе данных config, чтобы проверить метаданные shard; mongo shell предоставляет вспомогательную функцию sh, которая позволяет безопасно проверять метаданные кластера shard.
Для выполнения запроса к любому shard, получают только подмножество данных collection, хранящееся на данном shard, а не весь набор данных. Приложение должно подключаться только к mongos и выполнять чтение/запись, mongos автоматически маршрутизирует запросы на соответствующий shard. MongoDB через mongos предоставляет низкоуровневое управление шардами для приложения, и с точки зрения приложения, оно имеет доступ ко всему набору данных.
Первое, главный фрагмент
Не каждая коллекция хранится в распределенном порядке в кластере фрагментов. Только после того, как collection будет явно фрагментирована с помощью функции sh.shardCollection(), она будет храниться в различных shard. Для ненаправленных коллекций (un-sharded collection) данные будут храниться только в главном фрагменте (Primary shard). По умолчанию, это shard, который был создан при最初 создании базы данных, и используется для хранения данных ненаправленных коллекций в этой базе данных. У каждой базы данных есть свой главный фрагмент.
У каждой базы данных в фрагментированном кластере есть главный фрагмент, который хранит все нефрагментированные коллекции для этой базы данных. У каждой базы данных есть свой главный фрагмент.
Например, у фрагментированного кластера有三个 фрагмента: shard1, shard2, shard3. Если создать базу данных blog в фрагменте shard1, то MongoDB автоматически создаст структуру базы данных blog в shard2 и shard3. Главный фрагмент базы данных blog - это Shard1.
На рисунке, главный фрагмент Collection2 - это ShardA.
Использование команды movePrimary для изменения главного фрагмента базы данных по умолчанию. Ненаправленные фрагменты будут перемещены из текущего фрагмента в новый главный фрагмент.
db.runCommand( { movePrimary : "test", to : "shard0001" } )
После изменения основной фрагмента базы данных с помощью команды movePrimary, информация о конфигурации в config server является последней, а информация о конфигурации в кэше mongos устарела.MongoDB предоставляет команду: flushRouterConfig, которая强迫mongos получить последнюю информацию о конфигурации из config server и обновить кэш mongos.
db.adminCommand({"flushRouterConfig":1})
Второе, метаданные фрагментации
Не следует напрямую обращаться к config server для просмотра метаданных информационного кластера фрагментов,因为这些 данные очень важны. Безопасным способом является подключение к config данным через mongos или использование вспомогательной функции sh.
использование вспомогательной функции sh для просмотра
sh.status()
подключение к mongos для просмотра коллекций в базе данных config
mongos> use config
1, коллекция shards сохраняет информацию о фрагментах
db.shards.find()
данные фрагмента хранятся в replica set или standalone mongod, указанном в host.
{ "_id" : "shard_name", "host" : "replica_set_name/host:port", "tag":[shard_tag1,shard_tag2] }
2, коллекция databases сохраняет информацию о всех базах данных в кластере фрагментов, независимо от того, фрагментированы они или нет
db.databases.find()
Если на базе данных выполняется sh.enableSharding(“db_name”) , то значение поля partitioned будет true; поле primary определяет главный фрагмент базы данных (primary shard).
{ "_id" : "test", "primary" : "rs0", "partitioned" : true }
3, коллекция collections сохраняет информацию о всех фрагментированных коллекциях, не включая нефрагментированные коллекции (un-sharded collections)
ключ: ключ фрагмента
db.collections.find() { "_id" : "test.foo", "lastmodEpoch" : ObjectId("57dcd4899bd7f7111ec15f16"), "lastmod" : ISODate("1970-02-19T17:02:47.296Z"), "dropped" : false, "key" : { "_id" : 1 }, "unique" : true }
4, коллекция chunks сохраняет информацию о данных блоков
ns:сборник фрагментов, структура: db_name.collection_name
min и max: минимальное и максимальное значение ключа
shard:块所在的分片
db.chunks.find() { "_id" : "test.foo-_id_MinKey", "lastmod" : Timestamp(1, 1), "lastmodEpoch" : ObjectId("57dcd4899bd7f7111ec15f16"), "ns" : "test.foo", "min" : { "_id" : 1 }, "max" : { "_id" : 3087 }, "shard" : "rs0" }
5. Коллекция changelog записывает операции распределенного кластера, включая разделение chunk и операции迁移, добавление или удаление shard.
Поля what: представляют собой тип операции, например: multi-split означает разделение chunk,
"what" : "addShard", "what" : "shardCollection.start", "what" : "shardCollection.end", "what" : "multi-split",
6. Tags записывают тег shard и соответствующий диапазон ключей shard.
{ "_id" : { "ns" : "records.users", "min" : { "zipcode" : "10001" } }, "ns" : "records.users", "min" : { "zipcode" : "10001" }, "max" : { "zipcode" : "10281" }, "tag" : "NYC" }
7. Коллекция settings записывает состояние балансировщика и размер chunk, по умолчанию размер chunk составляет 64MB.
{"_id" : "chunksize", "value" : 64} {"_id" : "balancer", "stopped" : false}
8. Коллекция locks записывает распределенный замок (distributed lock), гарантируя, что только один экземпляр mongos может выполнять администраторские задачи в распределенном кластере.
Mongos, занимающий роль балансировщика, блокирует распределенный замок и вставляет документ в config.locks.
Коллекция замков хранит распределенный замок. Это гарантирует, что только один экземпляр mongos может выполнять администраторские задачи в кластере одновременно. Mongos, выполняющий роль балансировщика, блокирует замок, вставляя документ, напоминающий следующий, в коллекцию замков.
{ "_id" : "balancer" "process" : "example.net:40000:1350402818:16807", "state" : 2, "ts" : ObjectId("507daeedf40e1879df62e5f3"), "when" : ISODate("2012-10-16T19:01:01.593Z"), "who" : "example.net:40000:1350402818:16807:Balancer:282475249", "why" : "делая балансировку" }
третий шаг, удаление фрагмента
Удаляя фрагмент, необходимо убедиться, что данные на этом фрагменте были перемещены на другие фрагменты, для разделенных集合 используйте балансир для миграции данных, для неразделенных集合 необходимо изменить основной фрагмент коллекции.
1, удалите данные из всех уже разделенных集合
шаг 1, обеспечьте, что балансир включен
sh.setBalancerState(true);
шаг 2,迁移所有已分片集合到其他分片
use admin db.adminCommand({"removeShard":"shard_name"})
Команда removeShard迁移数据块从当前分片到其他分片,если на фрагменте много данных, процесс может занять много времени.
шаг 3, проверка состояния миграции данных
use admin db.runCommand( { removeShard: "shard_name" } )
Использование команды removeShard позволяет проверить состояние миграции данных, поле remaining показывает количество оставшихся данных
{ "msg" : "продолжение слива", "state" : "ongoing", "remaining" : { "chunks" : 42, "dbs" : 1 }, "ok" : 1 }
шаг 4, завершение миграции данных
use admin db.runCommand( { removeShard: "shard_name" } ) { "msg" : "удаление фрагмента успешно завершено", "state" : "completed", "shard" : "shard_name" "ok" : 1 }
2, удалить не shardированные базы данных
step1, проверить не shardированные базы данных
Не shardированные базы данных включают в себя две части:
1, база данных не была shardирована, данные не использовали sh.enableSharding("db_name"), в базе данных config поле partitioned для этой базы данных равно false
2, в базе данных существует collection, которая не была shardирована, то есть текущий shard является основным shard этой коллекции
use config db.databases.find({$or:[{"partitioned":false},{"primary":"shard_name"}]})
Для базы данных с partitioned=false все данные хранятся в текущем shard; для базы данных с partitioned=true, primary="shard_name", существует нешарированный (un-sharded collection) хранилище в этой базе данных, эти коллекции необходимо изменить на основной shard.
step2, изменить основной shard базы данных
db.runCommand( { movePrimary: "db_name", to: "new_shard" })
Четыре, добавление shard
Поскольку шarding хранит часть набора данных, для обеспечения высокой доступности данных рекомендуется использовать Replica Set в качестве shard, даже если в Replica Set содержится только один член. Подключитесь к mongos и используйте вспомогательную функцию sh для добавления shard.
sh.addShard("replica_set_name/host:port")
Не рекомендуется использовать standalone mongod в качестве shard
sh.addShard("host:port")
Пять,超大 блок
В некоторых случаях чанк может продолжать расти, превышая ограничения размера чанка, и стать超大 блоком (jumbo chunk). Причина超大 блоков заключается в том, что все документы в чанке используют один и тот же ключ шарда (shard key), что делает невозможным разделение этого чанка MongoDB. Если этот чанк продолжит расти, это может привести к неравномерному распределению чанка и стать узким местом в производительности.
При передаче чанков существуют ограничения: размер каждого чанка не может превышать 25 000 документов doc или 1,3 раза превышать значение конфигурации. Значение по умолчанию для размера чанка составляет 64 МБ, чанки, превышающие ограничения, будут помечены MongoDB как超大块 (jumbo chunk), MongoDB не может迁移超大 блоки на другие shard.
MongoDB не может переместить блок, если количество документов в блоке превышает 250000 документов или 1,3 раза результат деления настроенного размера блока на средний размер документа.
1, проверка больших блоков
Используя sh.status(), можно обнаружить большие блоки, за большими блоками существует метка jumbo
{ "x" : 2 } -->> { "x" : 3 } on : shard-a Timestamp(2, 2) jumbo
2, распространение больших блоков
Большие блоки не могут быть разделены, их нельзя автоматически распространять через балансир, их необходимо распространять вручную.
step1, отключение балансира
sh.setBalancerState(false)
step2, увеличение значения конфигурации размера блока
Поскольку MongoDB не позволяет перемещать блоки, размер которых превышает ограничение, необходимо временно увеличить значение конфигурации размера блока, а затем равномерно распределить большие блоки по кластеру shard
use config db.settings.save({"_id":"chunksize","value":"1024"})
step3, перемещение больших блоков
sh.moveChunk("db_name.collection_name",{sharded_filed:"value_in_chunk"},"new_shard_name")
step4, включение балансира
sh.setBalancerState(true)
step5, обновление конфигурационного кэша mongos
Принудительно mongos синхронизирует конфигурационную информацию с config server и обновляет кэш.
use admin db.adminCommand({ flushRouterConfig: 1 })
Шестой, балансир
Балансир преобразуется из mongos, то есть mongos не только отвечает за маршрутизацию запросов к соответствующему shard, но и за балансировку данных. В общем случае, MongoDB автоматически обрабатывает балансировку данных, состояние балансира можно проверить через config.settings или через вспомогательные функции sh
sh.getBalancerState()
Возврат true, что означает, что балансир работает, система автоматически обрабатывает балансировку данных, использование вспомогательной функции sh позволяет отключить балансир
sh.setBalancerState(false)
balancer не может немедленно прекратить выполняемые операции по迁移 блоков, при переходе mongos в роль balancer, запрашивается lock balancer, проверяется коллекция config.locks,}
use config db.locks.find({"_id":"balancer"}) --or sh.isBalancerRunning()
Если state=2, это означает, что balancer находится в активном состоянии, если state=0, это означает, что balancer был закрыт.
Процесс выравнивания фактически включает迁移数据块从一个shard в другойshard, или сначала разбиение большого chunk на мелкие chunk, а затем их迁移 в другойshard,迁移和拆分块会增加系统的IO нагрузку, лучше ограничить активное время均衡器在系统空闲时进行, можно установить активное время окна balancer, ограничить balancer в指定的 временном интервале для выполнения операций по разбиению и迁移 данных.
use config db.settings.update( {"_id":"balancer"}, "$set":{"activeWindow":{"start":"23:00","stop":"04:00"}}), true )
Объекты, которые разрезаются и перемещаются, называются chunk,均衡器只保证chunk数量在各个shard上是均衡的,至于每个chunk包含的doc数量,并不一定是均衡的。可能存在一些chunk包含的doc数量很多,而有些chunk包含的doc数量很少,甚至不包含任何doc。因此,应该慎重选择分片的索引键,即片键,如果一个字段既能满足绝大多数查询的需求,又能使doc数量均匀分布,那么该字段是片键的最佳选择。
Заключение
Вот и все, что у нас есть в этой статье. Надеюсь, это поможет вам в изучении или работе. Если у вас есть вопросы, пожалуйста, оставляйте комментарии.