快速体验mongoDB分片

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 随着大数据海量数据的不断涌现,分布式,横向扩展是系统扩展的重要方式之一。基于文档的NoSQL领头羊mongoDB正是这样一个分布式系统,通过分片集群将所有数据分成数据段,并将每个数据段写入不同的节点。

随着大数据海量数据的不断涌现,分布式,横向扩展是系统扩展的重要方式之一。基于文档的NoSQL领头羊mongoDB正是这样一个分布式系统,通过分片集群将所有数据分成数据段,并将每个数据段写入不同的节点。本文简要描述mongoDB分片特性,以及给出演示,快速体验mongoDB分片方式。

一、为什么需要shard

    存储容量需求超出单机磁盘容量
    活跃的数据集超出单机内存容量,导致很多请求都要从磁盘读取数据,影响性能
    写IOPS超出单个mongoDB节点的写服务能力
    mongoDB支持自动分片以及手动分片,分片的基本单位是集合

二、Shared cluster架构

    Mongos
            客户端访问路由节点,mongos进行数据读写
    Config Server
            保存元数据以及集群配置信息
    Shard Server
            每一个shard包含特定集合数据的一部分,且shard可以配置为复制集

三、什么是主分片

    主分片用于存储所有未开启分片集合的数据
    每一个数据库都有一个主分片
    通过movePrimary命令改变主分片
    基于已经使用了复制集的环境,在开启一个分片集群的情形下,已经存在的数据库依旧位于原有的分片
    可以创建指向单个分片的片键

四、演示mongodb分片

//演示环境,在同一台机器上使用不同的端口来实现
//包含2个分片节点,端口号(28000,28001),一个config server,端口号(29000)
//本演示未涉及到副本集
# more /etc/redhat-release 
CentOS release 6.7 (Final)

# mongod --version
db version v3.0.12
git version: 33934938e0e95d534cebbaff656cde916b9c3573

//创建相应目录
# mkdir -pv /data/{s1,s2,con1}

//以下分别启动2个mongod分片实例
# mongod --shardsvr --dbpath  /data/s1 --port 28000 --logpath /data/s1/s1.log --smallfiles --oplogSize 128 --fork
# mongod --shardsvr --dbpath  /data/s2 --port 28001 --logpath /data/s2/s2.log --smallfiles --oplogSize 128 --fork

//以下分别启动config server以及mongos
# mongod --configsvr --dbpath  /data/con1 --port 29000 --logpath  /data/con1/config.log --fork 
# mongos --configdb localhost:29000 --logpath  /var/log/mongos.log --fork 

//登陆到mongo客户端
# mongo
MongoDB shell version: 3.0.12
connecting to: test
mongos> show dbs;
admin   (empty)
config  0.016GB

//添加分片
mongos> sh.addShard("localhost:28000") 
{ "shardAdded" : "shard0000", "ok" : 1 }
mongos> sh.addShard("localhost:28001")
{ "shardAdded" : "shard0001", "ok" : 1 }

//插入文档
mongos> db
test
mongos> for (i=0;i<1000000;i++){
    db.users.insert(
        {
                i:i,
                username:"user"+i,
                age:Math.floor(Math.random()*120),
                created:new Date()
        }
    );
}
WriteResult({ "nInserted" : 1 })

//查看分片状态
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("57c64b0e0ea3f71b79b3fb8e")
}
  shards:
        {  "_id" : "shard0000",  "host" : "localhost:28000" }
        {  "_id" : "shard0001",  "host" : "localhost:28001" }
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  0
        Migration Results for the last 24 hours: 
                No recent migrations
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "test",  "partitioned" : false,  "primary" : "shard0000" }

//通过sh.status()可知,当前的集群环境有2个分片为shard0000,shard0001,在当前主机的28000以及28001端口
//当前有2个数据库,一个是admin,一个test数据库
//可以看到当前我们刚刚创建的集合users位于test库,shard0000,即当前shard0000为主分片

//要对一个集合分片,需要先开启库级分片,如下
mongos> sh.enableSharding("test")
{ "ok" : 1 }

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
       .........
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "test",  "partitioned" : true,  "primary" : "shard0000" }

//在上面的查询中可以看出test数据库partitioned的value已经变成了true        

//为集合users添加索引,sharding会根据索引将其数据分布到不同的片上,所以索引是必须的
//这个sharding与RDBMS的分区表的实质一样
//RDBMS的分区表是将数据分布在单台机器的多个磁盘上
//MongoDB则是将数据分布在不同机器的不同磁盘上
mongos> db.users.ensureIndex({username:1})
{
        "raw" : {
                "localhost:28000" : {
                        "createdCollectionAutomatically" : false,
                        "numIndexesBefore" : 1,
                        "numIndexesAfter" : 2,
                        "ok" : 1
                }
        },
        "ok" : 1
}

//查看已经创建的索引
mongos> db.users.getIndexes()
[
        {
                "v" : 1,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "test.users"
        },
        {
                "v" : 1,
                "key" : {
                        "username" : 1
                },
                "name" : "username_1",
                "ns" : "test.users"
        }
]

//开启集合分片
mongos> sh.shardCollection("test.users",{"username":1})
{ "collectionsharded" : "test.users", "ok" : 1 }

//查看集合的状态
mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
        "_id" : 1,
        "minCompatibleVersion" : 5,
        "currentVersion" : 6,
        "clusterId" : ObjectId("57c689d2425d38d84702dbf4")
}
  shards:
        {  "_id" : "shard0000",  "host" : "localhost:28000" }
        {  "_id" : "shard0001",  "host" : "localhost:28001" }
  balancer:
        Currently enabled:  yes
        Currently running:  no
        Failed balancer rounds in last 5 attempts:  0
        Migration Results for the last 24 hours: 
                10 : Success
                1 : Failed with error 'chunk too big to move', from shard0000 to shard0001
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "test",  "partitioned" : true,  "primary" : "shard0000" }
                test.users
                        shard key: { "username" : 1 }
                        chunks:
                                shard0000       4
                                shard0001       3
                        { "username" : { "$minKey" : 1 } } -->> { "username" : "user167405" } on : shard0001 Timestamp(2, 0) 
                        { "username" : "user167405" } -->> { "username" : "user234814" } on : shard0001 Timestamp(3, 0) 
                        { "username" : "user234814" } -->> { "username" : "user302222" } on : shard0001 Timestamp(4, 0) 
                        { "username" : "user302222" } -->> { "username" : "user369631" } on : shard0000 Timestamp(4, 1) 
                        { "username" : "user369631" } -->> { "username" : "user639266" } on : shard0000 Timestamp(1, 1) 
                        { "username" : "user639266" } -->> { "username" : "user908900" } on : shard0000 Timestamp(1, 2) 
                        { "username" : "user908900" } -->> { "username" : { "$maxKey" : 1 } } on : shard0000 Timestamp(1, 3) 
//从上面的结果可知,基于username分片,分成了7个片,或者说7个chunk,其中shard0000 4个,shard0001 3个
//$minKey,$maxKey表示最小值或最大值,也可以理解为负无穷和正无穷。
//$minKey到user167405位于shard0001,user167405到user234814位于shard0001,其余依此类推

//查看集合的状态
mongos> db.users.stats()
{
        "sharded" : true,
        "paddingFactorNote" : "paddingFactor is unused and unmaintained in 3.0.
         It remains hard coded to 1.0 for compatibility only.",
        "userFlags" : 1,
        "capped" : false,        //Author : Leshami
        "ns" : "test.users",     //Blog   : http://blog.csdn.net/leshami
        "count" : 1000000,
        "numExtents" : 20,
        "size" : 112000000,
        "storageSize" : 212533248,
        "totalIndexSize" : 66863328,
        "indexSizes" : {
                "_id_" : 32916576,
                "username_1" : 33946752
        },
        "avgObjSize" : 112,
        "nindexes" : 2,
        "nchunks" : 7,
        "shards" : {
                "shard0000" : {
                        "ns" : "test.users",
                        "count" : 775304,
                        "size" : 86834048,
                        "avgObjSize" : 112,
                        "numExtents" : 12,
                        "storageSize" : 174735360,
                        "lastExtentSize" : 50798592,
                        "paddingFactor" : 1,
                        "paddingFactorNote" : "paddingFactor is unused and unmaintained in 3.0. 
                        It remains hard coded to 1.0 for compatibility only.",
                        "userFlags" : 1,
                        "capped" : false,
                        "nindexes" : 2,
                        "totalIndexSize" : 47020176,
                        "indexSizes" : {
                                "_id_" : 25214784,
                                "username_1" : 21805392
                        },
                        "ok" : 1
                },
                "shard0001" : {
                        "ns" : "test.users",
                        "count" : 224696,
                        "size" : 25165952,
                        "avgObjSize" : 112,
                        "numExtents" : 8,
                        "storageSize" : 37797888,
                        "lastExtentSize" : 15290368,
                        "paddingFactor" : 1,
                        "paddingFactorNote" : "paddingFactor is unused and unmaintained in 3.0. 
                        It remains hard coded to 1.0 for compatibility only.",
                        "userFlags" : 1,
                        "capped" : false,
                        "nindexes" : 2,
                        "totalIndexSize" : 19843152,
                        "indexSizes" : {
                                "_id_" : 7701792,
                                "username_1" : 12141360
                        },
                        "ok" : 1
                }
        },
        "ok" : 1
}
//上面的结果中可以看到不同shard上对应的记录数,如shard0000为775304,shard0001为224696
//也可以看到很对与当前集合相关的信息,如大小,平均队列长度,索引等等

//下面测试文档查找
mongos> db.users.find({username:"user1000"},{_id:0})
{ "i" : 1000, "username" : "user1000", "age" : 87, "created" : ISODate("2016-08-31T08:31:28.233Z") }
mongos> db.users.find({username:"user639266"},{_id:0})
{ "i" : 639266, "username" : "user639266", "age" : 6, "created" : ISODate("2016-08-31T08:38:30.122Z") }
mongos> db.users.count()
1000000

//以下查看执行计划
//从执行计划可知,当前查询到了分片shard0001,即实现了基于分片的隔离
mongos> db.users.find({username:"user1000"}).explain()
{
        "queryPlanner" : {
                "mongosPlannerVersion" : 1,
                "winningPlan" : {
                        "stage" : "SINGLE_SHARD",
                        "shards" : [
                                {
                                        "shardName" : "shard0001",
                                        "connectionString" : "localhost:28001",
                                        "serverInfo" : {
                                                "host" : "node1.edq.com",
                                                "port" : 28001,
                                                "version" : "3.0.12",
                                                "gitVersion" : "33934938e0e95d534cebbaff656cde916b9c3573"
                                        },
                                        "plannerVersion" : 1,
                                        "namespace" : "test.users",
                                        "indexFilterSet" : false,
                                        "parsedQuery" : {
                                                "username" : {
                                                        "$eq" : "user1000"
                                                }
                                        },
                                        "winningPlan" : {
                                                "stage" : "FETCH",
                                                "inputStage" : {
                                                        "stage" : "SHARDING_FILTER",
                                                        "inputStage" : {
                                                                "stage" : "IXSCAN",
                                                                "keyPattern" : {
                                                                        "username" : 1
                                                                },
                                                                "indexName" : "username_1",
                                                                "isMultiKey" : false,
                                                                "direction" : "forward",
                                                                "indexBounds" : {
                                                                        "username" : [
                                                                                "[\"user1000\", \"user1000\"]"
                                                                        ]
                                                                }
                                                        }
                                                }
                                        },
                                        "rejectedPlans" : [ ]
                                }
                        ]
                }
        },
        "ok" : 1
}                        

五、小结

1、mongodb分片的实质是将数据分散到不同的物理机器,以分散IO,提供并发与吞吐量
2、mongodb分片依赖于片键,即任意一个需要开启的集合都需要创建索引
3、开启分片的集合需要首先在DB级别启用库级分片
4、mongodb的分片由分片服务器,配置服务器以及路由服务器组成
5、基于分片可以结合副本集(replicate set)来实现高可用

相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
运维 NoSQL 安全
【最佳实践】高可用mongodb集群(1分片+3副本):规划及部署
结合我们的生产需求,本次详细整理了最新版本 MonogoDB 7.0 集群的规划及部署过程,具有较大的参考价值,基本可照搬使用。 适应数据规模为T级的场景,由于设计了分片支撑,后续如有大数据量需求,可分片横向扩展。
1160 1
|
2月前
|
存储 NoSQL 前端开发
MongoDB 分片
10月更文挑战第17天
37 2
|
3月前
|
存储 监控 NoSQL
*MongoDB的水平扩展主要通过分片技术实
*MongoDB的水平扩展主要通过分片技术实
52 5
|
3月前
|
存储 NoSQL 前端开发
MongoDB 分片总结
这篇文章总结了MongoDB分片的概念、集群结构、分片实例、配置和测试过程。
69 6
|
7月前
|
存储 负载均衡 NoSQL
MongoDB分片技术:实现水平扩展的利器
【4月更文挑战第30天】MongoDB的分片技术是应对数据增长和复杂业务需求的解决方案,它将数据水平拆分存储在多个实例上,实现数据库的水平扩展。分片带来水平扩展性、负载均衡、高可用性和灵活的数据管理。分片工作涉及mongos路由进程、config server和shard实例。设置分片包括部署配置服务器、添加分片、启动mongos、配置分片键和开始分片。选择合适的分片键和有效管理能确保系统性能和稳定性。
|
4月前
|
存储 运维 NoSQL
轻松上手:逐步搭建你的高可用MongoDB集群(分片)
【8月更文挑战第13天】在数据激增的背景下,传统单机数据库难以胜任。MongoDB作为流行NoSQL数据库,采用分片技术实现水平扩展,有效处理海量数据。分片将数据分散存储,提高并发处理能力和容错性,是高可用架构基石。构建MongoDB集群需理解shard、config server和router三组件协同工作原理。通过具体实例演示集群搭建流程,包括各组件的启动及配置,确保数据高可用性和系统稳定性。合理规划与实践可构建高效稳定的MongoDB集群,满足业务需求并支持未来扩展。
121 0
|
7月前
|
NoSQL 算法 测试技术
【MongoDB 专栏】MongoDB 的自动分片与手动分片
【5月更文挑战第11天】MongoDB的分片技术在处理大规模数据和高并发场景中至关重要,提供自动和手动两种方式。自动分片基于预定义规则,简化管理,适合大部分场景,但灵活性有限。手动分片则允许用户自定义策略,实现高效布局,适用于有特殊需求的应用,但配置复杂。选择分片方式需考虑业务需求、数据特点和技术能力。正确实施分片策略能构建高性能、可扩展的系统,支持企业业务发展。随着技术进步,未来的分片技术将更加智能和易用。
187 3
【MongoDB 专栏】MongoDB 的自动分片与手动分片
|
7月前
|
存储 监控 NoSQL
【MongoDB 专栏】MongoDB 分片策略与最佳实践
【5月更文挑战第10天】MongoDB 分片是应对大数据量的扩展策略,涉及哈希和范围分片两种策略。分片架构包含分片服务器、配置服务器和路由服务器。最佳实践包括选择合适分片键、监控调整、避免热点数据等。注意数据分布不均和跨分片查询的挑战。通过实例展示了如何在电商场景中应用分片。文章旨在帮助理解并优化 MongoDB 分片使用。
270 3
【MongoDB 专栏】MongoDB 分片策略与最佳实践
|
6月前
|
存储 负载均衡 NoSQL
MongoDB的分片功能
【6月更文挑战第6天】MongoDB的分片功能
73 1
|
5月前
|
负载均衡 NoSQL 中间件