MongoDB分片(sharding)/分区(partitioning)介绍

2024-03-13 07:32

本文主要是介绍MongoDB分片(sharding)/分区(partitioning)介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分片简介

  分片是指将数据拆分,将其分散存放在不同的机器上的过程。有时也用分区(partitioning)来表示这个概念。

  几乎所有数据库软件都能进行手动分片(manual sharding)。应用需要维护与若干不同数据库服务器的连接,每个连接还是完全独立的。应用程序管理不同服务器上不同数据的存储,还管理在合适的数据库上查询数据的工作。

  Mongodb支持自动分片(autosharding),可以使数据库架构对应用程序不可见,也可以简化系统管理。Mongodb自动处理数据在分片上的分布,也更容易添加和删除分片。

理解集群的组件

  Mongodb的分片机制允许你创建一个包含许多台机器(分片)的集群。将数据子集分散在集群中,每个分片维护着一个数据集合的子集。与单个服务器和副本集相比,使用集群架构可以使应用程序具有更大的数据处理能力。

  复制是让多台服务器都拥有同样的数据副本,每一台服务器都是其它服务器的镜像,而每一个分片和其它分片拥有不同的数据子集。

  为了对应用程序隐藏数据库架构的细节,在分片之前要先执行mongos进行一次路由过程。这个路由服务器维护着一个“内容列表”,指明了每个分片包含什么数据内容。应用程序只需要连接到路由服务器,就可以像使用单机服务器一样进行正常的请求了。路由服务器知道哪些数据位于哪个分片,可以将请求转发给相应的分片。每个分片对请求的响应都会发送给路由服务器,路由服务器将所有响应合并在一起,返回给应用程序。对应用程序来说,它只知道自己是连接到了一台单机mongod服务器。

使用分片的连接


不使用分片连接



快速建立一个简单的集群

  在单台服务器上快速建立一个集群。首先,使用--nodb选项启动mongo shell:

$mongo --nodb

使用ShardingTest类创建集群:

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

运行这个命令会创建一个包含3个分片(mongod进程)的集群。分别运行在30000,30001,30002端口。默认情况下,ShardingTest会在30999端口启动mongos。接下来就连接到这个mongos开始使用集群。

集群会将日志输出到当前shell中,所以再打开一个shell用来连接到集群的mongos:

>db = (new Mongo("localhost:30999")).getDB("test")

现在的情况如“使用分片的连接”所示,客户端(shell)连接到了一个mongos。现在就可以将请求发送给mongos了,它会自动将请求路由到合适的分片。客户端不需要知道分片的任何信息,比如分片数量和分片地址。只要有分片存在,就可以向mongos发送请求,它会自动将请求转发到合适的分片上。

首先插入一些数据:

>for(var i=0;i<100000;i++){db.users.insert({"username" : "user"+i , "created_at" : new Date()});}
>db.users.count()
100000

可以看到,与mongos进行交互与使用单机服务器完全一样,如上图“不使用分片的连接”。

运行sh.status()可以看到集群的状态:分片摘要信息、数据库摘要信息、集合摘要信息:

>sh.status()
...Sharding Status...
sharding version : {"_id" : 1 , "version" : 3}
shards :{"_id" : "shard0000" , "host" : "localhost : 30000"}{"_id" : "shard0001" , "host" : "localhost : 30001"}{"_id" : "shard0002" , "host" : "localhost : 30002"}
databases:{"_id" : "admin" , "partitioned" : false , "primary" : "config" }{"_id" : "test" , "partitioned" : false , "primary" : "shard0001" }

sh命令与rs命令很像,除了它是用于分片的:rs是一个全局变量,其中定义了许多分片操作的辅助函数。可以运行sh.help()查看可以使用的辅助函数。如sh.status()的输出所示,当前拥有3个分片,2个数据库(其中admin数据库是自动创建的)。

  与上面sh.status()的输出信息不同,test数据库可能有一个不同的主分片(primary shard)。主分片是为每个数据库随机选择的,所有数据都会位于主分片上。MongoDB现在还不能自动将数据分发到不同的分片上,因为它不知道你希望如何分发数据。必须要明确指定,对于每一个集合,应该如何分发数据。

  主分片与副本集中的主节点不同。主分片指的是组成分片的整个副本集。而副本集中的主节点是指副本集中能够处理写请求的单台服务器。


要对一个集合分片,首先要对这个集合的数据库启用分片,执行如下命令:

>sh.enableSharding("test")

现在就可以对test数据库内的集合进行分片了。

对集合分片时,要选择一个片键(shard key)。片键是集合的一个键,MongoDB根据这个键拆分数据。例如,如果选择基于“username”进行分片,MongoDB会根据不同的用户名进行分片。选择片键可以认为是选择集合中数据的顺序。它与索引是个相似的概念:随着集合的不断增长,片键就会成为集合上最重要的索引。只有被索引过的键才能够作为片键。


在启用分片之前,先在希望作为片键的键上创建索引:

>db.users.ensureIndex({"username" : 1})

现在就可以依据“username”对集合分片了:

>sh.shardCollection(“test.users” , "username" : 1)

几分钟之后,再次运行sh.status(),可以看到,这次的输出信息比较多:

...Sharding Status...
sharding version : {"_id" : 1 , "version" : 3}
shards :
{“_id” : "shard0000" , "host" : "localhost : 30000"}
{“_id” : "shard0001" , "host" : "localhost : 30001"}
{“_id” : "shard0002" , "host" : "localhost : 30002"}
databases:
{"_id" : "admin" , "partitioned" : false , "primary" : "cofig"}
{"_id" : "test" , "partitioned" : true , "primary" : "shard0000"}test.users chunks:shard0001 4shard0002 4shard0000 5
{"username" : {$minkey : 1}} -->> {"username" : "user1704"}on : shard0001
{"username" : "user1704"} -->> {"username" : "user24083"}on : shard0002
{"username" : "user24083"} -->> {"username" : "user31126"}on : shard0001
{"username" : "user31126"} -->> {"username" : "user38170"}on : shard0002
{"username" : "user38170"} -->> {"username" : "user45213"}on : shard0001
{"username" : "user45213"} -->> {"username" : "user52257"}on : shard0002
{"username" : "user52257"} -->> {"username" : "user59300"}on : shard0001
{"username" : "user59300"} -->> {"username" : "user66344"}on : shard0002
{"username" : "user66344"} -->> {"username" : "user73388"}on : shard0000
{"username" : "user73388"} -->> {"username" : "user80430"}on : shard0000
{"username" : "user80430"} -->> {"username" : "user87475"}on : shard0000
{"username" : ”user87475“} -->> {"username" : "user94518"}on : shard0000
{"username" : "user94518"} -->> {"username" : {$maxkey : 1}}

集合被分成了多个数据块,每一个数据块都是集合的一个数据子集。这些是按照片键的范围排列的({”username“ :minvalue} -->>{"username" : maxvalue}指出了每个数据块的数据范围)。通过查看输出信息中的"on" : shard部分,可以发现集合数据比较均匀地分布在不同分片上。

  在分片之前,集合实际上是一个单一的数据块。分片依据片键将集合拆分为多个数据块,这块数据块被分布在集群中的每个分片上:


注意,数据块列表开始的键值和结束的键值:$minkey和$maxkey。可以将$minkey认为是”负无穷“,它比MongoDB中的任何值都要小。类似地,可以将$maxkey认为是”正无穷“,它比MongoDB中的任何值都要大。片键值的范围始终位于$minkey和$maxkey之间。这些值实际上是BSON类型。只是用于内部使用,不应该被用在应用程序中。如果希望在shell中使用的话,可以用Minkey和Maxkey常量代替。

现在数据已经分布在多个分片上了,接下来做一个查询操作。首先,做一个基于指定的用户名的查询:

>db.users.find({username : "user12345"})
{"_id" : ObjectId("50b0451951d30ac5782499e6"),"username" : "user12345","created_at" : ISODate("2012-11-24T03:55:05.636Z")
}

可以看到查询可以正常工作,现在运行explain()来看看MongoDB到底是如何处理这次查询的:

>db.users.find(username : "user12345").explain(){"clusteredType" : "ParallelSort","shards" : {"localhost : 30001" : [{"cursor" : "BtreeCursor username_1","nscanned" : 1,"nscannedObjects" : 1,"n" : 1,"millis" : 0,"nYields" : 0,"nChunkSkips" : 0,"isMultiKey" : false,"indexOnly" : false,"indexBounds" : {"username" : [["user12345","user12345"]]}}]},"n" : 1,"nChunkSkips" : 0,"nYields" : 0,"nscanned" : 1,"nscannedObjects" : 1,"millisTotal" : 0,"millsAvg" : 0,"numQueries" : 1,"numShards" : 1}
输出信息包含两个部分,一个看起来比较普遍的explain()输出嵌套在另一个explain()输出中。外层的explain()输出来自mongos:描述了为了处理这个查询,mongos所做的工作。内层的explain()输出来自查询所使用的分片。在本例中是localhost:30001。

由于”username“是片键,所以mongos能够直接将查询发送到正确的分片上。作为对比,来看一下查询所有数据的过程:

>db.users.find().explain(){"clusteredType" : "ParallelSort","shards" : {"localhost : 30000" : [{"cursor" : "BasicCursor","nscanned" : 37393,"nscannedObjects" : 37393,"n" : 37393,"millis" : 38,"nYields" : 0,"nChunkSkips" : 0,"isMultiKey" : false,"indexOnly" : false,"indexBounds" : {}}],"localhost : 30001" : [{"cursor" : "BasicCursor","nscanned" : 31303,"nscannedObjects" : 31303,"n" : 31303,"millis" : 37,"nYields" : 0,"nChunkSkips" : 0,"isMultiKey" : false,"indexOnly" : false,"indexBounds" : {}}],"localhost : 30002" : [{"cursor" : "BasicCursor","nscanned" : 31304,"nscannedObjects" : 31304,"n" : 31304,"millis" : 36,"nYields" : 0,"nChunkSkips" : 0,"isMultiKey" : false,"indexOnly" : false,"indexBounds" : {}}]},"n" : 100000,"nChunkSkips" : 0,"nYields" : 0,"nscanned" : 100000,"nscannedObjects" : 100000,"millisTotal" : 111,"millsAvg" : 37,"numQueries" : 3,"numShards" : 3}
可以看到,这次查询不得不访问所有3个分片,查询出所有数据。通常来说,如果没有在查询中使用片键,mongos就不得不将查询发送到每个分片。包含片键的查询能够直接被发送到目标分片或者是集群分片的一个子集,这样的查询叫做 定向查询(targeted query)。有些查询必须被发送到所有分片,这样的查询叫做 分散--聚集查询(scatter-gather query):mongos将查询分散到所有分片上,然后将各个分片的查询结果聚集起来。

运行cluster.stop()就可以关闭整个集群了。

>cluster.stop()

这篇关于MongoDB分片(sharding)/分区(partitioning)介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/804080

相关文章

揭秘未来艺术:AI绘画工具全面介绍

📑前言 随着科技的飞速发展,人工智能(AI)已经逐渐渗透到我们生活的方方面面。在艺术创作领域,AI技术同样展现出了其独特的魅力。今天,我们就来一起探索这个神秘而引人入胜的领域,深入了解AI绘画工具的奥秘及其为艺术创作带来的革命性变革。 一、AI绘画工具的崛起 1.1 颠覆传统绘画模式 在过去,绘画是艺术家们通过手中的画笔,蘸取颜料,在画布上自由挥洒的创造性过程。然而,随着AI绘画工

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

20.Spring5注解介绍

1.配置组件 Configure Components 注解名称说明@Configuration把一个类作为一个loC容 器 ,它的某个方法头上如果注册7@Bean , 就会作为这个Spring容器中的Bean@ComponentScan在配置类上添加@ComponentScan注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>@Sc

为什么要做Redis分区和分片

Redis分区(Partitioning)和分片(Sharding)是将数据分布在多个Redis实例或多个节点上的做法。这种技术用于提高性能、可扩展性和可用性。以下是执行Redis分区和分片的主要原因: 1. **提高吞吐量**:    - 通过将数据分散到多个节点,可以并行处理更多的操作,从而提高整体吞吐量。 2. **内存限制**:    - 单个Redis实例的内存是有限的。分区允许数据

C++标准模板库STL介绍

STL的六大组成部分 STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,提供了丰富的通用数据结构和算法,使得 C++ 编程变得更加高效和方便。STL 包括了 6 大类组件,分别是算法(Algorithm)、容器(Container)、空间分配器(Allocator)、迭代器(Iterator)、函数对象(Functor)、适配器(Adapter)

一二三应用开发平台应用开发示例(4)——视图类型介绍以及新增、修改、查看视图配置

调整上级属性类型 前面为了快速展示平台的低代码配置功能,将实体文件夹的数据模型上级属性的数据类型暂时配置为文本类型,现在我们调整下,将其数据类型调整为实体,如下图所示: 数据类型需要选择实体,并在实体选择框中选择自身“文件夹” 这时候,再点击生成代码,平台会报错,提示“实体【文件夹】未设置主参照视图”。这是因为文件夹选择的功能页面,同样是基于配置产生的,因为视图我们还没有配置,所以会报错。

Sharding(切片)技术(解决数据库分库一致性问题)

Sharding(切片) 不是一门新技术,而是一个相对简朴的软件理念,就是当我们的数据库单机无法承受高强度的i/o时,我们就考虑利用 sharding 来把这种读写压力分散到各个主机上去。 所以Sharding 不是一个某个特定数据库软件附属的功能,而是在具体技术细节之上的抽象处理,是Horizontal Partitioning 水平扩展(或横向扩展)的解决方案,其主要目的是为突破单节点数

49-1 内网渗透 - Bypass UAC介绍

一、Bypass UAC         用户账户控制(UAC)是Windows操作系统的一种安全机制,旨在防止未经授权的应用程序自动安装并防止非授权修改系统设置。它确保应用程序和任务通常在非管理员账户的安全上下文中运行,除非明确需要管理员权限,用户才会被提示确认。         对于非RID 500的管理员用户(除了内置的Administrator账户),当他们登录时,系统会为其分配两个访

okhttp3的详细介绍

这篇文章说下OkHttp的基本用法,是最新的3哦,如果你曾经在网上搜索OkHttp怎么使用发现有些类没有了可能是因为人家说的是2。首先说下OkHttp3是Java和Android都能用,Android还有一个著名网络库叫Volley,那个只有Android能用。导入自己到入jar包,别漏了okio:okhttp-3.3.0.jarokio-1.8.0.jarmaven方式:<dependen

Retrofit详细介绍

转载请标明出处:http://blog.csdn.net/xx326664162/article/details/51910837 文章出自:薛瑄的博客 你也可以查看我的其他同类文章,也会让你有一定的收货! 一、Retrofit 是什么? Retrofit is a type-safe HTTP client for Android and java. Retrofit 是与 Web 服务器提