MongoDB
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源非关系数据库系统(NoSQL)。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
什么是NoSQL
NoSQL一词最早出现于1998年,是Carlo Strozzi开发的一个轻量、开源、不提供SQL功能的关系数据库。
2009年,Last.fm的Johan Oskarsson发起了一次关于分布式开源数据库的讨论[2],来自Rackspace的Eric Evans再次提出了NoSQL的概念,这时的NoSQL主要指非关系型、分布式、不提供ACID的数据库设计模式。
2009年在亚特兰大举行的"no:sql(east)"讨论会是一个里程碑,其口号是"select fun, profit from real_world where relational=false;"。因此,对NoSQL最普遍的解释是"非关联型的",强调Key-Value Stores和文档数据库的优点,而不是单纯的反对RDBMS。
NoSQL的优点/缺点
优点:
- - 高可扩展性
- - 分布式计算
- - 低成本
- - 架构的灵活性,半结构化数据
- - 没有复杂的关系
缺点:
- - 没有标准化
- - 有限的查询功能(到目前为止)
- - 最终一致是不直观的程序
MongoDB的特点
- MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。
- 基于二进制JSON存储文档
- 高性能、高可用、直接加机器就可以解决扩展性问题
- 支持丰富的CRUD操作,包括聚合统计,全文检索,地理坐标检索
- 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。
- 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。
- 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。
- Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
- MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
- Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
- Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
- Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
- GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
- MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
- MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
- MongoDB安装简单。
与mysql的类比
安装mongoDB
windows版本的安装和配置
https://www.mongodb.com/download-center/community
下载windows版本的msi安装包
[图片上传失败...(image-889d35-1590748791742)]
选择以下选项设置安装目录,然后一路下一步即可:
安装完需要创建一个数据和日志目录,数据目录应该放在根目录下
创建完成后通过命令行运行mongoDB服务器
D:\tools\mongodb\bin>mongod --dbpath D:\data\db
如果执行成功,会输出如下信息:
接下来就可以在bin目录下运行mongo.exe连接上mongoDB了。
D:\tools\mongodb\bin>mongo.exe
配置mongoDB服务
在mongodb文件夹下创建mongod.cfg配置文件,需要指明systemLog.path 和 storage.dbPath
systemLog:
destination: file
path: d:\data\log\mongod.log
storage:
dbPath: d:\data\db
在bin目录下执行通过执行mongod.exe,使用--install选项来安装服务,使用--config选项来指定配置文件
D:\tools\mongodb\bin>mongod.exe --config "D:\tools\mongodb\mongod.cfg" --install
接下来就可以启动MongoDB服务了
#启动
net start MongoDB
#关闭
net stop MongoDB
#移除
D:\tools\mongodb\bin>mongod.exe --remove
使用shell来进行mongoDB的管理:
D:\tools\mongodb\bin>mongo.exe> mongo
使用docker在linux上启动mongoDB
安装docker可以参考:https://zhuanlan.zhihu.com/p/135245499 docker安装
#拉取镜像
$ docker pull mongo:4
#查看拉下来的镜像
$ docker images
#启动一个mongodb服务器容器,命名为mymongo,挂载容器内的/data/db到物理机的/mymongo/data目录中,并对外开放容器内部的27017端口为27017。
$ docker run --name mymongo -p 27017:27017 -v /mymongo/data:/data/db -d mongo:4
#查看容器状态
$ docker ps
#默认情况下mongo使用27017这个端口号
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
48357f0c6d5f mongo:4 "docker-entrypoint.s…" 14 hours ago Up 14 hours 27017/tcp mymongo
#查看数据库服务器日志
$ docker logs mymongo
到这里Mongo就已经启动起来了,可以使用navicat等工具去连接一下,mongo默认是没有密码的,下面的navicat所连接的是windows本机中的mongo,linux中的mongo更换主机名即可。
使用Mongo Express来管理mongoDB数据库
Mongo Express是一个基于网络的MongoDB数据库管理界面
#下载mongo-express镜像
$ docker pull mongo-express
#运行mongo-express
$ docker run --link mymongo:mongo -p 8081:8081 -d mongo-express
Mongo Express界面
使用MongoShell来操作MongDB
MongoShell是mongoDB自带的JavaScript shell,可在shell中使用命令行与MongoDB实例交互。shell可以执行管理操作,检查运行实列等等操作
# 运行mongoshell
$ docker exec -it mymongo mongo
MongoDB shell version v4.2.6
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("48ff10a8-e728-41c9-8320-eeea07116d80") }
MongoDB server version: 4.2.6
Server has startup warnings:
2020-05-27T03:48:29.205+0000 I CONTROL [initandlisten]
2020-05-27T03:48:29.205+0000 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database.
2020-05-27T03:48:29.205+0000 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted.
2020-05-27T03:48:29.205+0000 I CONTROL [initandlisten]
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten]
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** WARNING: You are running on a NUMA machine.
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** We suggest launching mongod like this to avoid performance problems:
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** numactl --interleave=all mongod [other options]
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten]
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten]
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten] ** We suggest setting it to 'never'
2020-05-27T03:48:29.206+0000 I CONTROL [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).
The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.
To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
MongoDB的基本概念
在mongodb中基本的概念是文档、集合、数据库。
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
数据库
一个mongodb中可以建立多个数据库。
MongoDB的默认数据库为"db",该数据库存储在data目录中。
MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
执行"show dbs" 命令可以显示所有数据的列表。
执行 "db" 命令可以显示当前数据库对象或集合。
运行"use"命令,可以连接到一个指定的数据库。
数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串。
- 不能是空字符串("")。
- 不得含有' '(空格)、.、$、/、\和\0 (空字符)。
- 应全部小写。
- 最多64字节。
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
- admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
- local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
- config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
文档
文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
文档主键 _id
- 每个存储在Mongo中的文档都存在一个主键,该主键存储于 _id这个字段中
- 每个文档的_id都具有唯一性
- 所有在Mongo中的数据类型都可以存储为 _id(不支持数组)
- 用户创建文档时不提供主键,则系统自动生成该主键
文档示例:
{"site":"www.google.com","name":"Google"}
下表列出了 RDBMS 与 MongoDB 对应的术语:
RDBMS | MongoDB |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | 主键 (MongoDB 提供了 key 为 _id ) |
需要注意的是:
- 文档中的键/值对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
- MongoDB区分类型和大小写。
- MongoDB的文档不能有重复的键。
- 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
文档键命名规范:
- 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
- .和$有特别的意义,只有在特定环境下才能使用。
- 以下划线"_"开头的键是保留的(不是严格要求的)。
集合
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
比如,我们可以将以下不同数据结构的文档插入到集合中:
{"site":"www.baidu.com"}
{"site":"www.google.com","name":"Google"}
{"site":"www.sina.com.cn","name":"新浪","num":5}
当第一个文档插入时,集合就会被创建
合法的集合名
- 集合名不能是空字符串""。
- 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
- 集合名不能以"system."开头,这是为系统集合保留的前缀。
- 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
如下实例:
db.col.findOne()
capped collections
Capped collections 就是固定大小的collection。
它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 "RRD" 概念类似。
Capped collections 是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能和标准的 collection 不同,你必须要显式的创建一个capped collection,指定一个 collection 的大小,单位是字节。collection 的数据存储空间值提前分配的。
Capped collections 可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放位置也是按照插入顺序来保存的,所以当我们更新Capped collections 中文档的时候,更新后的文档不可以超过之前文档的大小,这样话就可以确保所有文档在磁盘上的位置一直保持不变。
由于 Capped collection 是按照文档的插入顺序而不是使用索引确定插入位置,这样的话可以提高增添数据的效率。MongoDB 的操作日志文件 oplog.rs 就是利用 Capped Collection 来实现的。
要注意的是指定的存储大小包含了数据库的头信息。
db.createCollection("mycoll", {capped:true, size:100000})
- 在 capped collection 中,你能添加新的对象。
- 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
- 使用 Capped Collection 不能删除一个文档,可以使用 drop() 方法删除 collection 所有的行。
- 删除之后,你必须显式的重新创建这个 collection。
- 在32bit机器中,capped collection 最大存储为 1e9( 1X109)个字节。
元数据
数据库的信息是存储在集合中。它们使用了系统的命名空间:
dbname.system.*
在MongoDB数据库中名字空间
集合命名空间 | 描述 |
---|---|
dbname.system.namespaces | 列出所有名字空间。 |
dbname.system.indexes | 列出所有索引。 |
dbname.system.profile | 包含数据库概要(profile)信息。 |
dbname.system.users | 列出所有可访问数据库的用户。 |
dbname.local.sources | 包含复制对端(slave)的服务器信息和状态。 |
对于修改系统集合中的对象有如下限制。
在{{system.indexes}}插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。
{{system.users}}是可修改的。 {{system.profile}}是可删除的。
MongoDB 数据类型
下表为MongoDB中常用的几种数据类型。
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
对象主键 ObjectId
objectId是默认的文档主键。可以可以很快的去生成和排序,有12 bytes,且包含创建时间,可以认为objectId的顺序代表了文档创建的顺序,但是如果有多个文档同一秒被创建,则无法用它区分,由于该主键是在客户端生成,如果各个客户端的系统时间不一致,也可能会出现顺序有误。
ObjectId 的含义包括:
- 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
- 接下来的 3 个字节是机器标识码
- 紧接的两个字节由进程 id 组成 PID
- 最后三个字节是随机数
MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的,默认是个 ObjectId 对象
由于 ObjectId 中保存了创建的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:
ObjectId 转为字符串
字符串
BSON 字符串都是 UTF-8 编码。
时间戳
BSON 有一个特殊的时间戳类型用于 MongoDB 内部使用,与普通的 日期 类型不相关。 时间戳值是一个 64 位的值。其中:
- 前32位是一个 time_t 值(与Unix新纪元相差的秒数)
- 后32位是在某秒中操作的一个递增的
序数
在单个 mongod 实例中,时间戳值通常是唯一的。
在复制集中, oplog 有一个 ts 字段。这个字段中的值使用BSON时间戳表示了操作时间。
BSON 时间戳类型主要用于 MongoDB 内部使用。在大多数情况下的应用开发中,你可以使用 BSON 日期类型。
日期
表示当前距离 Unix新纪元(1970年1月1日)的毫秒数。日期类型是有符号的, 负数表示 1970 年之前的日期。
这样创建的时间是日期类型,可以使用 JS 中的 Date 类型的方法。
返回一个时间类型的字符串:
或者
mongoDB操作示例
可以在shell中对mongoDB进行操作
基本的增删改查
选择数据库:
列举所有的数据库: show databases
选择某个数据库: use my_db
数据库不需要创建,可以直接选择
创建collection
列举所有的数据表:show collections
建立数据表:db.createCollection("my_collection")
数据表是模式自由的,不需要定义字段
插入document
插入的文档结构
{
uid:10000,
name:"xiaoming",
likes:[
"football",
"game"
]
}
db.my_collection.insertOne({uid:10000,name:"xiaoming",likes:["football","game"]})
可以嵌套任意层级的BSON(二进制的JSON)
文档ID是自动生成的,不需要自己制定
查询document
查询符合likes:'football'且name在[‘’xiaoming,‘libai’]范围内的结果并用uid升序排列
db.my_collection.find({likes:'football',name:{$in:['xiaoming','libai']}}).sort({uid:1})
mongo支持基于任意BSON层级的过滤
支持的功能与mysql基本相当
更新document
更新符合likes:'football'的数据,将其name修改为'libai'
db.my_collection.updateMany({likes:'football'},{$set:{name:'libai'}})
updateMany({},{})
第一个参数是过滤条件,第二个参数是更新参数
删除document
db.my_collection.deleteMany({name:'libai'})
deleteMany()
参数是过滤条件
创建index
使用uid和name两个字段做联合索引,uid是正序,name是反序
db.my_collection.createIndex({uid:1,name:-1})
索引的顺序会影响到排序效率
聚合类比
mysql和mongo的对比
聚合统计的示例
db.my_collection.aggregate([{$unwind:'$likes'},{$group:{_id:{likes:'$likes'}}},{$project:{_id:0,like:"$_id.likes",total:{$sum:1}}}])
{$unwind:'$likes'}
将数据按照likes进行拆解,之前的数据{uid:10000,name:"xiaoming",likes:[ "football","game" ]}
中likes有两个值,拆解后变成两行分别为小明喜欢足球和小明喜欢游戏。
{$group:{_id:{likes:'$likes'}}}
对拆解完成的两行数据进行聚合处理,即如果有多条数据会将喜欢游戏的人聚合到一起,喜欢足球的聚合到一起。
完成聚合后{$project:{_id:0,like:"$_id.likes",total:{$sum:1}}}
会对同类进行查询,likes会对likes的分类进行查询,total会统计每一类的数目。
pipeline使用流式计算,功能比较复杂,使用时可以多查手册,下面列举一些聚合的表达式:
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{by_user", num_tutorial : {likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{by_user", num_tutorial : {likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{by_user", num_tutorial : {likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{by_user", num_tutorial : {likes"}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{by_user", url : {url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{by_user", url : {url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{by_user", first_url : {url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{by_user", last_url : {url"}}}]) |
mongo的整体存储架构
mongod:单机版数据库
RepliceSet:复制集,由多个Mongod组成的高可用存储单元
Sharding:分布式集群,由多个RepliceSet组成的可扩展集群
Mongod的架构
最外层是Client客户端,客户端发来请求后走到MongoDB Query Language(查询解释层),MongoDB Query Language会对查询内容进行解析,然后进入MongoDB Data Model(存储层)进行存储,MongoDB Data Model进行了一个抽象,支持底层多种主流的存储引擎。
Mongod默认是采用了WiredTiger引擎
-
基于journaling log宕机恢复(类比mydql的redo log)
它可以在即使服务器意外宕机的情况下,将数据库操作进行重演。mongo会在你写入数据时先将你的操作先顺序追加到log文件,数据会暂时修改在内存中,定时将内存的修改写入到磁盘,如果发生宕机会通过log恢复,实现高吞吐写入。
Replica Set架构
客户端发起的请求会到达Replica Set,Replica Set中存在一主多从,即数据写入到主节点同步到从节点。主宕机之后Replica Set会重新进行选主,客户端就可以写到新的节点上,保证了高可用的特性。客户端默认读请求是读主节点,也可以要求客户端读从节点。但是因为复制是异步的,读从节点可能会读到不正确的数据。
- Replica Set至少有三个节点组成,其中1个可以只充当arbiter(有个节点只参与投票选举,不存储数据)
- 主从基于oplog复制同步(类比mysql binlog)
- 客户端默认读写主节点
Sharding架构
在这里部署两个Replica Set,每个都是高可用的,这两个Replica Set组成一个分布式集群,每个Replica Set都成为shards分片,他们的对外服务会通过Router节点进行路由,客户端的请求会打到Router节点,通过路由层将请求打到对应的分片上。ConfigServers作为配置服务器,存储元信息,即某个KEY在那个shard中,因为mongo集群中存在很多的文档,而这里则存储了这些文档都在哪个shard中,ConfigServers也是基于Replica Set的,已达成高可用的目标。
- Mongos作为代理,路由请求到特定的shard
- 3个mongd节点组成ConfigServers,保存数据元信息
- 每一个shard都是一个Replica Set,可以无限扩容
Collection分片
当客户端读写mongos路由节点之后,路由节点会把请求路由到索所要查询的collection所在的shard上,collection的数据有可能会被分摊到不同的Replica Set上。collection会自动分裂成多个chunk,每个chunk会被自动的负载均衡到不通的shard中,每个shard都可以保证其上的chunk的高可用
按照range给Collection分片
选择文档中的某X字段,可以根据X字段进行分片,按照顺序进行划分。假设X字段是时间的情况下,因为时间都是当前时间,那就可能存在着写入热点问题,数据会集中在某一段时间,会导致某个chunk非常的忙。
- shard key可以是但索引字段或者联合索引字段
- 超过16M的chunk会被一分为二
- 一个collection的所有chunk首尾相连,会构成整个表。
按照hash算法给Collection分片
使用hash算法给Collection分片可以避免写入热点问题,文档中有某个X字段,通过hash算法得到某个hash值(64位整形),通过hash值与哈希数量(预分配)进行取模运算,这样就可以模到某个chunk上,这样即便X是递增的,也不一直存取某个chunk,这样就可以打散了。
-
shardkey(X)必须是哈希索引字段
但是hash是存在冲突率的,即多个shardkey可能经过hash运算后得到同一个hash值,MongoDB无法保证哈希索引的唯一性,因为不同的值可能存在相同索引,所以无法对哈希索引建立唯一键。
shardKey经过hash函数打散可以避免写入热点问题。
支持预分配chunk,避免运行时分裂影响写入
shard用法示例
为db激活特性sh.enableSharding('my_db')
配置hash分片:基于_id设置哈希索引,并进行分片
sh.shardCollection("my_db.my_collection",{_id:"hashed"},false,{numInitialChunks:10240})
如果按非shard key查询,那么需要广播,请求相当于被扇出给所有shard,会导致性能差很多。