翻译自: http://gihyo.jp/dev/serial/01/mongodb/0005
第5回 试试MongoDB的Sharding
前言
这次我将说明MongoDB的sharding。
Sharding是指将数据分散到多个服务器中的功能。这次我将先说明sharding,之后是sharding的概要,之后将解说在sharding中登场的几个关键词。第二章之后将解说sharding的架构顺序。
Sharding在MongoDB功能之中是很重要而复杂的。用手边的环境来架构的话,对sharding的理解有很大帮助,请一定好好参考本文再进行架构。
sharding的优点
Sharding通过将MongoDB进行水平Scaling的功能,有以下优点。
因为分散负荷所以可以提高性能
通过将数据分散到多个服务器中,可以减少CPU以及I/O的负荷。虽然是复述,但MongoDB可以用key的范围数据。通过设定合适的范围,可以将负荷进行水平Scaling。
由于资源分散导致性价比的提高。
近年因为内存以及磁盘的价格变得非常便宜了,尺寸越大内存模块价格越高,另外价格的上升幅度也会增多。要举内存的例子的话,共计需要64GB的内存时,比起与16个4GB内存Module的价格,4个16GModule的价格一般而言会更贵。内存以及磁盘在一个服务器中能够累计的Unit数是有极限的。在这样的背景下,在多个服务器中,使得数据分散,可以使得性价比提高。在MongoDB因为内存与性能直接相关,我推荐要保证有充足尺寸的内存。
MongoDB的sharding的概要
关于sharding,我将说明数据分散以及自动Balancing这两个特征。
根据Shard key的范围的数据分散
MongoDB的sharding采用范围分区(※1)。通过指定Shard key,可以决定个服务器中存储的数据的范围。服务器间不拥有重复数据,一个数据被存储的数据库是根据Shard key的范围来决定。
用图表示Sharding的image的话,就如图1所示。在图一中出现的术语我稍后说明。首先请随我对全体内容有个大致印象。
图1 sharding的概要图
图:右图例:mongos服务器 Shard Chunk 数据
※1)
仅仅观察数据分散这个点的话,几乎与MySQL的范围指定的分区几乎相同。
自动balancing
Key范围的调整以及伴随调整的服务器间的数据的移动,MongoDB有将其全部自动进行balancing的功能。被设计不去在意由于自动balancing导致的服务器间的数据的偏差也行的形式。另外追加新的服务器时,自动调整会使得执行数据移动的偏差渐渐消失。
※2)
在设定中可关闭自动balancing
重要关键词的说明
现在我将说明在sharding中出现的关键词。
shard
这是指数据被实际存储的mongod进程。1个文件存在一个shard中,无法在shard之间执行数据的复制。虽然不是必要的,但我推荐为每一个shard都要配置replication复制。
config服务器
这是指管理sharing的Metadata的mongod进程。因为会成为单一故障点,所以我推荐用复数的config服务器来构成。
mongos服务器
这是指在sharing中的路由进程Routing process。可以使shard以及客户端合作。必要的话,可以做多个mongos服务器。因为不是mongod进程,所以是无状态的,也不存放数据。
Shard key
这是指分散数据的key。可以进行复数指定。Key上哪个范围的数据被存储在那个shard中由MongoDB管理,根据数据的偏差进行自动调整。
chunk
chunk是指分散的数据单位。具体来说,在某个collection的连续范围的数据中,会变成复数的文件。达到chunk的最大尺寸的话,就会被分割,shard对应拥有的chunk数,必要的话会移动到其他shard中。可以变更chunk的最大尺寸。
至此我们说明的的关键词,一下子记不住也没关系。我们将通过在下一章中通过实际构造sharding环境,来加深理解。
试试sharding(前半)
在这一章与下一章中,我们将实际制作sharding结构。
这次,我们将在一台机器中区分节点,做5个服务器。具体来说就是,config服务器、mongos服务器、以及3个shard(node0,node1,node2)。3个mongod分别变成其他shard(参考图2)
构筑系统的服务器准备
首先制成数据direct以及日志direct。顺序按MongoDB的解压direct执行。
$ cd (MongoDB相关目录) $ mkdir -p data/config $ mkdir data/node0 $ mkdir data/node1 $ mkdir data/node2 $ mkdir log
启动shard
$ bin/mongod --shardsvr --port 30000 --dbpath data/node0 --logpath log/node0.log --fork $ bin/mongod --shardsvr --port 30001 --dbpath data/node1 --logpath log/node1.log --fork $ bin/mongod --shardsvr --port 30002 --dbpath data/node2 --logpath log/node2.log --fork
Mongod命令中,由于指定shardsvr的option,这个mongod会变成shard。
启动config服务器
$ bin/mongod --configsvr --port 20001 --dbpath data/config --logpath log/config.log --fork
通过在mongod命令中,指定configsvr的选项,这个mongod会变成config。
mongos服务器启动
$ bin/mongos --configdb localhost:20001 --port 20000 --logpath log/mongos.log --chunkSize 1 --fork
通过mongos命令,可以启动mongos服务器(不是mongod)。——在configdb中指定config服务器。mongos服务器是仅仅在内存上存在的进程,所以没有必要指定dbpath。chunkSize是chunk的尺寸。默认是64M,但这次想确认chunk分割的东西,所以这次设定1MB。
确认
在ps命令中可以看见5个进程就没问题了。
$ ps -ef | grep mongoroot $ bin/mongod --shardsvr --port 30000 --dbpath data/node0 --logpath log/node0.logroot 1235 $ bin/mongod --shardsvr --port 30001 --dbpath data/node1 --logpath log/node1.logroot 1236 $ bin/mongod --shardsvr --port 30002 --dbpath data/node2 --logpath log/node2.logroot 1239 $ bin/mongod --configsvr --port 20001 --dbpath data/config --logpath log/config.logroot 1241 $ bin/mongos --configdb localhost:20001 --port 20000 --logpath log/mongos.log --chunkSize 1
在mongos服务器中追加shard
用mongo shell,连接到mongos服务器的admin数据库。
$ bin/mongo localhost:20000/admin
用sh.addShard方法追加shard。
mongos> sh.addShard("localhost:30000") // 追加{ "shardAdded" : "shard0000", "ok" : 1 } mongos> sh.addShard("localhost:30001") // 追加{ "shardAdded" : "shard0001", "ok" : 1 } mongos> sh.addShard("localhost:30002") // 追加{ "shardAdded" : "shard0002", "ok" : 1 }
因为在「sh」这个object中有简化sharding的设定的方法。
用sh.status方法确认追加的shard是否正确追加了。
mongos> sh.status() --- Sharding Status --- sharding version: { "_id" : 1, "version" : 3 } shards: { "_id" : "shard0000", "host" : "localhost:30000" } { "_id" : "shard0001", "host" : "localhost:30001" } { "_id" : "shard0002", "host" : "localhost:30002" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" }
投入数据
然后,将通过mongos服务器投入数据。
在连接mongos服务器的状态下,制作logdb这个数据库。
mongos> use logdb switched to db logdb
然后,在logs这个collection中投入10万件数据。因为在mongoshell中可以使用javascript的语法。通过for循环插入数据。
mongos> for(var i=1; i<=100000; i++) db.logs.insert({"uid":i, "value":Math.floor(Math.random()*100000+1)}) mongos> db.logs.count()100000 //插入了10万个document
最后在uid中展开index。理由是,在此后将collection进行sharding化的情况下,需要对应shard key制成index。
mongos> db.logs.ensureIndex( { uid : 1 } );
在这个时间点,sharding还没有变成有效的。仅仅是单纯地在最开始的节点中插入10万个document
图3 sharding有效前的image图
最右:mongos服务器 shard 数据
要确认这个状态,观察mongo shell中mongos服务器的config数据库就行了。让我们来试着对config数据库的chunks collection加入询问。
试着sharding吧
sharding的有效化
那么接下来,让我们对sharding就行有效化,试着分散数据吧。要将sharding有效的话,需要在sh object的enableSharding方法中指定数据名。
mongos> use admin switched to db admin mongos> sh.enableSharding("logdb"){ "ok" : 1 }
然后用sh.shardCollection方法指定shard化的collection。第一参数是(数据库名).(collection名)的文字列,第二参数是作成index时的hash。
mongos> sh.shardCollection("logdb.logs" , { uid : 1 }){ "collectionsharded" : "logdb.logs", "ok" : 1 }
sharding的状态确认
在此,用sh.status方法表示sharding的状态的话,我们可以知道在3个shard服务器中,分别可以作成chunk。
mongos> sh.status() --- Sharding Status --- sharding version: { "_id" : 1, "version" : 3 } shards: { "_id" : "shard0000", "host" : "localhost:30000" } { "_id" : "shard0001", "host" : "localhost:30001" } { "_id" : "shard0002", "host" : "localhost:30002" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "logdb", "partitioned" : true, "primary" : "shard0000" } logdb.logs chunks: shard0001 1 // ←shard0001的chunk数 shard0002 { "uid" : { $minKey : 1 } } -->> { "uid" : 10083 } on : shard0001 Timestamp(2000, 0) { "uid" : 10083 } -->> { "uid" : 20166 } on : shard0002 Timestamp(3000, 0)
在上述的输出中,shard0000的chunk数有8个,shard0001的chunk数是1个,然后shard0002的chunk数是1个
这样chunk数发生偏移的情况是因为数据还在移动中的原因。请稍等后,在此执行sh.status。
--- Sharding Status --- sharding version: { "_id" : 1, "version" : 3 } shards: { "_id" : "shard0000", "host" : "localhost:30000" } { "_id" : "shard0001", "host" : "localhost:30001" } { "_id" : "shard0002", "host" : "localhost:30002" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "logdb", "partitioned" : true, "primary" : "shard0000" } logdb.logs chunks: shard0001 3 // ←shard0001的chunk数 shard0002 3 // ←shard0002的chunk数 shard0000 4 // ←shard0000的chunk数 { "uid" : { $minKey : 1 } } -->> { "uid" : 10083 } on : shard0001 Timestamp(2000, 0) { "uid" : 10083 } -->> { "uid" : 20166 } on : shard0002 Timestamp(3000, 0)
稍等后,chunk数就均等地变成3.3.4了(参考图4)
Chunk数均分的image图
图:最右 mongos服务器、shard、chunk、数据
数据数和chunk数是image。
另外,各输出的后半中加入的各chunk中的shard key的范围被输出了,
{ “uid” : 10083 } –>> { “uid” : 20166 } on : shard0002 Timestamp(3000, 0)
在上述例子中,我们可以看出shard0002的chunk被储存在uid的范围是10083≦uid<20166这个collection中。
$minKey被看做比所有值都小,$maxKey被看做比所有值都大。
另外也有别的确认方法——观察mongos服务器的config表的方法。
mongos> use config switched to db config mongos> db.chunks.count() 10 mongos> db.chunks.findOne()
各shard服务器的状态确认
在被sharding的状态下,确认各shard服务器会变成怎样。做法很简单,只要在各shard服务器中用mongoshell连接就性了,首先试着访问node1吧。
$ bin/mongo localhost:30000/logdb > db.logs.count() 39503 > exit
这样,就可以参照在各shard服务器中加入的collection数。另外用find方法等也能参照collection数。其他的shard服务器也是相同的。
$ bin/mongo localhost:30001/logdb > db.logs.count() 30248> exit $ bin/mongo localhost:30002/logdb > db.logs.count() 30249 > exit
下次的主题
这次我介绍了mongoDB的数据分散功能,sharding。通过使用sharding功能,可以分散负荷以及资源从而实现减少成本。另外我也介绍了自动balancing这种MongoDB的特有的功能。
下次,我介绍上次介绍过的复制以及这次介绍的sharding来进行组合构成介绍。
Leave a Reply