控制MongoDB中的集合分布

分片标记(Shard tagging)是MongoDB 2.2.0版中的一项新功能。通过对集合进行标记使其被强制写入到本地数据中心,也可以用来将某个集合固定到一个分片或一系列分片中。

注意:尝试分片标记功能,必须使用2.2.0-rc0或更高版本。

使用此功能,首先需要启动一个分片群集:

> sharding = new ShardingTest({shards:3,chunksize:1})

这个命令将启动3个分片,一个配置服务器和一个mongos。并将所有的服务器日志输出到标准输出,所以我建议把这个shell先放在一边,然后使用另一个shell进行以下操作。

启动一个新的shell并连接到mongos(默认为端口30999),并创建一些分片的集合和数据来进行操作:

> // 记住,使用不同的shell
> conn = new Mongo("localhost:30999")
> db = conn.getDB("villains")
>
> // 启用分片
> sh.enableSharding("villains")
>
> // 将集合加入分片
> sh.shardCollection("villains.joker", {jokes:1});
> sh.shardCollection("villains.two-face", {luck:1});
> sh.shardCollection("villains.poison ivy", {flora:1});
> 
> // 添加数据
> for (var i=0; i<100000; i++) { db.joker.insert({jokes: Math.random(), count: i, time: new Date()}); }
> for (var i=0; i<100000; i++) { db["two-face"].insert({luck: Math.random(), count: i, time: new Date()}); }
> for (var i=0; i<100000; i++) { db["poison ivy"].insert({flora: Math.random(), count: i, time: new Date()}); }

现在我们有三个分片和三个集合。如果你查看一下主要的数据块在哪里,你应该看到数据在分片之间相当均衡:

> use config
> db.chunks.find({ns:“villains.joker”},{shard:1,_id:0})。sort({shard:1})
{“shard”:“shard0000”}
{“shard”:“shard0000”}
{“shard”:“shard0000”}
{“shard”:“shard0001”}
{“shard”:“shard0001”}
{“shard”:“shard0001”}
{“shard”:“shard0002”}
{“shard”:“shard0002”}
{“shard”:“shard0002”}
> db.chunks.find({ns:“villains.two-face”},{shard:1,_id:0})。sort({shard:1})
{“shard”:“shard0000”}
{“shard”:“shard0000”}
{“shard”:“shard0000”}
{“shard”:“shard0001”}
{“shard”:“shard0001”}
{“shard”:“shard0001”}
{“shard”:“shard0002”}
{“shard”:“shard0002”}
{“shard”:“shard0002”}
> db.chunks.find({ns:“villains.poison ivy”},{shard:1,_id:0})。sort({shard:1})
{“shard”:“shard0000”}
{“shard”:“shard0000”}
{“shard”:“shard0001”}
{“shard”:“shard0001”}
{“shard”:“shard0002”}
{“shard”:“shard0002”}
 
或许哈雷会说:“布丁”

然而,我们的每个villains可不想和其他人混到一起,所以我们要分开储存这些集合:每个villain一个分片。我们的目标如下:

分片

命名空间

shard0000

“villains.joker”

shard0001

“villains.two-face”

shard0002

“villains.poison ivy”

要做到这一点,我们将使用标记标记描述了一个分片的属性,可以是任何属性(标签非常灵活)。所以,你可以把一个分片标记为“快”,“慢”,“东海岸”,“机架空间”或者随便什么东西。

在这个例子中,我们要标记一个碎片属于某个villain,所以我们将villain的昵称作为标签。

> sh.addShardTag(“shard0000”,“mr.j”)
> sh.addShardTag(“shard0001”,“harv”)
> sh.addShardTag(“shard0002”,“ivy”)

这就是说,“把任何标记为 ‘mr. j’的数据块放在shard0000分片上。“

我们要做的第二件事就是制定一个规则:“对于在villains.joker系列中创建的所有数据块,给他们标记‘mr. j’。“要做到这一点,我们可以使用addTagRange

> sh.addTagRange("villains.joker", {jokes:MinKey}, {jokes:MaxKey}, "mr. j")
> sh.addTagRange("villains.two-face", {luck:MinKey}, {luck:MaxKey}, "harv")
> sh.addTagRange("villains.poison ivy", {flora:MinKey}, {flora:MaxKey}, "ivy")
 

这条命令的作用是用 ‘mr. j’来标记villains.joker中的每一个数据块。(MinKey是负无穷大,MaxKey是正无穷大,因此所有的块落在这个范围内)。

现在让我们为其他两个集合做同样的事情:

> sh.addTagRange("villains.two-face", {luck:MinKey}, {luck:MaxKey}, "harv")
> sh.addTagRange("villains.poison ivy", {flora:MinKey}, {flora:MaxKey}, "ivy")

操作之后需要等几分钟(数据块的平衡需要一点时间),然后再来看这些集合当中的数据块。

> use config
> db.chunks.find({ns: "villains.joker"}, {shard:1, _id:0}).sort({shard:1})
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
> db.chunks.find({ns: "villains.two-face"}, {shard:1, _id:0}).sort({shard:1})
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
> db.chunks.find({ns: "villains.poison ivy"}, {shard:1, _id:0}).sort({shard:1})
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }

使用标记进行伸缩

假设Two-Face对这种安排并不满意,并立即要求两台服务器提供数据(即要求拥有两个分片)。我们可以通过操纵标签将Joker 和Poison Ivy的集合移动到同一个分片,并将Harvey的集合扩展到两个分片:

> // move Poison Ivy to shard0000
> sh.addShardTag("shard0000", "ivy")
> sh.removeShardTag("shard0002", "ivy")
>
> // expand Two-Face to shard0002
> sh.addShardTag("shard0002", "harv")

现在,如果您等待几分钟并查看数据块,将看到Two-Face的集合分布在2个分片上,另外两个集合分布在shard0000分片上。

> db.chunks.find({ns: "villains.poison ivy"}, {shard:1, _id:0}).sort({shard:1})
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
{ "shard" : "shard0000" }
> db.chunks.find({ns: "villains.two-face"}, {shard:1, _id:0}).sort({shard:1})
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0001" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }
{ "shard" : "shard0002" }

“Bad heads, you get EBS.”

然而,对于 Harvey来说,这仍然不太合适,他希望一块分片性能好,另一块分片性能差些。比方说,我们利用亚马逊的新服务,用SSD代替shard0002分片。然后我们划分流量:将 Harvey的50%的写入发送到SSD分片,50%发送到HDD分片。首先,我们将标签添加到分片,并为它们添加描述:

> sh.addShardTag("shard0001", "spinning")
> sh.addShardTag("shard0002", "ssd")

设定一个“运气”字段,运气值在0和1之间,我们设定如果运气<0.5,发送到HDD。如果运气> = 0.5,发送到SSD。

> sh.addTagRange("villains.two-face", {luck:MinKey}, {luck:.5}, "spinning")
> sh.addTagRange("villains.two-face", {luck:.5}, {luck:MaxKey}, "ssd")
 

现在,“倒霉”文档将被写入慢速磁盘,“好运”文档将写入SSD。

通过这种方式添加新的服务器,我们可以控制他们的负载情况。标记为DBA提供了对集合存放位置的控制权。

最后,我写了一个小脚本,为集合添加一个“home”方法,将它们固定在一个标签上。用法示例:

> // load the script
> load("batman.js")
> // put foo on bar
> db.foo.home("bar")
> // put baz on bar
> db.baz.home("bar")
> // move foo to bat
> db.foo.home("bat")

本文的版权归 Sepmer Fi 所有,如需转载请联系作者。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏开发 & 算法杂谈

并行化的动态数据竞争验证和检测方法

之前系列提到的动态数据竞争验证和检测方法是结合了验证和检测两部分。这篇文章主要介绍一下并行化的动态数据竞争验证和检测方法。

2264
来自专栏公有云大数据平台弹性 MapReduce

EMR上Zeppelin入门

简而言之,就是一个大数据分析平台。用户可以利用提供好的WEB UI,在线编写分析逻辑代码,输出结果,并且能够利用可视化工具,形象生动的在线展示结果。

1421
来自专栏精讲JAVA

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解

这些问题在日常开发中可能被很多人忽视(比如有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但能够理解并解决这些问题是Java程序员...

1363
来自专栏数据和云

如何提高Linux下块设备IO的整体性能?

编辑手记:本文主要讲解Linux IO调度层的三种模式:cfp、deadline和noop,并给出各自的优化和适用场景建议。 作者简介: ? 邹立巍 Linux...

6244
来自专栏用户画像

4.2.4 文件系统实现

线性列表就是把文件名组织成一个线性表,查找的时候依次与线性表中每个表项进行比较。若把文件名按序排列使用折半查找法 可以降低平均的查找时间,但是建立新文件时会增加...

802
来自专栏漫漫前端路

写个 vue-loading-template 组件

源码(star ? start : start):github.com/jkchao/vue-…

3482
来自专栏Java架构沉思录

JVM性能调优监控工具使用详解

这些问题在日常开发中可能被很多人忽视(比如有的人遇到上面的问题只是重启服务器或者调大内存,而不会深究问题根源),但能够理解并解决这些问题是Java程序员...

953
来自专栏Jack-Cui

Jetson TX1开发笔记(三):开发利器-Nsight Eclipse Edition

PC平台(Host): 虚拟机Ubuntu14.04 嵌入式平台(Target): Jeston TX1 一、NSight简介     Jetpack开...

2765
来自专栏云计算教程系列

如何在Ubuntu 14.04上使用wrk对HTTP延迟进行基准测试

本文重点介绍称为开源HTTP基准测试工具WRK,它可以在高负荷下测量HTTP服务的延迟。

3780
来自专栏Hadoop数据仓库

将MySQL去重操作优化到极致之三弹连发(二):多线程并行执行

        上一篇已经将单条查重语句调整到最优,但该语句是以单线程方式执行。能否利用多处理器,让去重操作多线程并行执行,从而进一步提高速度呢?比如我的实验环...

1897

扫码关注云+社区

领取腾讯云代金券