1. 分片概念:
    分片是指将数据拆分,将其分散放在不同机器上的过程,有时也用分区来表示这个概念。MongoDB支持自动分片。
    MongoDB的分片机制允许你创建一个包含许多机器(分片)的集群,将数据分散在集群中,每个分片维护着一个数据集合的子集。
    在分片之前要先执行mongos进行一次路由过程,这个路由服务器维护着一个“内容列表”,指明了每个分片包含什么数据,应用程序只需要连接到路由服务器就可以了。
    如果从一个未分片的系统转换为只有几个分片的系统,性能通常会有所下降。由于迁移数据、维护元数据、路由等开销,少量分片的系统与未分片的系统相比,通常延迟更大,吞吐量甚至可能会更小。因此,至少应该创建3个或以上的分片
  2. 进行分片
    MongoDB不能自动将数据分发到不同的分片上,必须要明确指定每一个集合应该如何分发数据。对一个集合分片,首先要对这个集合的数据库启用分片:

sh.enableSharding(“test”)

  1. 对集合分片时,要选择一个片键。MongoDB根据片键拆分数据,只有被索引过的键才能够作为片键。启用分片之前,先在希望作为片键的键上创建索引:

db.users.ensureIndex({“username”:1})

  1. 接下来就可以依据”username”对集合分片了:

sh.shardCollection(“test.users”,{“username”:1})

  1. 如果在查询中没有使用片键,mongos就得将查询发送到每个分片上,而包含片键的查询能够直接被发送到目标分片或者是集群分片的一个子集,这样的查询叫做定向查询。有些查询必须被发送到所有分片,这样的查询叫做分散-聚集查询。
  2. 片键
    拆分数据的最常用分发方式有三种:升序片键、随机分发的片键、基于位置的片键。
    ① 升序片键
    不断插入的文档都会出现在最大块中,因为升序的新键总是越来越接近$maxkey,这样,所有的写请求都会被路由到一个分片。该块是唯一一个不断增长和拆分的块,因为它是唯一一个能够接收到插入请求的块。这种模式经常会导致MongoDB的数据均衡处理变得更为困难,因为所有的新块都是由同一个分片创建的。
    ② 随机分发的片键
    随机分发的片键可以是用户名、邮件地址、UDID、MD5散列值,或者是数据集中其他一些没有规律的键
    由于写入数据是随机分发的,各分片增长的速度大致相同,这就减少了需要进行迁移的次数。唯一弊端在于,Mongodb在随机访问超出RAM大小的数据时效率不高。然后如果拥有足够多的RAM或者是并不介意系统性能的话,使用随机片键在集群上分配负载是非常好的。
    ③ 基于位置的片键
    基于位置的片键可以是用户的IP、经纬度,或者是地址。
    如果希望特定范围的块出现在特定的分片中,可以为分片添加tag,然后为块指定相应的tag.
    通过为分片指定tag,请求均衡器实现该指令:

sh.addShardTag(“shard0000”,”USPS”)

  1. 创建规则:

sh.addTagRange(“test.ips”,{“ip”:”056.000.000.000”}),
…{“ip”:”057.000.000.000”},”USPS”)

  1. ④ 散列片键
    散列键可使其他任何键随机分发,如果打算在大量查询中使用升序键,但同时又希望写入数据随机分发的话,散列片键是很好的选择。弊端是无法使用散列片键做指定目标的范围查询。
    创建散列片键,首先要创建散列索引:

db.users.ensureIndex({“username”:”hashed”})

  1. 然后对集合分片:

sh.shardCollection(“app.users”,{“username”:”hashed”})

  1. 使用散列片键存在着一定的局限性。不能使用unique选项,不能使用数组字段。浮点型的值会先被取整。然后进行散列,所以1和1.99会得到相同的散列值
  2. 流水策略
    强制将所有的数据插入到配置了SSD的服务器上,然后让均衡器将旧的块移动到其他分片上,这样能够提供比转式磁盘更低的延迟。
    为SSD指定一个标签:

sh.addShardTag(“shard-name”,”ssd”)

  1. 将升序键的当前值一直到正无穷范围的块指定分布在SSD上,以便后续的写入请求均被分发到SSD分片上:

sh.addTagRange(“dbName.collName”,{“_id”:ObjectId()},{“_id”:MaxKey},”ssd”)

  1. 除非修改标签范围,否则从升序键的当前值一直到正无穷的这个范围则被固定在了这个分片上。可创建一个定时任务每天更新一次标签范围
  2. 配置分片
    ① 如上所述,需要建立mongos和分片。第三个组件——配置服务器也非常重要。配置服务器是普通的mongod服务器,保存着集群的配置信息:集群有哪些分片、分片的是哪些集合,以及数据块的分布。鉴于配置服务器的重要性,必须启用其日志功能,并确保其数据保存在非易失性驱动器上。每个配置服务器都应位于单独的物理机器上,最好是分布在不同地理位置的机器上
    ② 配置服务器应先于所有的mongos进程启动:
$mongod --configser --dbpath /var/lib/mongodb -f /var/lib/config/mongod.conf

需要配置3台配置服务器
如果所有的配置服务器都不可用,就要对所有分片做数据分析。比较好的方式是经常对配置服务器做数据备份。
③ 三个配置服务器均处于运行状态后,启动一个mongos进程供应用程序连接,mongos进程需要知道配置服务器的地址,所以需要使用–configdb选项启动mongos:

$mongos --config configser1:27019,configser2:27019,configser3:27019 -f /var/lib/mongos.conf

可启动任意数量的mongos进程。通常的设置是每个应用程序服务器使用一个mongos进程(与应用服务器运行在同一台机器上)

  1. 将副本集转换为分片
    有两种可能性:已经有了一个副本集,或是从零开始建立集群。如果是从零开始的话,可先初始化一个空的副本集,然后按以下操作进行:
    如已经有一个使用中的副本集,该副本集会成为第一个分片。为了将副本集转换为分片,需告知mongos副本集名称和副本集成员列表:
    例如,如果在server1、server2、server3、server4、server5上有一个名为spock的副本集,可连接到mongos并运行:

sh.addShard(“spock/server1:27017,server2:27017,server4:27017”)

  1. 可在参数中指定副本集的所有成员,但并非一定要这样做
    副本集名称spock被用作分片名称。
    将副本集作为分片添加到集群后,应将应用程序设置从连接到副本集改为连接到mongos。
  2. 增加集群容量:
    可通过增加分片来增加集群的容量。为添加一个新的、空的分片,可先创建一个副本集,确保副本集的名字与其他分片不同。副本集完成初始化并拥有一个主节点后,可在mongos上运行addShard()命令,将副本集作为分片添加到集群中,在参数中指定副本集的名称和主机名作为种子。如有多个现存的副本集没有做分片,只要它们没有同名的数据库,就可以将它们作为新分片全部添加到集群中,方法同空分片。
  3. MongoDB如何追踪集群数据
    Mongodb将文档分组为块(chunk),每个块由给定片键特定范围内的文档组成。一个块只存在于一个分片上,所以Mongodb用一个比较小的表就能够维护块跟分片的映射。
    当一个块增长到特定大小时,Mongodb会自动将其拆分为两个较小的块。一个文档属于且只属于一个块,这就意味着,不可以使用数组字段作为片键,因为MongoDB会为数组创建多个索引。
    可创建复合片键,工作方式与使用复合索引进行排序一样
    块拆分时只需改变块的元数据即可,而无需进行数据移动,配置服务器会创建新的块文档,同时修改旧的块范围。mongos选择一个拆分点,然后视图将这些信息通知给配置服务器,但是配置服务器不可达时,它仍位于这个块的拆分阈值点,随后的任何写请求都会导致monogos重发拆分请求,导致拆分风暴。防止拆分风暴的唯一方法是保证配置服务器的健康和可用。也可重启mongos,重置写入计数器,这样它就不再处于拆分阈值点了。
    另一个问题:mongos并没有一个全局的计数器用于追踪每个块到底有多大,每个mongos只是计算收到的写请求是否达到了特定了阈值点。也就是说,如果mongos进程频繁的上线和宕机,那么mongos在再次宕机之前可能永远无法收到足以达到拆分阈值点的写请求,因此块会变得越来越大。防止这种情况发生的第一种方式是减少mongos进程的波动,然而维持不需要的mongos持续运行开销过大。这时可选另一种方式:使块的大小比实际预期小些,这样就更容易达到拆分阈值点。可在启动mongos时指定–nosplit选项,从而关闭块的拆分
  4. 均衡器
    负责数据的迁移,它会周期性地检查分片间是否存在不均衡,如果存在,则开始块的迁移。
    每隔几秒钟,mongos就会尝试变身为均衡器。如果没有其他可用的均衡器,mongos就会对整个集群加锁,以防止配置服务器对集群进行修改,然后做一次均衡。均衡并不影响mongos正常的路由操作,所以使用mongos的客户端不会受到影响。
    查看config.locks集合,可得知哪一个mongos是均衡器。config.locks集合会追踪所有集群范围的锁。
  5. 分片管理
    检查集群状态:
sh.status()

查看分片、数据库和分片集合的摘要信息

sh.status(true)

尽可能详细的打印信息

config.shards.findOne()

shards集合跟踪记录集群内所有分片的信息

config.databases.findOne()

databases集合跟踪记录集合中所有数据库的信息

config.collections.findOne()

collections集合跟踪记录所有分片集合的信息

config.chunks.findOne()

chunks集合记录有集合中所有块的信息

config.changelog.findOne()

changelog集合可用于跟踪记录集群的操作,因为该集合会记录所有的拆分和迁移

config.tags.findOne()

该集合的创建是在为系统配置分片标签时发生的,每个标签都与一个块范围相关联

config.settings.findOne()

该集合含有当前均衡器设置和块大小的文档信息
查看网络连接

connPollStats命令,查看mongos和mongod之间的连接信息,并可得知服务器上看、打开的所有连接

限制连接数量
一个mongos进程最多允许20000个连接(mongod也是如此),所以应该在mongos命令行配置中使用maxConns选项。来限制mongos能够创建的连接数量

均衡器只使用块的数量,而非数据大小,作为衡量分片间是否均衡的指标

  1. mongodb集群包括一定数量的mongod(分片存储数据)、mongos(路由处理)、config server(配置节点)、clients(客户端)、arbiter(仲裁节点:为了选举某个分片存储数据节点那台为主节点)。

mongodb 按时间段group mongodb按时间分片_mongodb

  1. ① shards:一个shard为一组mongod,通常一组为两台,主从或互为主从,这一组mongod中的数据时相同的。数据分割按有序分割方式,每个分片上的数据为某一范围的数据块,故可支持指定分片的范围查询,这同google的BigTable 类似。数据块有指定的最大容量,一旦某个数据块的容量增长到最大容量时,这个数据块会切分成为两块;当分片的数据过多时,数据块将被迁移到系统的其他分片中。另外,新的分片加入时,数据块也会迁移。 ② mongos:可以有多个,相当于一个控制中心,负责路由和协调操作,使得集群像一个整体的系统。mongos可以运行在任何一台服务器上,有些选择放在shards服务器上,也有放在client 服务器上的。mongos启动时需要从config servers上获取基本信息,然后接受client端的请求,路由到shards服务器上,然后整理返回的结果发回给client服务器。③ config server:存储集群的信息,包括分片和块数据信息。主要存储块数据信息,每个config server上都有一份所有块数据信息的拷贝,以保证每台config server上的数据的一致性。④ shard key:为了分割数据集,需要制定分片key的格式,类似于用于索引的key格式,通常由一个或多个字段组成以分发数据,比如:
{ name : 1 } 
 { _id : 1 } 
 { lastname : 1, firstname : 1 } 
 { tag : 1, timestamp : -1 }

  1. mongoDB的分片为有序存储(1为升序,-1为降序),shard key相邻的数据通常会存在同一台服务(数据块)上。