mongodb3.4 Sharded cluster

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mongodb3.4 Sharded cluster相关的知识,希望对你有一定的参考价值。

MongoDB目前3大核心优势:灵活模式、高可用性、可扩展性,通过json文档来实现灵活模式,通过复制集来保证高可用,通过Sharded cluster来保证可扩展性。 

1.为什么需要Sharded cluster?

当MongoDB复制集遇到下面的业务场景时,你就需要考虑使用Sharded cluster。

1.存储容量需求超出单机磁盘容量
2.活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能
3.写IOPS超出单个MongoDB节点的写服务能力

mongodb3.4

如上图所示,Sharding Cluster使得集合的数据可以分散到多个Shard(复制集或者单个Mongod节点)存储,使得MongoDB具备了横向扩展(Scale out)的能力,丰富了MongoDB的应用场景。

2.Sharded cluster架构

Sharded cluster由Shard、Mongos和Config server 3个组件构成。

mongodb3.4

Mongos是Sharded cluster的访问入口,强烈建议所有的管理操作、读写操作都通过mongos来完成,以保证cluster多个组件处于一致的状态。

Mongos本身并不持久化数据,Sharded cluster所有的元数据都会存储到Config Server(下一节详细介绍),而用户的数据则会分散存储到各个shard。Mongos启动后,会从config server加载元数据,开始提供服务,将用户的请求正确路由到对应的Shard。

3.数据分布策略

Sharded cluster支持将单个集合的数据分散存储在多个shard上,用户可以指定根据集合内文档的某个字段即shard key来分布数据,目前主要支持2种数据分布的策略,范围分片(Range based sharding)或hash分片(Hash based sharding)。

(1).范围分片

mongodb3.4

如上图所示,集合根据x字段来分片,x的取值范围为[minKey, maxKey](x为整型,这里的minKey、maxKey为整型的最小值和最大值),将整个取值范围划分为多个chunk,每个chunk(通常配置为64MB)包含其中一小段的数据。

Chunk1包含x的取值在[minKey, -75)的所有文档,而Chunk2包含x取值在[-75, 25)之间的所有文档... 每个chunk的数据都存储在同一个Shard上,每个Shard可以存储很多个chunk,chunk存储在哪个shard的信息会存储在Config server种,mongos也会根据各个shard上的chunk的数量来自动做负载均衡。

范围分片能很好的满足『范围查询』的需求,比如想查询x的值在[-30, 10]之间的所有文档,这时mongos直接能将请求路由到Chunk2,就能查询出所有符合条件的文档。

范围分片的缺点在于,如果shardkey有明显递增(或者递减)趋势,则新插入的文档多会分布到同一个chunk,无法扩展写的能力,比如使用_id作为shard key,而MongoDB自动生成的id高位是时间戳,是持续递增的。

(2).Hash分片

Hash分片是根据用户的shard key计算hash值(64bit整型),根据hash值按照『范围分片』的策略将文档分布到不同的chunk。

mongodb3.4

Hash分片与范围分片互补,能将文档随机的分散到各个chunk,充分的扩展写能力,弥补了范围分片的不足,但不能高效的服务范围查询,所有的范围查询要分发到后端所有的Shard才能找出满足条件的文档。

(3).合理的选择shard key

选择shard key时,要根据业务的需求及『范围分片』和『Hash分片』2种方式的优缺点合理选择,同时还要注意shard key的取值一定要足够多,否则会出现单个jumbo chunk,即单个chunk非常大并且无法分裂(split);比如某集合存储用户的信息,按照age字段分片,而age的取值非常有限,必定会导致单个chunk非常大。

4.mongos

Mongos作为Sharded cluster的访问入口,所有的请求都由mongos来路由、分发、合并,这些动作对客户端driver透明,用户连接mongos就像连接mongod一样使用。

Mongos会根据请求类型及shard key将请求路由到对应的Shard。

(1).查询请求

查询请求不包含shard key,则必须将查询分发到所有的shard,然后合并查询结果返回给客户端,查询请求包含shard key,则直接根据shard key计算出需要查询的chunk,向对应的shard发送查询请求.

(2).写请求

写操作必须包含shard key,mongos根据shard key算出文档应该存储到哪个chunk,然后将写请求发送到chunk所在的shard。

(3).更新/删除请求

更新、删除请求的查询条件必须包含shard key或者_id,如果是包含shard key,则直接路由到指定的chunk,如果只包含_id,则需将请求发送至所有的shard。

(4).其他命令请求

除增删改查外的其他命令请求处理方式都不尽相同,有各自的处理逻辑,比如listDatabases命令,会向每个Shard及Config Server转发listDatabases请求,然后将结果进行合并。

5.Config Server

(1).config database

Config server存储Sharded cluster的所有元数据,所有的元数据都存储在config数据库,3.2版本后,Config Server可部署为一个独立的复制集,极大的方便了Sharded cluster的运维管理。

mongos> use config
switched to db config
mongos> db.getCollectionNames()
[
"shards",
"actionlog",
"chunks",
"mongos",
"collections",
"lockpings",
"settings",
"version",
"locks",
"databases",
"tags",
"changelog"
]
(2).config.shards

config.shards集合存储各个Shard的信息,可通过addShard、removeShard命令来动态的从Sharded cluster里增加或移除shard。如下所示,cluster目前拥有2个shard,均为复制集。

mongos> db.addShard("mongo-9003/10.1.72.135:9003,10.1.72.136:9003,10.1.72.137:9003")
mongos> db.addShard("mongo-9003/10.1.72.135:9003,10.1.72.136:9003,10.1.72.137:9003")
mongos> db.shards.find()
"_id" : "mongo-9003", "host" : "mongo-9003/10.1.72.135:9003,10.1.72.136:9003,10.1.72.137:9003"
"_id" : "mongo-9004", "host" : "mongo-9004/10.1.72.135:9004,10.1.72.136:9004,10.1.72.137:9004"
(3).config.databases

config.databases集合存储所有数据库的信息,包括DB是否开启分片,primary shard信息,对于数据库内没有开启分片的集合,所有的数据都会存储在数据库的primary shard上。

如下所示,shtest数据库是开启分片的(通过enableSharding命令),primary shard为mongo-9003; 而test数据库没有开启分片,primary shard为mongo-9003。

mongos> sh.enableSharding("shtest")
"ok" : 1
mongos> db.databases.find()
"_id" : "shtest", "primary" : "mongo-9003", "partitioned" : true
"_id" : "test", "primary" : "mongo-9003", "partitioned" : false

Sharded cluster在数据库创建时,为用户选择当前存储数据量最小的shard作为数据库的primary shard,用户也可调用movePrimary命令来改变primary shard以实现负载均衡,一旦primary shard发生改变,mongos会自动将数据迁移到的新的primary shard上。

(4).config.colletions

数据分片是针对集合维度的,某个数据库开启分片功能后,如果需要让其中的集合分片存储,则需调用shardCollection命令来针对集合开启分片。

如下命令,针对shtest数据里的hello集合开启分片,使用x字段作为shard key来进行范围分片。

mongos> sh.shardCollection("shtest.coll", x: 1)
"collectionsharded" : "shtest.coll", "ok" : 1
mongos> db.collections.find()
"_id" : "shtest.coll", "lastmodEpoch" : ObjectId("57175142c34046c3b556d302"), "lastmod" : ISODate("1970-02-19T17:02:47.296Z"), "dropped" : false, "key" : "x" : 1 , "unique" : false
(5).config.chunks

集合分片开启后,默认会创建一个新的chunk,shard key取值[minKey, maxKey]内的文档(即所有的文档)都会存储到这个chunk。当使用Hash分片策略时,也可以预先创建多个chunk,以减少chunk的迁移。

mongos> db.chunks.find(ns: "shtest.coll")
"_id" : "shtest.coll-x_MinKey", "ns" : "shtest.coll", "min" : "x" : "$minKey" : 1 , "max" : "x" : "$maxKey" : 1 , "shard" : "mongo-9003", "lastmod" : Timestamp(1, 0), "lastmodEpoch" : ObjectId("5717530fc34046c3b556d361")

当chunk里写入的数据量增加到一定阈值时,会触发chunk分裂,将一个chunk的范围分裂为多个chunk,当各个shard上chunk数量不均衡时,会触发chunk在shard间的迁移。如下所示,shtest.coll的一个chunk,在写入数据后分裂成3个chunk。

mongos> use shtest
mongos> for (var i = 0; i < 10000; i++) db.coll.insert( x: i );
mongos> use config
mongos> db.chunks.find(ns: "shtest.coll")
"_id" : "shtest.coll-x_MinKey", "lastmod" : Timestamp(5, 1), "lastmodEpoch" : ObjectId("5703a512a7f97d0799416e2b"), "ns" : "shtest.coll", "min" : "x" : "$minKey" : 1 , "max" : "x" : 1 , "shard" : "mongo-9003"
"_id" : "shtest.coll-x_1.0", "lastmod" : Timestamp(4, 0), "lastmodEpoch" : ObjectId("5703a512a7f97d0799416e2b"), "ns" : "shtest.coll", "min" : "x" : 1 , "max" : "x" : 31 , "shard" : "mongo-9003"
"_id" : "shtest.coll-x_31.0", "lastmod" : Timestamp(5, 0), "lastmodEpoch" : ObjectId("5703a512a7f97d0799416e2b"), "ns" : "shtest.coll", "min" : "x" : 31 , "max" : "x" : "$maxKey" : 1 , "shard" : "mongo-9004"
(6).config.settings

config.settings集合里主要存储sharded cluster的配置信息,比如chunk size,是否开启balancer等

mongos> db.settings.find()
"_id" : "chunksize", "value" : NumberLong(64)
"_id" : "balancer", "stopped" : false

通过一步步创建sharded cluster来认识mongodb

 

https://www.cnblogs.com/xybaby/p/6832296.html
 

 

正文

  mongodb是目前使用非常广泛的nosql(not only sql)之一,在db engines上排名非常靠前,下图是5月份的排名:

  

  可以看到前面四个都是传统的关系型数据库,而mongodb在nosql中拔得头筹。本文会简单介绍mongodb的一些特性,然后通过在Linux环境下一步步搭建sharded cluster来学习mongodb。本文实验的mongodb是mongodb3.0,可能与最新的版本(mongodb3.4)在细节之处略有差异。

 

Mongodb特性

   官方一句话就能概括Mongodb的特点:
  MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling.

  开源、基于文档(document oriented)、高性能、高可用、自动伸缩。

  开源

  这个好处就不用多说了,GitHub上有源码。

  面向文档
  文档(document)在很多编程语言都有类似的数据结构,各种table、map、dict,再也不用使用DAO(data access object)。比如在python中,document与dict对应,array与list对应。
      document也支持嵌套的document和array,这样的话也能部分解决关联查询(当然,虽然把相关信息放在一个嵌套的document降低了关联查询的开销,但在某些情况不得不需要关联查询的时候还是有点头疼)
  由于基于document,所以就schema free(模式自由)啦,使用关系型数据的同学都知道,线上修改表结构是多么麻烦的一件事情。但在mongodb中,增该删一个字段太容易了,这个也是最后开发人员喜欢的一点,比如游戏服务器,玩家的持久化数据会不停的变化,每次更新都会增加一些功能,也就回增加一些需要持久化的字段,用mongodb就很合适。
  
  高性能
  支持嵌套的document,在关系型数据库中需要联合查询的耗时操作,在mongodb中一条查询就能搞定
  丰富的索引支持,而且索引还支持嵌套文档和数组
  在使用了sharding机制的情况下,读写操作可以路由到不同的shard,提到了集群的并发性能
 
  高可用
  要想mongodb高可用,那么就得使用mongodb的复制机制:replica set
  replica set通过异步复制(Asynchronous replication)和自动Failover来保证可用性
  后面会专门介绍replica set
 
  自动扩展(水平拆分)
  在关系型数据中,当单个表数据量过大的时候,一般会通过垂直分表或者水平分表的方式来提到数据库吞吐量。在mongodb中,sharding是其核心功能之一,提供了自动的水平扩展(horizontal scalability)来对数据量比较大的集合进行拆分,sharding将同一个集合的不同子集数据放在不同的机器上,当应用程序选择好适当的sharding key,可以将读写操作路由到某一个shard上,大大提高了集群吞吐性能。
  后面会专门介绍sharding cluster的组成
 

预备知识

  本文并不涵盖mongodb的基础知识,但是为了后面介绍sharding知识,以及搭建sharded cluster,在这里介绍一下_id这个特殊的字段(field)
  默认情况下,mongodb会在集合的_id字段上创建unique index。如果没有在持久化的文档中包含_id,那么mongodb会自动添加这个字段,其value是一个ObjectId。
  mongodb官方建议_id使用ObjectId、或者自然唯一标示(unique identifier)、说着自增的数字、或者UUID。_id在sharding相关的CRUD中有特殊性,具体使用的时候可以参加文档。
  另外,为了后文描述方便,这里声明几个在mongodb中的概念
  DB:与mysql的DB对应
  collection、集合: 与mysql的table对应
  document:与mysql的record对应

replica set

  MongoDB中通过replica set(复制集)来提供高可用性:冗余与自动failover。
  复制集是说将同一份数据的多分拷贝放在不同的机器(甚至不同的数据中心)来提高容错。一个典型的replica set由一组mongod实例组成,其中有且仅有一个节点提供写操作,称之为primary,primary也是默认的读节点。同时,replica set中可包含一个到多个secondary节点,secondary节点只提供读操作。如下图所示:
  

 

  应用程序通过驱动与Primary连接,所有的写操作都在Primary上进行,同时primary会将这些操作写到oplog(operation log)中,secondary通过异步复制oplog,然后在本地数据集上执行oplog中的操作,这样就达到了数据的一致性。从这里可以看到,虽然secondary和primary维护的上同一份数据,但是其变更是要迟于primary的。

  如果应用程序对数据的实时性要求不太高,比如评论数据、聚合数据等,那么可以从secondary读取,这样可以做到读写分离和高并发。如果拷贝放在不同的数据中心,能更好的提供数据局部性(data locality)和分布式服务的可用性。
 
  我们看到,如果一个Secondary不能正常工作了(可能是进程crash、物理损坏、网络故障),对应用程序来说影响并不大。但是如果primary不能工作了呢?这个时候mongodb的automatic failover就开始发挥作用了。
  在replica set中的所用mongod节点之间都会有心跳(heartbeat)存在,如果超过一定时间其他节点没有收到primary的心跳,那么就认为primary挂掉了。可被选举的secondary会投票选举出新的primary。整个过程如下所示:

 

  自动的failover 虽然保证了mongodb的高可用性,但是在primary到secondary的切换过程中,这一段时间,mongodb是无法提供写操作的。表现就是对于应用程序的数据库操作请求会返回一些错误,这个时候应用程序需要识别这些错误,然后做重试。

  

  除了Primary和Secondary,在replica set中还可以存在存在另外一种节点:Arbiter。Arbiter与Secondary节点的区别在于,Arbiter不持久化数据(do not bearing data),  自然也不可能在Primary挂掉的时候被选举。Arbiter的作用在于投票:为了选出新的primary,secondary投票规则是少数服从多数,如果replica set中的节点数目是偶数,那么就可能出现“平局”的情况,所以加入一个Arbiter就可以以最小的代价解决这个问题。

 

   Arbiter不持久化数据,所以占用的磁盘空间也很少,对硬件的要求也不高。官方建议,Arbiter不要和primary或者secondary放在同一个物理主机上。
  在后面的演示中,也会在replica set中加入一个Arbiter,减少磁盘占用。

sharded cluster

  所谓sharding就是将同一个集合的不同子集分发存储到不同的机器(shard)上,Mongodb使用sharding机制来支持超大数据量,将不同的CRUD路由到不同的机器上执行,提到了数据库的吞吐性能。由此可见,sharding是非常常见的scale out方法。

  

 

  如上图所示,一个集合(Collection1)有1T的数据,原本放在一个单独的数据库中,通过sharding,将这个集合的数据放在四个独立的shard中,每一个shard存储这个集合256G的数据。每个shard物理上是独立的数据库,但逻辑上共同组成一个数据库。

  一个sharded cluster由一下三部分组成:config server,shards,router。如图所示:

  

 

  shards

  存储数据,可以是单个的mongod,也可以是replica set。在生产环境中,为了提高高可用性,都会使用replica set。存储在mongod上的数据以chunk为基本单位,默认的大小为64M,后面会介绍shard上数据的分裂(split)与迁移(migration)

  config server

  存储集群的元数据(metadata),即数据的哪一部分放在哪一个shard上,router将会利用这些元数据将请求分发到对应的shards上,shards上chunk的迁移也是config server来控制的。

  router:

  mongos实例,在一个集群中直接为应用程序提供服务,利用config server上的元数据来制定最佳的查询计划。

 

  数据分割(data partition)

  从前文知道,MongoDB在collection这个级别进行数据的切块,称之为sharding。块的最小粒度是chunk,其大小(chunkSize)默认为64M。

  当一个集合的数据量超过chunkSize的时候,就会被拆分成两个chunk,这个过程称为splitting。那么按照什么原则将一个chunk上的数据拆分成两个chunk,这就是Sharding key的作用,Sharding key是被索引的字段,通过sharding key,就可以把数据均分到两个chunk,每一个document在哪一个chunk上,这就是元数据信息。元数据信息存放在config server上,方便router使用。

  如果sharding cluster中有多个shard,那么不同shard上的chunk数目可能是不一致的,这个时候会有一个后台进程(balancer)来迁移(migrate)chunk,从chunk数目最多的shard迁移到chunk数目最少的chunk,直到达到均衡的状态。迁移的过程对应用程序来说是透明的。

  如下图所示,迁移之前ShardA ShardB上都有3个chunk,而Shard C上只有一个Chunk。通过从ShardB上迁移一个chunk到ShardC,就达到了一个均衡的状态。  

  splitting和migration 的目的是为了让数据在shards之间均匀分布,其根本目标是为了将对数据的CRUD操作均衡地分发到各个shard,提高集群的并发性能。

  

Sharded cluster搭建

  声明,本章节只是演示Sharded Cluster的搭建过程,与生产环境还是有较大差异,不过我也会在文中尽量指出这些差异。首先需要注意的是,本文的演示不涉及到鉴权(--auth),但在生产环境中鉴权是非常重要的,相信大家都还记得春节期间Mongodb被劫持、被攻击的事件。
  前文已经提到,一个典型的Sharded Cluster包括router(mongos)、config server和shards,其中每个shard都可以是单点(standalone)或者复制集(replica set)。接下来的演示包括一个router, 三个config server,两个shard。每一个shard都是有一个primary、一个secondary和一个arbiter组成的replica set。
  在开始之前,首先预定义好所有需要用到的变量,如下所示:
复制代码
 1 #!/bin/bash
 2 export BIN_HOME=/usr/local/mongodb/bin
 3 export DB_PATH=/home/mongo_db/data
 4 export LOG_PATH=/home/mongo_db/log
 5 
 6 LOCAL=127.0.0.1
 7 
 8 #config rs
 9 export RS1_1_DB_PATH=$DB_PATH/rs1_1
10 export RS1_2_DB_PATH=$DB_PATH/rs1_2
11 export RS1_3_DB_PATH=$DB_PATH/rs1_3
12 export RS2_1_DB_PATH=$DB_PATH/rs2_1
13 export RS2_2_DB_PATH=$DB_PATH/rs2_2
14 export RS2_3_DB_PATH=$DB_PATH/rs2_3
15 
16 export RS1_1_DB_LOG=$LOG_PATH/rs1_1.log
17 export RS1_2_DB_LOG=$LOG_PATH/rs1_2.log
18 export RS1_3_DB_LOG=$LOG_PATH/rs1_3.log
19 export RS2_1_DB_LOG=$LOG_PATH/rs2_1.log
20 export RS2_2_DB_LOG=$LOG_PATH/rs2_2.log
21 export RS2_3_DB_LOG=$LOG_PATH/rs2_3.log
22 
23 export RS1_1_PORT=27018
24 export RS1_2_PORT=27019
25 export RS1_3_PORT=27020
26 export RS2_1_PORT=27021
27 export RS2_2_PORT=27022
28 export RS2_3_PORT=27023
29 
30 export RS1=rs1
31 export RS2=rs2
32 
33 #config config_server
34 export CONF1_DB_PATH=$DB_PATH/db_conf1
35 export CONF2_DB_PATH=$DB_PATH/db_conf2
36 export CONF3_DB_PATH=$DB_PATH/db_conf3
37 
38 export CONF1_DB_LOG=$LOG_PATH/conf1.log
39 export CONF2_DB_LOG=$LOG_PATH/conf2.log
40 export CONF3_DB_LOG=$LOG_PATH/conf3.log
41 
42 export CONF1_PORT=40000
43 export CONF2_PORT=40001
44 export CONF3_PORT=40002
45 
46 export CONF1_HOST=$LOCAL:$CONF1_PORT
47 export CONF2_HOST=$LOCAL:$CONF2_PORT
48 export CONF3_HOST=$LOCAL:$CONF3_PORT
49 
50 #config route_server
51 export ROUTE_DB_LOG=$LOG_PATH/route.log
52 
53 export ROUTE_PORT=27017
复制代码

   可以在会话窗口中将这些命令执行一遍,不过更好的方式是将其保存在一个文件中(如mongodb_define.sh),然后执行这个文件就行了:source mongodb_define.sh

启动shards(replica set)

  在这一部分,会创建两个replica set,分别是rs1, rs2。每个replica set包含三个节点,且其中一个是arbiter。由于两个replica set创建过程没什么区别,因此以rs1为例。关于replica set的搭建,可参见mongodb doc中deploy-replica-set-for-testing部分,讲得比较清楚。
  step1: 首先得创建好存放数据的目录:
  mkdir -p $RS1_1_DB_PATH
  mkdir -p $RS1_2_DB_PATH
  mkdir -p $RS1_3_DB_PATH
  PS: -p means "no error if existing, make parent directories as needed"
 
  step2: 启动组成rs1的三个mongod 

  $BIN_HOME/mongod --port $RS1_1_PORT --dbpath $RS1_1_DB_PATH --fork --logpath $RS1_1_DB_LOG --replSet $RS1 --smallfiles --nojournal
  $BIN_HOME/mongod --port $RS1_2_PORT --dbpath $RS1_2_DB_PATH --fork --logpath $RS1_2_DB_LOG --replSet $RS1 --smallfiles --nojournal
  $BIN_HOME/mongod --port $RS1_3_PORT --dbpath $RS1_3_DB_PATH --fork --logpath $RS1_3_DB_LOG --replSet $RS1 --smallfiles --nojournal

  关于mongod的启动选项,可以通过mongod --help查看,在上面的命令行中,--replSet 指定了replica set的名字, --smallfiles 声明使用更小的默认文件, --nojournal表明不开启journaling机制。注意,在这个地方不开启journaling是因为实验环境磁盘空间有限,而所有的mongod实例都在这个机器上,在生成环境中,一定要开始journaling,这个是mongodb durability的保证。
  
  step3:初始化复制集rs1
  在这一步,需要通过mongdb的客户端mongo连接到复制集的任何一个节点,对复制集初始化,这里连接到RS1_1(端口为27018):
  mongo --port $RS1_1_PORT
  先来看一下现在复制集的状态(PS:下面所有以 > 开头的命令行都表示是在mongo这个交互式客户端输入的指令)
  > rs.status()
  
  可以看到这个复制集还没有初始化
  >config = {

    _id : "rs1",
    members : [
      {_id : 0, host : "127.0.0.1:27018"},
      {_id : 1, host : "127.0.0.1:27019"},
      {_id : 2, host : "127.0.0.1:27020", arbiterOnly: true},
    ]
  }

  >rs.initiate(config)

  
  从config和运行后的复制集状态都可以看到,RS1_3(127.0.0.1:27020)这个mongod为一个Arbiter,即只参与投票,不持久化数据。另外RS1_1为Primary, RS1_2为Secondary。
  到此为止,复制集rs1就启动好了。
 
 
  关于s2的启动,下面也给出所有命令。方便读者实践

  mkdir -p $RS2_1_DB_PATH
  mkdir -p $RS2_2_DB_PATH
  mkdir -p $RS2_3_DB_PATH

  $BIN_HOME/mongod --port $RS1_1_PORT --dbpath $RS1_1_DB_PATH --fork --logpath $RS1_1_DB_LOG --replSet $RS1 --smallfiles --nojournal
  $BIN_HOME/mongod --port $RS1_2_PORT --dbpath $RS1_2_DB_PATH --fork --logpath $RS1_2_DB_LOG --replSet $RS1 --smallfiles --nojournal
  $BIN_HOME/mongod --port $RS1_3_PORT --dbpath $RS1_3_DB_PATH --fork --logpath $RS1_3_DB_LOG --replSet $RS1 --smallfiles --nojournal

  mongo --port $RS2_1_PORT
  >config = {
  _id : "rs2",
  members : [
  {_id : 0, host : "127.0.0.1:27021"},
  {_id : 1, host : "127.0.0.1:27022"},
  {_id : 2, host : "127.0.0.1:27023", arbiterOnly: true},
  ]
  }
  >rs.initiate(config)

启动config servers

  mongodb官方建议config server需要三个mongod实例组成,每一个mongod最好部署在不同的物理机器上。这个三个mongod并不是复制集的关系,

  step1:创建db目录

  mkdir -p $CONF1_DB_PATH
  mkdir -p $CONF2_DB_PATH
  mkdir -p $CONF3_DB_PATH

  step2:启动三个mongod实例:

  $BIN_HOME/mongod --port $CONF1_PORT --dbpath $CONF1_DB_PATH --fork --logpath $CONF1_DB_LOG --configsvr --smallfiles --nojournal
  $BIN_HOME/mongod --port $CONF2_PORT --dbpath $CONF2_DB_PATH --fork --logpath $CONF2_DB_LOG --configsvr --smallfiles --nojournal
  $BIN_HOME/mongod --port $CONF3_PORT --dbpath $CONF3_DB_PATH --fork --logpath $CONF3_DB_LOG --configsvr --smallfiles --nojournal

  同样启动参数中nojournal只是为了节省存储空间,在生产环境中一定要使用journaling。与创建replica set时mongod的启动不同的是,这里有一个configsvr 选项,表明这些节点都是作为config server存在。

  再启动这三个mongod之后,不会有类似replica set那样讲三个mongod绑定之类的操作,也说明了config server之间是相互独立的

 

启动router

  在Sharded Cluster中,router(mongos)是应用程序连接的对象,一切对mongodb的操作都通过router来路由
  step1:启动mongos
 
  $BIN_HOME/mongos --port $ROUTE_PORT --configdb $CONF1_HOST,$CONF2_HOST,$CONF3_HOST --fork --logpath $ROUTE_DB_LOG --chunkSize 32
  注意这里的可执行程序是mongos,而不是之前的mongod,关于参数,也是可以通过mongos --help查看的。在上面的命令中,--configdb选项指定了三个config server,--chunkSize指定了chunk的大小,单位为M。关于chunksize,默认是64M,虽然可以在初次启动的时候指定chunksize,但mongodb官方推荐按照以下方式修改。 在本文中将chunkSize改小的目的,是为了以后实验的时候更方便观察数据的拆分和迁移。
  chunkSize事实上会持久化到config.setting中,连接到mongos可查看:
  mongo --port $ROUTE_PORT 
  

  在上面截图蓝色框中可以看出,现在还没有任何shard的信息,原因是到现在为止,config servers与replica set还没有任何关系

 
  step2:将在前面创建的两个replica set(rs1 rs2)加入到Sharded Cluster中
  mongo --port $ROUTE_PORT 

  mongos> sh.addShard(\'rs1/127.0.0.1:27018\')
  mongos> sh.addShard(\'rs2/127.0.0.1:27021\')

  PS:为什么需要在rs1后面指定一个mongod的ip port,这个是用来找到对应的mongod,继而找到相应rs

  再次查看结果:

  
  可以看到已经添加了两个shard,每一个都是一个replica set。有意思的是Arbiter(比如RS1_3)并没有显示在查询结果中,可能的原因是Arbiter并不持久化数据,显示在这里也没有什么意义。
 
  到此为止,整个Sharded Cluster就算搭建好了,但是还未进入真正使用阶段,要发挥Sharded Cluster的作用,我们得指定哪些collection可以被sharding,以及如何sharding

创建sharding key

  为了演示,我们假设添加一个db叫test_db, 其中有两个collection,一个是需要sharding的,叫sharded_col;另一个暂时不用sharding,叫non_sharded_col, 当然之后也可以增加新的集合,或者把原来没有sharding的集合改成sharding。

  一下操作都需要登录到router进行: mongo --port $ROUTE_PORT 

  step1:首先得告知mongodb test_db这个数据库支持sharding

  mongos> sh.enableSharding("test_db")
  { "ok" : 1 }

  这个时候可以查看数据库的状态,注意,是在config这个db下面的databases集合

  mongos> use config

  mongos> db.databases.find()
  { "_id" : "admin", "partitioned" : false, "primary" : "config" }
  { "_id" : "test_db", "partitioned" : true, "primary" : "rs1" }
  从查询结果可以看到,test_db是支持sharding的("partitioned" : true)。另外上面加粗部分primary: rs1,这个primary与replica set里面的primary不是一回事,这里的primary是primary shard的意思,我们知道即使在sharded cluster环境中,一些数据量比较小的db也是无需分片的,这些db默认就存放在primary shard上面
 
  step2:为需要的collection(即这里的sharded_col)指定sharding key
  前面已经提到了sharding key的作用,关于sharding key的选择,是一个比较复杂的问题,sharding key对索引,对CRUD语句的操作都有诸多限制,这一部分以后再细讲,在这里默认使用_id做sharding key(_id是mongodb默认为每个集合增加的索引)
  mongos> sh.shardCollection(\'test_db.sharded_col\', {\'_id\': 1})
  接下来看看整个sharded cluster的状态:

  

  sh.status()反应的内容事实上也是来自config整个数据库的内容,只不过做了一定程度的整合。从上面可以看到,有两个shard,rs1, rs2;test_db允许sharding,test_db.sharded_col整个collection的sharding key为{"_id": 1},且目前只有一个chunk在rs1整个shard上。

总结:

  到目前为止,我们已经搭建了一个有三个config server,两个shard的sharded cluster,其中每一个shard包含三个节点的replica set,且都包含一个Arbiter。我们可以查看一下刚创建好之后各个mongod实例持久化的数据大小:

  

  可以看到,两个Arbiter(rs1_3, rs2_3)所占的空间要小得多。

  对于应用程序来说,集群(sharded cluster)和单点(standalone)是有一定差异的,如果需要发挥sharded cluster高性能、高可用的特点,需要根据应用场景精心选择好sharding key,而sharding key的选择跟索引的建立以及CRUD语句息息相关,这一部分以后再聊。对于目前搭建的这个实例,简单测试的话,往sharded_col插入足够多条document就能看到chunks的拆分和迁移。

 

references:

db engines

the-id-field

replication-introduction

deploy-replica-set-for-testing

deploy-shard-cluster

本文版权归作者xybaby(博文地址:http://www.cnblogs.com/xybaby/)所有,欢迎转载和商用,请在文章页面明显位置给出原文链接并保留此段声明,否则保留追究法律责任的权利,其他事项,可留言咨询。
 
 
标签: mongodb

以上是关于mongodb3.4 Sharded cluster的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB之 Sharded cluster架构原理

mongodb3.4.4安装

Deploy A MongoDB 4.0 Sharded Cluster

MongoDB——MongoDB分片集群(Sharded Cluster)

通过一步步创建sharded cluster来认识mongodb

Using Oracle Data Guard with a Sharded Database