数据库系统之MongoDB Sharding

基础知识

Sharding是将一个大型数据集划分为更小、更易于管理的片段的过程。

Shared nothing架构是一种分布式计算架构,其中每个计算节点不与其他节点共享数据。

在数据库系统中,它被称为sharding(shared nothing)。

在出现以下三种情况时我们要考虑使用Sharding:

  1. 大量的数据和更大的读/写吞吐量需求使得商品数据库服务器不够。

  2. 数据库服务器不能寻址足够的RAM,或者它们可能没有足够的CPU内核来有效地处理工作负载。

  3. 由于数据量大,在一个磁盘或RAID存储(廉价磁盘的冗余阵列)上存储和管理备份是不实际的。

这些问题的解决方案是将数据库和数据库处理分布到多个服务器上。

mongodb中实现这一功能的方法称为sharding。由于管理和性能开销,sharding使数据库系统变得复杂。

为什么要Sharding?

分片有两个主要原因:

  1. 存储分配

  2. 负荷分配

如果对存储容量的监视显示,在某个时刻,数据库应用程序需要的存储量超过了可用的存储量,并且不可能添加更多的存储量,那么sharding是最好的选择。

Mongodb监控意味着运行db.stats()和db.collection.stats()在mongo shell中以获取关于当前数据库的存储使用情况和其中的集合的统计信息,

负载意味着CPU和RAM利用率、I/O带宽、客户端请求使用的网络传输=>响应时间。

如果在某个时刻响应时间不符合客户的期望,那么它会触发一个shard决策。

Shard的决定取决于网络使用情况、磁盘使用情况、CPU使用情况和RAM使用情况。

分配

MongoDB的数据粒度分为四个级别:

  1. Document: MongoDB中最小的数据单位;文档表示系统中的单个对象(如关系数据库中的一行)。
  2. Chunk: 按文件中的值聚集的一组文档;块是一个仅存在于分片设置中的概念;块是根据文档的键或键集的值(称为分片键)通过对文档进行逻辑分组而创建的。
  3. Collection: 数据库中的一组命名的文档;集合允许用户将数据库分离为对应用程序有意义的逻辑分组。
  4. Database:一套文档集合;数据库名称和集合名称的组合在整个系统中是唯一的,通常称为名称空间。

数据在分片集群中的分布方式如下:
5. 在整个数据库的级别上,每个数据库及其所有集合都放在自己的分片上。
6. 在分区或集合块的级别上,集合中的文档本身根据文档中的一个键或一组键(shard key)的值分布在多个分片上。

Sharding模拟

建立分片集群的过程包括三个步骤:

  1. 通过生成组成集群的所有mongod和mongos进程来启动mongod和mongos服务器。

  2. 通过更新配置来配置集群,使得副本集被初始化,碎片被添加到集群中,并且节点能够彼此通信。

  3. sharding collections,以便它可以分布在多个切分上。

启动终端并处理以下shell命令来创建配置服务器(只有一个):

mkdir conf1
mkdir conf2

在一个新的终端窗口中处理以下命令:

mongod --configsvr --replSet conf --dbpath conf1 --port 4001

在另一个新的终端窗口中处理以下命令:

mongod --configsvr --replSet conf --dbpath conf2 --port 4002

接着在一个新的终端窗口中处理以下命令:

mongo -port 4001
rs.initiate()
rs.conf()
rs.add("localhost:4002")
rs.status()
exit
mongo --port 4002
rs.slaveOk()
exit

在新的终端窗口中处理以下命令,以创建数据碎片(两个复制集,每个复制集由两个服务器组成):

mkdir data1-1
mkdir data1-2

在一个新的终端窗口中处理以下命令:

mongod --shardsvr --replSet data1 --dbpath data1-1 --port 4003

在另一个新的终端窗口中处理以下命令:

mongod --shardsvr --replSet data1 --dbpath data1-2 --port 4004

在一个新的终端窗口中处理以下命令:

mongo -port 4003
rs.initiate()
rs.conf()
rs.add("localhost:4004")
rs.status()
exit
mongo --port 4004
rs.slaveOk()
exit

在新的终端窗口中处理以下命令:

mkdir data2-1
mkdir data2-2

在新的终端窗口中处理以下命令:

mongod --shardsvr --replSet data2 --dbpath data2-1 --port 4005

在新的终端窗口中处理以下命令:

mongod --shardsvr --replSet data2 --dbpath data2-2 --port 4006

在新的终端窗口中处理以下命令:

mongo -port 4005
rs.initiate()
rs.conf()
rs.add("localhost:4006")
rs.status()
exit
mongo --port 4006
rs.slaveOk()
exit

在新的终端窗口中处理以下命令以启动mongos:

mongos --configdb conf/localhost:4001,localhost:4002 --port 4000

在新的终端窗口中处理以下命令,在端口4003和4005上的复制集上创建碎片:

mongo --port 4000
sh.addShard("data1/localhost:4003")
sh.addShard("data2/localhost:4005")

列出数据碎片:

db.getSiblingDB("config").shards.find()

启用数据库分片:

sh.enableSharding("test")
db.getSiblingDB("config").databases.find()

将集合插入到shard中:

use test
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"000"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"001"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"002"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"003"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"004"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"005"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"006"})
db.testcol.insert({"fname":"James", "lname":"Bond", "shard-key":"007"})

在“shard-key”上创建索引:

db.testcol.createIndex({"shard-key":1})

Shard a collection:

sh.shardCollection("test.testcol", {"shard-key": 1})

获得统计数据:

db.test_collection.stats()

输出结果如下:

"shards" : {
	"data2" : {
		"ns" : "test.testcol",
		"size" : 592,
		"count" : 8,
		"avgObjSize" : 74,
		"storageSize" : 32768,

创建大型集合“test_collection”:

use test
var bulk = db.test_collection.initializeUnorderedBulkOp();
people = ["Marc", "Bill", "George", "Eliot", "Matt", "Trey", "Tracy",
"Greg", "Steve", "Kristina", "Katie", "Jeff"];
for(var i=0; i<1000000; i++){
	user_id = i;
	name = people[Math.floor(Math.random()*people.length)];
	number = Math.floor(Math.random()*10001);
	bulk.insert( { "user_id":user_id, "name":name, "number":number });
}
bulk.execute();

在“user_id”上创建索引:

db.test_collection.createIndex({user_id:1})

通过“user_id”分片一个集合:

sh.shardCollection("test.test_collection",{"user_id":1}) 

找到分片状态:

sh.status()
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
					config.system.sessions
						shard key: { "_id" : 1 }
						unique: false
						balancing: true
						chunks:
								data1 1
						{ "_id" : { "$minKey" : 1 } } -->>
						{ "_id" : { "$maxKey" : 1 } } on : data1 Timestamp(1, 0)
....

Production

理论上,要启动示例MongoDB shard集群,你必须启动总共9个进程(每个副本集有3个mongod,再加上3个配置服务器。
实际上在实践中不需要这么多过程。

复制的mongod是shard集群中资源最密集的进程,必须给它们自己的机器。

副本集仲裁程序的开销很小,而且它们不需要自己的服务器。

配置服务器存储的数据量相对较小。

这意味着那个配置服务器也不一定需要自己的机器。

References

  1. Banker K., Bakkum P., Verch S., Garret D., Hawkins T., MongoDB in Action, 2nd ed., Manning Publishers, 2016.
  2. MongoDB Manual, Sharding https://docs.mongodb.com/v3.6/sharding/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MongoDB 是一种文档型数据库,它可以通过分片来实现高可用性和扩展性。MongoDB 分片是将一个大的 MongoDB 数据库分成多个部分,每个部分称为一个 Shard。一个 MongoDB 分片集群通常由多个 Shard、多个复制集和多个配置服务器组成。 下面是MongoDB数据库集群的基本架构: 1. 分片(Sharding):将数据划分成多个片段,每个片段称为一个Shard。Shard是MongoDB中存储数据的最小单位,每个Shard可以是单台服务器或是一个复制集。 2. 复制集(Replica Set):MongoDB中的复制集是一组维护相同数据副本的MongoDB服务器。每个复制集包含一个Primary节点和多个Secondary节点,Primary节点负责处理所有的写操作,Secondary节点负责复制Primary节点的数据。 3. 配置服务器(Config Server):配置服务器维护了整个集群的元数据信息,包括分片信息、复制集信息等。每个配置服务器都保存了所有集群的元数据信息的一份拷贝。 4. Mongos路由器(Mongos Router):Mongos路由器是一个轻量级的进程,用于将客户端请求路由到正确的Shard上。 在MongoDB集群中,每个Shard都存储了部分数据,Mongos路由器根据某种规则将请求路由到相应的Shard上,Shard接收到请求后将数据返回给Mongos路由器,最终路由器将结果返回给客户端。配置服务器用于记录集群的元数据信息,包括Shard信息、数据分布信息等等。 通过分片来实现数据的水平扩展,可以将数据存储在多台服务器上,提高数据的可扩展性和可用性。同时,MongoDB还提供了复制集实现数据的高可用性,确保数据不会因为单点故障而丢失。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值