通过一步步创建sharded cluster来认识mongodb
mongodb是目前使用非常广泛的nosql(not only sql)之一,在db engines上排名非常靠前,下图是5月份的排名:

Mongodb特性
MongoDB is an open-source document database that provides high performance, high availability, and automatic scaling.
开源、基于文档(document oriented)、高性能、高可用、自动伸缩。
开源:
这个好处就不用多说了,GitHub上有源码。
预备知识
replica set
应用程序通过驱动与Primary连接,所有的写操作都在Primary上进行,同时primary会将这些操作写到oplog(operation log)中,secondary通过异步复制oplog,然后在本地数据集上执行oplog中的操作,这样就达到了数据的一致性。从这里可以看到,虽然secondary和primary维护的上同一份数据,但是其变更是要迟于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就可以以最小的代价解决这个问题。

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搭建
#!/bin/bash
export BIN_HOME=/usr/local/mongodb/bin
export DB_PATH=/home/mongo_db/data
export LOG_PATH=/home/mongo_db/log LOCAL=127.0.0.1 #config rs
export RS1_1_DB_PATH=$DB_PATH/rs1_1
export RS1_2_DB_PATH=$DB_PATH/rs1_2
export RS1_3_DB_PATH=$DB_PATH/rs1_3
export RS2_1_DB_PATH=$DB_PATH/rs2_1
export RS2_2_DB_PATH=$DB_PATH/rs2_2
export RS2_3_DB_PATH=$DB_PATH/rs2_3 export RS1_1_DB_LOG=$LOG_PATH/rs1_1.log
export RS1_2_DB_LOG=$LOG_PATH/rs1_2.log
export RS1_3_DB_LOG=$LOG_PATH/rs1_3.log
export RS2_1_DB_LOG=$LOG_PATH/rs2_1.log
export RS2_2_DB_LOG=$LOG_PATH/rs2_2.log
export RS2_3_DB_LOG=$LOG_PATH/rs2_3.log export RS1_1_PORT=
export RS1_2_PORT=
export RS1_3_PORT=
export RS2_1_PORT=
export RS2_2_PORT=
export RS2_3_PORT= export RS1=rs1
export RS2=rs2 #config config_server
export CONF1_DB_PATH=$DB_PATH/db_conf1
export CONF2_DB_PATH=$DB_PATH/db_conf2
export CONF3_DB_PATH=$DB_PATH/db_conf3 export CONF1_DB_LOG=$LOG_PATH/conf1.log
export CONF2_DB_LOG=$LOG_PATH/conf2.log
export CONF3_DB_LOG=$LOG_PATH/conf3.log export CONF1_PORT=
export CONF2_PORT=
export CONF3_PORT= export CONF1_HOST=$LOCAL:$CONF1_PORT
export CONF2_HOST=$LOCAL:$CONF2_PORT
export CONF3_HOST=$LOCAL:$CONF3_PORT #config route_server
export ROUTE_DB_LOG=$LOG_PATH/route.log export ROUTE_PORT=
可以在会话窗口中将这些命令执行一遍,不过更好的方式是将其保存在一个文件中(如mongodb_define.sh),然后执行这个文件就行了:source mongodb_define.sh
启动shards(replica set)
$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

_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)

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
在上面截图蓝色框中可以看出,现在还没有任何shard的信息,原因是到现在为止,config servers与replica set还没有任何关系
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
再次查看结果:

创建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

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:
deploy-replica-set-for-testing
通过一步步创建sharded cluster来认识mongodb的更多相关文章
- Java开发环境的搭建以及使用eclipse从头一步步创建java项目
一.java 开发环境的搭建 这里主要说的是在windows 环境下怎么配置环境. 1.首先安装JDK java的sdk简称JDK ,去其官方网站下载最近的JDK即可..http://www.orac ...
- java第一天--Java开发环境的搭建以及使用eclipse从头一步步创建java项目
一.java 开发环境的搭建 这里主要说的是在windows 环境下怎么配置环境. 1.首先安装JDK java的sdk简称JDK ,去其官方网站下载最近的JDK即可..http://www.orac ...
- 搭建一套Java开发环境以及使用eclipse从头一步步创建java项目
一.java 开发环境的搭建 在windows 环境下怎么配置环境. 1.首先安装JDK java的sdk简称JDK ,去其官方网站下载JDK. https://www.oracle.com/tech ...
- IDEA一步步创建Maven管理的Spring入门程序
目前,做Java开发的很多人都在使用IDEA了,而有些人也选择用Eclipse,我这里介绍一下IDEA一步步创建Maven项目的步骤,并创建一个Spring的入门程序(Java项目,非Web项目),讲 ...
- docker下创建redis cluster集群
概述 在Redis中,集群的解决方案有三种 主从复制 哨兵机制 Cluster Redis Cluster是Redis的分布式解决方案,在 3.0 版本正式推出. 准备工作 1.确定本机IP地址 2. ...
- 【Azure Redis 缓存】Windows版创建 Redis Cluster 实验 (精简版)
简介 学习Redis Cluster的第一步,即本地搭建Redis Cluster.但是在Redis的官方文档中,是介绍在Linux系统中搭建Redis Cluster.本文主要介绍在Windows系 ...
- Deploy a Sharded Cluster
Start the Config Server Database Instances for example : mongod --configsvr --dbpath <path> - ...
- 一步步创建Qt Widget项目+TextFinder案例(摘自笔者2015年将出的《QT5权威指南》,本文为试读篇)
创建一个基于应用的QtWidget应用程序 这个手册描述了怎样使用QtCreater创建个一个小的Qt应用程序,Text Finder.它是Qt工具Text Finder例子的简写版本.这个应用 ...
- 一步步创建第一个Docker App —— 4. 部署应用
原文:https://docs.docker.com/engine/getstarted-voting-app/deploy-app/ 在这一步中,将会使用第一步提到的 docker-stack.ym ...
随机推荐
- Access SQL实现连续及不连续Rank排名
一.关于起因 在Excel中我们经常使用Rank函数对数据进行排名操作.而在Access中我们要进行排名是找不到这个Rank函数的,此时我们需要自己书写VBA代码或者建立SQL查询来完成排序操作. 今 ...
- [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(四)
一步步打造一个简单的 MVC 电商网站 - BooksStore(四) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...
- AngularJS1.X学习笔记4-内置事件指令及其他
AngularJS为我们定义了一系列事件指令,方便我们对用户的操作作出响应.甚至他还有一个可选模块提供了触摸事件和手势事件的支持,为移动端开发提供了可能.现在开始学习一下AngularJS的事件指令. ...
- ReactJS入门:展示数据
由于公司开发需要,博主利用闲暇的时间对ReactJS的基础知识进行了一些粗浅的认识和了解.博主对ReactJS的学习主要来自官网(http://reactjs.cn/react/docs/thinki ...
- 高吞吐koa日志中间件
Midlog中间件 node服务端开发中少不了日志打点,而在koa框架下的日志打点在多进程环境中日志信息往往无法对应上下文,而且在高并发下直接进行写buffer操作(内核调用writev)也会造成内存 ...
- JavaScript设计模式读书笔记之一:接口
接口 在JavaScrip中模仿接口 用注释描述接口 用属性检查模仿接口 用鸭式辨型模仿接口 依赖于接口的设计模式 工厂模式 组合模式 装饰者模式 命令模式 接口 在JavaScrip中模仿接口 用注 ...
- 进入html+css世界的正确姿势
今天,我带大家一起走进html+css的世界. HTML其实是HyperText Markup Language的缩写, 超文本标记语言.他是用于告诉浏览器这是一个网页, 也就是说告诉浏览器我是一个H ...
- Java面试题04-final关键字详解
Java面试题04-final关键字详解 本篇博客将会讨论java中final关键字的含义,以及final用在什么地方,感觉看书总会有一些模糊,而且解释的不是很清楚,在此做个总结,以备准备面试的时候查 ...
- less补充函数
1.ceil():向上取整2.floor():向下取整3.percentage():将浮点数转换成百分比3.round():四舍五入4.sqrt():平方根5.abs():绝对值6.pow():乘方运 ...
- Apriori算法(C#)
AprioriMethod.cs using System; using System.Collections.Generic; using System.Linq; using System.Web ...