MongoDB 学习

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更换主机名即可。

image.png

使用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" 命令可以显示所有数据的列表。

image.png

执行 "db" 命令可以显示当前数据库对象或集合。

image.png

运行"use"命令,可以连接到一个指定的数据库。

image.png

数据库也通过名字来标识。数据库名可以是满足以下条件的任意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 )

需要注意的是:

  1. 文档中的键/值对是有序的。
  2. 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  3. MongoDB区分类型和大小写。
  4. MongoDB的文档不能有重复的键。
  5. 文档的键是字符串。除了少数例外情况,键可以使用任意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.* 是包含多种系统信息的特殊集合(Collection),如下:

集合命名空间 描述
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 函数来获取文档的创建时间:

image.png

ObjectId 转为字符串

image.png

字符串

BSON 字符串都是 UTF-8 编码。

时间戳

BSON 有一个特殊的时间戳类型用于 MongoDB 内部使用,与普通的 日期 类型不相关。 时间戳值是一个 64 位的值。其中:

  • 前32位是一个 time_t 值(与Unix新纪元相差的秒数)
  • 后32位是在某秒中操作的一个递增的序数

在单个 mongod 实例中,时间戳值通常是唯一的。

在复制集中, oplog 有一个 ts 字段。这个字段中的值使用BSON时间戳表示了操作时间。

BSON 时间戳类型主要用于 MongoDB 内部使用。在大多数情况下的应用开发中,你可以使用 BSON 日期类型。

日期

表示当前距离 Unix新纪元(1970年1月1日)的毫秒数。日期类型是有符号的, 负数表示 1970 年之前的日期。

image.png

这样创建的时间是日期类型,可以使用 JS 中的 Date 类型的方法。

返回一个时间类型的字符串:

image.png

或者

image.png

mongoDB操作示例

可以在shell中对mongoDB进行操作

基本的增删改查

选择数据库:

列举所有的数据库: show databases

选择某个数据库: use my_db

image.png

数据库不需要创建,可以直接选择

创建collection

列举所有的数据表:show collections

建立数据表:db.createCollection("my_collection")

image.png

数据表是模式自由的,不需要定义字段

插入document

插入的文档结构

{    
     uid:10000,
     name:"xiaoming",
     likes:[ 
         "football",
         "game" 
     ]
}

db.my_collection.insertOne({uid:10000,name:"xiaoming",likes:["football","game"]})

image.png

可以嵌套任意层级的BSON(二进制的JSON)

文档ID是自动生成的,不需要自己制定

查询document

查询符合likes:'football'且name在[‘’xiaoming,‘libai’]范围内的结果并用uid升序排列

db.my_collection.find({likes:'football',name:{$in:['xiaoming','libai']}}).sort({uid:1})

image.png

mongo支持基于任意BSON层级的过滤

支持的功能与mysql基本相当

更新document

更新符合likes:'football'的数据,将其name修改为'libai'

db.my_collection.updateMany({likes:'football'},{$set:{name:'libai'}})

image.png

updateMany({},{})第一个参数是过滤条件,第二个参数是更新参数

删除document

db.my_collection.deleteMany({name:'libai'})

deleteMany()参数是过滤条件

创建index

使用uid和name两个字段做联合索引,uid是正序,name是反序

db.my_collection.createIndex({uid:1,name:-1})

image.png

索引的顺序会影响到排序效率

聚合类比

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([{group : {_id : "by_user", num_tutorial : {sum : "likes"}}}])
$avg 计算平均值 db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {avg : "likes"}}}])
$min 获取集合中所有文档对应值得最小值。 db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {min : "likes"}}}])
$max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{group : {_id : "by_user", num_tutorial : {max : "likes"}}}])
$push 在结果文档中插入值到一个数组中。 db.mycol.aggregate([{group : {_id : "by_user", url : {push: "url"}}}])
$addToSet 在结果文档中插入值到一个数组中,但不创建副本。 db.mycol.aggregate([{group : {_id : "by_user", url : {addToSet : "url"}}}])
$first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{group : {_id : "by_user", first_url : {first : "url"}}}])
$last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{group : {_id : "by_user", last_url : {last : "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架构

image.png

客户端发起的请求会到达Replica Set,Replica Set中存在一主多从,即数据写入到主节点同步到从节点。主宕机之后Replica Set会重新进行选主,客户端就可以写到新的节点上,保证了高可用的特性。客户端默认读请求是读主节点,也可以要求客户端读从节点。但是因为复制是异步的,读从节点可能会读到不正确的数据。

  • Replica Set至少有三个节点组成,其中1个可以只充当arbiter(有个节点只参与投票选举,不存储数据)
  • 主从基于oplog复制同步(类比mysql binlog)
  • 客户端默认读写主节点

Sharding架构

image.png

在这里部署两个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分片

image.png

当客户端读写mongos路由节点之后,路由节点会把请求路由到索所要查询的collection所在的shard上,collection的数据有可能会被分摊到不同的Replica Set上。collection会自动分裂成多个chunk,每个chunk会被自动的负载均衡到不通的shard中,每个shard都可以保证其上的chunk的高可用

按照range给Collection分片

image.png

选择文档中的某X字段,可以根据X字段进行分片,按照顺序进行划分。假设X字段是时间的情况下,因为时间都是当前时间,那就可能存在着写入热点问题,数据会集中在某一段时间,会导致某个chunk非常的忙。

  • shard key可以是但索引字段或者联合索引字段
  • 超过16M的chunk会被一分为二
  • 一个collection的所有chunk首尾相连,会构成整个表。

按照hash算法给Collection分片

image.png

使用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,会导致性能差很多。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269