19.分片

分片就是将数据库分布在多台服务器上

为什么会用到分片?

1 机器的磁盘空间不足
2 单个的mongoDB服务器已经不能满足大量的插入操作
3 想通过把大数据放到内存中来提高性能

1.组成介绍:

1.分片

MongoDB分片集群将数据分布在一个或多个分片上。每个分片都部署成一个MongoDB副本集,该副本集保存了集群整体数据的一部分。因为每个分片都是一个副本集没所以它们拥有自己的复制机制,能够自动进行故障转移。直接连接单个分片只能查看到部分数据。

2.mongos路由器

用于连接整个集群,它将所有的读写请求指引到合适的分片上。这是一个前端路由,客户端由此接入,然后询问 Config Servers 需要到哪个 Shard 上查询或保存记录,再连接相应的 Shard 进行操作,最后将结果返回给客户端。客户端只需要将原本发给 mongod 的查询或更新请求原封不动地发给 Routing Process,而不必关心所操作的记录
存储在哪个 Shard 上。

3.配置服务器

持久化分片集群的元数据。这些数据包括:全局集群配置;每个数据库、集合和特定范围数据的位置;一份变更记录,保存了数据在分片之间进行迁移的历史信息。

2示例

实现一个这样架构的分片集群:

这里写图片描述

s0Server:18000
s1Server:18001

configServer:18200

route:18010

2.1 启动 Shard Server

--创建数据目录
E:\MyProgram\MongodbDATA\09\s0
E:\MyProgram\MongodbDATA\09\s1
E:\MyProgram\MongodbDATA\09\c

编辑配置文件:

s0Server.conf

dbpath=E:\MyProgram\MongodbDATA\09\s0
bind_ip = 127.0.0.1
port=18000
shardsvr=true

s1Server.conf

dbpath=E:\MyProgram\MongodbDATA\09\s1
bind_ip = 127.0.0.1
port=18001
shardsvr=true

启动 Shard Server 实例 s0Server:

mongod --config s0Server.conf

启动 Shard Server 实例 s1Server:

mongod --config s1Server.conf

2.2 启动 Config Server

1.创建数据目录:

2.配置文件configServer.conf

configsvr=true
dbpath = E:\MyProgram\MongodbDATA\09\c
port = 18200
bind_ip = 127.0.0.1

3.启动 Config Server 实例:

mongod --config configServer.conf

2.3 启动 Route Process

启动 Route Server 实例:

mongos --port 18010 --configdb 127.0.0.1:18200 --chunkSize=1

mongos 启动参数中, chunkSize 这一项是用来指定 chunk 的大小的,单位是 MB,默认大小
为 200MB,为了方便测试 Sharding 效果,我们把 chunkSize 指定为 1MB。

2.4 配置 Sharding

接下来,我们使用 MongoDB Shell 登录到 mongos,添加 Shard 节点

[root@localhost ~]# /Apps/mongo/bin/mongo admin --port 40000 --此操作需要连接 admin 库
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:40000/admin
> db.runCommand({ addshard:"localhost:18000" }) --添加 Shard Server1
{ "shardAdded" : "shard0000", "ok" : 1 }

> db.runCommand({ addshard:"localhost:18001" }) --添加 Shard Server2
{ "shardAdded" : "shard0001", "ok" : 1 }

> db.runCommand({ enablesharding:"test" }) --设置分片存储的数据库
{ "ok" : 1 }

> db.runCommand({ shardcollection: "test.users", key: { _id:1 }}) --设置分片的集合名称,且必须指定 Shard Key,系统会自动创建索引
{ "collectionsharded" : "test.users", "ok" : 1 }
>

2.5 验证 Sharding 正常工作

我们已经对 test.users 表进行了分片的设置,下面我们们插入50w条数据看一下结果

> use test
switched to db test
> for (var i = 1; i <= 500000; i++) db.users.insert({age:i, name:"tom", addr:"Beijing",country:"China"})
>mongos> db.users.stats()
{
        "sharded" : true,    ##说明此表已经被分片了
        "flags" : 1,
        "ns" : "test.users",
        "count" : 500000,
        "numExtents" : 16,
        "size" : 44000016,
        "storageSize" : 66666496,
        "totalIndexSize" : 16253888,
        "indexSizes" : {
                "_id_" : 16253888
        },
        "avgObjSize" : 88.000032,
        "nindexes" : 1,
        "nchunks" : 5,
        "shards" : {
                "shard0000" : {    ##第一个分片大约25M
                        "ns" : "test.users",
                        "count" : 289589,
                        "size" : 25483840,
                        "avgObjSize" : 88.0000276253587,
                        "storageSize" : 33333248,
                        "numExtents" : 8,
                        "nindexes" : 1,
                        "lastExtentSize" : 12083200,
                        "paddingFactor" : 1,
                        "flags" : 1,
                        "totalIndexSize" : 9410576,
                        "indexSizes" : {
                                "_id_" : 9410576
                        },
                        "ok" : 1
                },
                "shard0001" : {   ##第二个分片大约18M
                        "ns" : "test.users",
                        "count" : 210411,
                        "size" : 18516176,
                        "avgObjSize" : 88.00003802082591,
                        "storageSize" : 33333248,
                        "numExtents" : 8,
                        "nindexes" : 1,
                        "lastExtentSize" : 12083200,
                        "paddingFactor" : 1,
                        "flags" : 1,
                        "totalIndexSize" : 6843312,
                        "indexSizes" : {
                                "_id_" : 6843312
                        },
                        "ok" : 1
                }
        },
        "ok" : 1
}

2.6我们看一下磁盘上的物理文件情况

看上述结果,表明 test.users 集合已经被分片处理了,但是通过 mongos 路由,我们并感觉不到是数据存放在哪个 shard 的 chunk 上的,这就是 MongoDB 用户体验上的一个优势,即对用户是透明的

3管理维护 Sharding

3.1 列出所有的 Shard Server

> use admin
> db.runCommand({ listshards: 1 }) --列出所有的 Shard Server
{
        "shards" : [
                {
                        "_id" : "shard0000",
                        "host" : "localhost:18000"
                },
                {
                        "_id" : "shard0001",
                        "host" : "localhost:18001"
                }
        ],
        "ok" : 1
}

3.2 查看 Sharding 信息

> printShardingStatus() --查看 Sharding 信息
--- Sharding Status ---
  sharding version: { "_id" : 1, "version" : 3 }
  shards:
        {  "_id" : "shard0000",  "host" : "localhost:18000" }
        {  "_id" : "shard0001",  "host" : "localhost:18001" }
  databases:
        {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
        {  "_id" : "test",  "partitioned" : true,  "primary" : "shard0000" }
                test.users chunks:
                                shard0000       4
                                shard0001       1
                        { "_id" : { $minKey : 1 } } -->> { "_id" : ObjectId("585
fbdc22730e421633a26a8") } on : shard0000 { "t" : 2000, "i" : 1 }
                        { "_id" : ObjectId("585fbdc22730e421633a26a8") } -->> {
"_id" : ObjectId("585fbdc72730e421633a3f3c") } on : shard0000 { "t" : 1000, "i"
: 3 }
                        { "_id" : ObjectId("585fbdc72730e421633a3f3c") } -->> {
"_id" : ObjectId("585fbdea2730e421633d7527") } on : shard0001 { "t" : 3000, "i"
: 1 }
                        { "_id" : ObjectId("585fbdea2730e421633d7527") } -->> {
"_id" : ObjectId("585fbe432730e4216340ac0c") } on : shard0000 { "t" : 3000, "i"
: 2 }
                        { "_id" : ObjectId("585fbe432730e4216340ac0c") } -->> {
"_id" : { $maxKey : 1 } } on : shard0000 { "t" : 3000, "i" : 3 }

3.3 判断是否是 Sharding

> db.runCommand({ isdbgrid:1 })
    { "isdbgrid" : 1, "hostname" : "acer", "ok" : 1 }
>

3.4 对现有的表进行 Sharding

刚才我们是对表 test.users 进行分片了,下面我们将对库中现有的未分片的表 test.users_2 进行分片处理

先建一个表test.users2:

> use test
switched to db test

插入数据:
> for (var i = 1; i <= 500000; i++) db.users.insert({age:i, name:"tom", addr:"Beijing",country:"China"})

表最初状态如下,可以看出他没有被分片过:

> db.users2.stats()
{
    "ns" : "test.users_2",
    "sharded" : false,
    "primary" : "shard0000",
    "ns" : "test.users_2",
    "count" : 500000,
    "size" : 48000016,
    "avgObjSize" : 96.000032,
    "storageSize" : 61875968,
    "numExtents" : 11,
    "nindexes" : 1,
    "lastExtentSize" : 15001856,
    "paddingFactor" : 1,
    "flags" : 1,
    "totalIndexSize" : 20807680,
    "indexSizes" : {
    "_id_" : 20807680
},
"ok" : 1
}

对其进行分片处理:

首先切换到admin用户

> use admin
switched to db admin

执行分片命令:传入参数:1.要被分片的文档 2.指定片键
> db.runCommand({ shardcollection: "test.users2", key: { _id:1 }})
{ "collectionsharded" : "test.users2", "ok" : 1 }

再次查看分片后的表的状态,可以看到它已经被我们分片了

> use test
switched to db test

> db.users2.stats()
{
    "sharded" : true,
    "ns" : "test.users_2",
    "count" : 505462,
    ……
    "shards" : {
        "shard0000" : {
            "ns" : "test.users2",
            ……
            "ok" : 1
        },
        "shard0001" : {
            "ns" : "test.users2",
            ……
            "ok" : 1
        }
    },
    "ok" : 1
}
>

3.5 新增分片服务器 Shard Server

刚才我们演示的是新增分片表,接下来我们演示如何新增 Shard Server
启动一个新 Shard Server 进程

[root@localhost ~]# mkdir /data/shard/s2
[root@localhost ~]# /Apps/mongo/bin/mongod --shardsvr --port 20002 --dbpath /data/shard/s2
--fork --logpath /data/shard/log/s2.log --directoryperdb
all output going to: /data/shard/log/s2.log
forked process: 6772

配置新 Shard Server
[root@localhost ~]# /Apps/mongo/bin/mongo admin --port 40000
MongoDB shell version: 1.8.1
connecting to: 127.0.0.1:40000/admin

## 添加分片
> db.runCommand({ addshard:"localhost:20002" })
{ "shardAdded" : "shard0002", "ok" : 1 }
> printShardingStatus()
--- Sharding Status ---
sharding version: { "_id" : 1, "version" : 3 }
shards:
    { "_id" : "shard0000", "host" : "localhost:20000" }
    { "_id" : "shard0001", "host" : "localhost:20001" }
    { "_id" : "shard0002", "host" : "localhost:20002" }#新增的Shard Server
databases:
    { "_id" : "admin", "partitioned" : false, "primary" : "config" }
    { "_id" : "test", "partitioned" : true, "primary" : "shard0000" }
test.users chunks:
    shard0002 2
    shard0000 21
    shard0001 21
too many chunksn to print, use verbose if you want to force print
test.users_2 chunks:
    shard0001 46
    shard0002 1
    shard0000 45
too many chunksn to print, use verbose if you want to force print

查看分片表状态,以验证新 Shard Server

> use test
switched to db test
> db.users_2.stats()
{
    "sharded" : true,
    "ns" : "test.users_2",
    ……
    "shard0002" : { ## 新的 Shard Server 已有数据
        "ns" : "test.users_2",
        "count" : 21848,
        "size" : 2097408,
        "avgObjSize" : 96,
        "storageSize" : 2793472,
        "numExtents" : 5,
        "nindexes" : 1,
        "lastExtentSize" : 2097152,
        "paddingFactor" : 1,
        "flags" : 1,
        "totalIndexSize" : 1277952,
        "indexSizes" : {
            "_id_" : 1277952
        },
        "ok" : 1
        }
    },
    "ok" : 1
}
>

3.6 移除 Shard Server

  有些时候有于硬件资源有限,所以我们不得不进行一些回收工作,下面我们就要将刚刚启用的 Shard Server 回收
系统首先会将在这个即将被移除的 Shard Server 上的数据先平均分配到其它的 Shard Server 上,然后最终在将这个 Shard Server 踢下线, 我们需要不停的调用db.runCommand({“removeshard” : “localhost:18002”});来观察这个移除操作进行到哪里了:

> use admin
switched to db admin
> db.runCommand({"removeshard" : "localhost:18002"});
{
    "msg" : "draining started successfully",
    "state" : "started",    ##启动
    "shard" : "shard0002",
    "ok" : 1
}
> db.runCommand({"removeshard" : "localhost:18002"});
{
    "msg" : "draining ongoing",
    "state" : "ongoing",    ##即将开始
    "remaining" : {
    "chunks" : NumberLong(44),  ##块的个数
    "dbs" : NumberLong(0)
},
"ok" : 1
}
……
> db.runCommand({"removeshard" : "localhost:18002"});
{
    "msg" : "draining ongoing",
    "state" : "ongoing",
    "remaining" : {
    "chunks" : NumberLong(1),
    "dbs" : NumberLong(0)
},
"ok" : 1
}
> db.runCommand({"removeshard" : "localhost:18002"});
{
    "msg" : "removeshard completed successfully",
    "state" : "completed",
    "shard" : "shard0002",
    "ok" : 1
}
> db.runCommand({"removeshard" : "localhost:18002"});
{
    "assertion" : "can't find shard for: localhost:20002",
    "assertionCode" : 13129,
    "errmsg" : "db assertion failure",
    "ok" : 0
}

最终移除后,当我们再次调用 db.runCommand({“removeshard” : “localhost:18002”});的时候系统
会报错,已便通知我们不存在 18002 这个端口的 Shard Server 了,因为它已经被移除掉了。
接下来我们看一下表中的数据分布:

> use test
switched to db test
> db.users2.stats()
{
    "sharded" : true,
    "ns" : "test.users_2",
    "count" : 500000,
    "size" : 48000000,
    "avgObjSize" : 96,
    "storageSize" : 95203584,
    "nindexes" : 1,
    "nchunks" : 92,
    "shards" : {
        "shard0000" : {
            "ns" : "test.users_2",
            "count" : 248749,
            "size" : 23879904,
            "avgObjSize" : 96,
            "storageSize" : 61875968,
            "numExtents" : 11,
            "nindexes" : 1,
            "lastExtentSize" : 15001856,
            "paddingFactor" : 1,
            "flags" : 1,
            "totalIndexSize" : 13033472,
            "indexSizes" : {
            "_id_" : 13033472
        },
        "ok" : 1
        },
        "shard0001" : {
            "ns" : "test.users_2",
            "count" : 251251,
            "size" : 24120096,
            "avgObjSize" : 96,
            "storageSize" : 33327616,
            "numExtents" : 8,
            "nindexes" : 1,
            "lastExtentSize" : 12079360,
            "paddingFactor" : 1,
            "flags" : 1,
            "totalIndexSize" : 10469376,
            "indexSizes" : {
            "_id_" : 10469376
        },
        "ok" : 1
        }
    },
    "ok" : 1
}

可以看出数据又被平均分配到了另外 2 台 Shard Server 上了,对业务没什么特别大的影响。

我们可以发现,当我们新增 Shard Server 后数据自动分布到了新 Shard 上,这是由 MongoDB 内部自已实现的。

实际生产环境中最常用的结构–副本集+分片(Replica sets + Sharding)

MongoDB Auto-Sharding 解决了海量存储和动态扩容的问题,但离实际生产环境所需的高可靠、高可用还有些距离,所以有了” Replica Sets + Sharding”的解决方案:
Shard:
使用 Replica Sets,确保每个数据节点都具有备份、自动容错转移、自动恢复能力。
Config:
使用 3 个配置服务器,确保元数据完整性
Route:
使用 3 个路由进程,实现负载平衡,提高客户端接入性能
以下我们配置一个 Replica Sets + Sharding 的环境,架构图如下:
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值