MongoDB 分片

1.分片简介  分片是指将数据拆分,将其分散存在不一样机器上的过程.有时也叫分区.将数据分散在不一样的机器上,不须要功能 强大的大型计算机就能够存储更多的数据,处理更大的负载.使用几乎全部数据库软件都能进行手动分片,应用须要维护与若干不一样数据库服务器的链接,每一个链接 仍是彻底独立的.应用程序管理不一样服务器上的不一样数据,存储查村都须要在正确的服务器上进行.这种方法能够很好的工做,可是也难以维护,好比向集群添加节 点或从集群删除节点都很困难,调整数据分布和负载模式也不轻松.
MongoDB支持自动分片,能够摆脱手动分片的管理.集群自动切分数据,作负载均衡. shell

2.MongoDB的自动分片 MongoDB分片的基本思想就是将集合切分红小块.这些块分散到若干片里面,每一个片只负责总数据  的 一部分.应用程序没必要知道哪片对应哪些数据,甚至不须要知道数据已经被拆分了,因此在分片以前要运行一个路由进程,进程名mongos,这个路由器知道全部数据的存放位置,因此应用能够链接它来正常发送请求.对应用来讲,它仅知道链接了一个普通的mongod.路由器知道和片的对应关系,可以转发请求到正确的片上.若是请求有了回应,路由器将其收集起来回送给应用.
在没有分片的时候,客户端链接mongod进程,分片时客户端会链接mongos进程.mongos对应用隐藏了分片的细节.
从应用的角度看,分片和不分片没有区别.因此须要扩展的时候,没必要修改应用程序的代码.不分片的客户端链接:
数据库

何时须要分片:
a.机器的磁盘不够用了
b.单个mongod已经不能知足些数据的性能须要了
c.想将大量数据放在内存中提升性能
通常来讲,先要从不分片开始,而后在须要的时候将其转换成分片.缓存

3.片键
设置分片时,须要从集合里面选一个键,用该键的值做为数据拆分的依据.这个键成为片键.
假设有个文档集合表示的是人员,若是选择名字"name"作为片键,第一篇可能会存放名字以A-F开头的文档.
第二片存G-P开头的文档,第三篇存Q-Z的文档.随着增长或删除片,MongoDB会从新平衡数据,是每片的流量比较
均衡,数据量也在合理范围内(如流量较大的片存放的数据或许会比流量下的片数据要少些)
服务器

4.将已有的集合分片
假设有个存储日志的集合,如今要分片.咱们开启分片功能,而后告诉MongoDB用"timestamp"做为片键,就要全部数据放到
了一个片上.能够随意插入数据,但总会是在一个片上.
而后,新增一个片.这个片建好并运行了之后,MongoDB就会把集合拆分红两半,成为块.每一个块中包含片键值在必定
范围内的全部文档,假设其中一块包含时间戳在2011.11.11前的文档,则另外一块含有2011.11.11之后的文档.其中
一块会被移动到新片上.若是新文档的时间戳在2011.11.11以前,则添加到第一块,不然添加到第二块.负载均衡

5.递增片键仍是随机片键
片键的选择决定了插入操做在片之间的分布.
若是选择了像"timestamp"这样的键,这个值可能不断增加,并且没有太大的间断,就会将全部数据发送到一个片上
(含有2011.11.11之后日期的那片).若是有添加了新片,再拆分数据,仍是会都导入到一台服务器上.添加了新片,
MongoDB肯能会将2011.11.11之后的拆分红2011.11.11-2021.11.11.若是文档的时间大于2021.11.11之后,
全部的文档还会以最后一片插入.这就不适合写入负载很高状况,但按照片键查询会很是高效.
若是写入负载比较高,想均匀分散负载到各个片,就得选择分布均匀的片键.日志例子中时间戳的散列值,没有模式的"logMessage"
都是复合这个条件的.
不论片键随机跳跃仍是稳定增长,片键的变化很重要.如,若是有个"logLevel"键的值只有3种值"DEBUG","WARN","ERROR",
MongoDB不管如何也不能把它做为片键将数据分红多于3片(由于只有3个值).若是键的变化太少,但又想让其做为片键,
能够把这个键与一个变化较大的键组合起来,建立一个复合片键,如"logLevel"和"timestamp"组合.
选择片键并建立片键很像索引,觉得两者原理类似.事实上,片键也是最经常使用的索引.

6.片键对操做的影响
最终用户应该没法区分是否分片,可是要了解选择不一样片键状况下的查询有何不一样.
假设仍是那个表示人员的集合,按照"name"分片,有3个片,其名字首字母的范围是A-Z.下面以不一样的方式查询:
db.people.find({"name":"Refactor"})
mongos会将这个查询直接发送给Q-Z片,得到响应后,直接转发给客户端
db.people.find({"name":{"$lt":"L"}})
mongos会将其先发送给A-F和G-P片,而后将结果转发给客户端.
db.people.find().sort({"email":1})
mongos会在全部片上查询,返回结果时还会作归并排序,确保结果顺序正确.
mongos用游标从各个服务器上获取数据,因此没必要等到所有数据都拿到才向客户端发送批量结果.
db.people.find({"email":"refactor@msn.cn"})
mongos并不追踪"email"键,因此也不知道应该将查询发给那个片.因此他就向全部片顺序发送查询.
若是是插入文档,mongos会依据"name"键的值,将其发送到相应的片上.

7.创建分片
创建分片有两步:启动实际的服务器,而后决定怎么切分数据.
分片通常会有3个组成部分:
a.片
片就是保存子集合数据的容器,片但是单个的mongod服务器(开发和测试用),也能够是副本集(生产用).因此一片
有多台服务器,也只能有一个主服务器,其余的服务器保存相同的数据.
b.mongos
mongos就是MongoDB配的路由器进程.它路由全部的请求,而后将结果聚合.它自己并不存储数据或者配置信息
但会缓存配置服务器的信息.
c.配置服务器
配置服务器存储了集群的配置信息:数据和片的对应关系.mongos不永久存房数据,因此须要个地方存放分片的配置.
它会从配置服务器获取同步数据.
8.启动服务器
首先要启动配置服务器和mongos.配置服务器须要先启动.由于mongos会用到其上的配置信息.
配置服务器的启动就像普通的mongod同样
mongod --dbpath "F:\mongo\dbs\config" --port 20000 --logpath "F:\mongo\logs\config\MongoDB.txt" --rest
配置服务器不须要不少的空间和资源(200M实际数据大约占用1kB的配置空间)
创建mongos进程,一共应用程序链接.这种路由服务器链接数据目录都不须要,但必定要指明配置服务器的位置:
mongos --port 30000 --configdb 127.0.0.1:20000 --logpath "F:\mongo\logs\mongos\MongoDB.txt"
分片管理一般是经过mongos完成的.
添加片
片就是普通的mongod实例(或副本集)
mongod --dbpath "F:\mongo\dbs\shard" --port 10000 --logpath "F:\mongo\logs\shard\MongoDB.txt" --rest
mongod --dbpath "F:\mongo\dbs\shard1" --port 10001 --logpath "F:\mongo\logs\shard1\MongoDB.txt" --rest
链接刚才启动的mongos,为集群添加一个片.启动shell,链接mongos:
肯定链接的是mongos而不是mongod,经过addshard命令添加片:
>mongo 127.0.0.1:30000
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10000",
... "allowLocal":true
... }
... )
Sat Jul 21 10:46:38 uncaught exception: error { "$err" : "can't find a shard to
put new db on", "code" : 10185 }
mongos> use admin
switched to db admin
mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10000",
... "allowLocal":1
... }
... )
{ "shardAdded" : "shard0000", "ok" : 1 }


mongos> db.runCommand(
... {
... "addshard":"127.0.0.1:10001",
... "allowLocal":1
... }
... )
{ "shardAdded" : "shard0001", "ok" : 1 }


当在本机运行片的时候,得设定allowLocal键为1.MongoDB尽可能避免因为错误的配置,将集群配置到本地,


因此得让它知道这仅仅是开发,并且咱们很清楚本身在作什么.若是是生产环境中,则要将其部署在不一样的机器上.


想添加片的时候,就运行addshard.MongoDB会负责将片集成到集群.


 


切分数据


MongoDB不会将存储的每一条数据都直接发布,得先在数据库和集合的级别将分片功能打开.


若是是链接配置服务器,


E:\mongo\bin>mongo 127.0.0.1:20000
MongoDB shell version: 2.0.6
connecting to: 127.0.0.1:20000/test
> use admin
switched to db admin
> db.runCommand({"enablesharding":"test"})
{
"errmsg" : "no such cmd: enablesharding",
"bad cmd" : {
"enablesharding" : "test"
},
"ok" : 0
}


应该是链接 路由服务器:


db.runCommand({"enablesharding":"test"})//将test数据库启用分片功能.


对数据库分片后,其内部的集合便会存储到不一样的片上,同时也是对这些集合分片的前置条件.


在数据库级别启用了分片之后,就可使用shardcollection命令堆积和进行分片:


db.runCommand({"shardcollection":"test.refactor","key":{"name":1}})//对test数据库的refactor集合进行分片,片键是name


若是如今对refactor集合添加数据,就会依据"name"的值自动分散到各个片上.


 


9.生产配置


进入生产环境后,须要更健壮的分片方案,成功的构建分片须要以下条件:


多个配置服务器


多个mongos服务器


每一个片都是副本集


正确的设置w


 


健壮的配置


设置多个配置服务器是很简单的.


设置多个配置服务器和设置一个配置服务器同样


mongod --dbpath "F:\mongo\dbs\config" --port 20000 --logpath "F:\mongo\logs\config\MongoDB.txt" --rest


mongod --dbpath "F:\mongo\dbs\config1" --port 20001 --logpath "F:\mongo\logs\config1\MongoDB.txt" --rest


mongod --dbpath "F:\mongo\dbs\config2" --port 20002 --logpath "F:\mongo\logs\config2\MongoDB.txt" --rest


启动mongos的时候应将其链接到3个配置服务器上:


mongos --port 30000 --configdb 127.0.0.1:20000,127.0.0.1:20001,127.0.0.1:20002 --logpath "F:\mongo\logs\mongos\MongoDB.txt"


配置服务器使用的是两步提交机制,而不是普通的MongoDB的异步复制,来维护集群配置的不一样副本.这样能保证集群的状态


的一致性.这意味着,某台配置服务器宕机后,集群的配置信息是只读的.客户端仍是可以读写,可是只有全部配置服务器备份了


之后才能从新均衡数据.


 


多个mongos


mongos的数量不受限制,建议针对一个应用服务器只运行一个mongos进程.这样每一个应用服务器就能够与mongos进行


本地回话,若是服务器不工做了,就不会有应用试图与不存的mongos通话了


 


健壮的片


生产环境中,每一个片都应是副本集,这样单个服务器坏了,就不会致使整个片失效.用addshard命令就能够将副本集做为片添加,


添加时,只要指定副本集的名称和种子就好了.


如要添加副本集refactor,其中包含一个服务器127.0.0.1:10000(还有别的服务器),就能够用下列命令将其添加到集群中:


db.runCommand({"addshard":"refactor/127.0.0.1:10000"})


若是127.0.0.1:10000服务器挂了,mongos会知道它所链接的是一个副本集,并会使用新的主节点.

10.管理分片
分片信息主要存放在config数据库上,这样就能被任何链接到mongos的进程访问到了.
配置集合
在shell中链接了mongos,并使用了use config数据库
a.片
能够在shareds集合中查到全部的片
db.shards.find()
b.数据库
databases集合含有已经包含在片上的数据库列表和一些相关信息
b.databases.find()
返回的文档解释:
"_id"
表示数据库名
"partitioned"
表示是否启用了分片功能
"primary"
这个值与"_id"相对应,表名这个数据的"大本营"在哪里.不论分片与否,数据库总会有个大本营.要是分片的话,建立数据库时会
随机选择一个片.也就是说,大本营是开始建立数据库文档的位置.虽然分片时数据库也会用到不少别的服务器,但会从这个片开始.
c.块
块信息存储在chunks集合中.这能够看到数据究竟是怎么切分到集群中的
db.chunks.find()
分片命令异步

得到概要
db.printShardingStatus()
删除片
用removeshard就能从集群中删除片.removeshard会把给定片上的全部块的数据都挪到其余片上
db.runCommand({"removeshard":"127.0.0.1:10001"})
性能

相关文章
相关标签/搜索